feat(short): la paleta de audio viva — GET /audio en el contrato, el prompt y el bucle de edición
Build & Deploy ResearchOwl / build-and-push (push) Successful in 9s
Build & Deploy ResearchOwl / build-and-push (push) Successful in 9s
shortsmith ya compone la banda sonora (sonar); ahora publica una paleta (pulse, static) y este repo la consume en vivo: el prompt la ofrece con sus notas de mood, validate_spec la usa como fuente de verdad para audio.preset, y editar el preset en /short_spec es la manera gratis de escucharlas. Sin /audio (404 o caída) todo cae a la paleta base y nada deja de renderizar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1fd0c1b3d6
commit
93a506b636
@@ -42,10 +42,20 @@ __all__ = [
|
||||
"ShortsmithUnavailable",
|
||||
"ShortsmithRejected",
|
||||
"JobResult",
|
||||
"BASELINE_PRESETS",
|
||||
"POLL_INTERVAL",
|
||||
"POLL_CEILING",
|
||||
]
|
||||
|
||||
#: La paleta que existía antes de que shortsmith publicara `GET /audio`. Es el
|
||||
#: fallback cuando el endpoint no está (404 = shortsmith anterior) o no se pudo
|
||||
#: consultar: la paleta mejora el spec, no lo define, y quedarse en sonar nunca
|
||||
#: rompe un render.
|
||||
BASELINE_PRESETS = {
|
||||
"sonar": "low drone and sonar pings tightening toward the close",
|
||||
"none": "digital silence",
|
||||
}
|
||||
|
||||
|
||||
class ShortsmithError(Exception):
|
||||
"""Cualquier fallo hablando con shortsmith."""
|
||||
@@ -86,6 +96,7 @@ class JobResult:
|
||||
#: petición cuando una validación falla, por si el renderizador se actualizó a
|
||||
#: mitad de una run.
|
||||
_templates_cache: dict[str, dict[str, Any]] = {}
|
||||
_presets_cache: dict[str, dict[str, str]] = {}
|
||||
|
||||
|
||||
class ShortsmithClient:
|
||||
@@ -136,6 +147,37 @@ class ShortsmithClient:
|
||||
logger.info("shortsmith templates fetched", n=len(data))
|
||||
return data
|
||||
|
||||
async def audio_presets(self, refresh: bool = False) -> dict[str, str]:
|
||||
"""La paleta de audio: nombre de preset -> nota de una línea (`GET /audio`).
|
||||
|
||||
La mitad de audio del contrato vivo: shortsmith añade un preset y el
|
||||
prompt lo ofrece sin tocar este repo. Un 404 es un shortsmith anterior
|
||||
al endpoint y devuelve la paleta base, sin error — fallbacks siempre.
|
||||
"""
|
||||
if not refresh and self.base_url in _presets_cache:
|
||||
return _presets_cache[self.base_url]
|
||||
try:
|
||||
async with self._session(30) as sess:
|
||||
async with sess.get(f"{self.base_url}/audio") as resp:
|
||||
if resp.status == 404:
|
||||
data = dict(BASELINE_PRESETS)
|
||||
elif resp.status != 200:
|
||||
body = await resp.text()
|
||||
raise ShortsmithError(
|
||||
f"GET /audio devolvió {resp.status}: {body[:200]}")
|
||||
else:
|
||||
payload = await resp.json()
|
||||
presets = payload.get("presets")
|
||||
data = (presets if isinstance(presets, dict) and presets
|
||||
else dict(BASELINE_PRESETS))
|
||||
except aiohttp.ClientError as e:
|
||||
raise ShortsmithUnavailable(f"shortsmith inalcanzable: {e}") from e
|
||||
except asyncio.TimeoutError as e:
|
||||
raise ShortsmithUnavailable("shortsmith no respondió a /audio") from e
|
||||
_presets_cache[self.base_url] = data
|
||||
logger.info("shortsmith audio presets fetched", presets=sorted(data))
|
||||
return data
|
||||
|
||||
async def render(self, spec: dict[str, Any]) -> str:
|
||||
"""`POST /render`. Devuelve el job_id. 422 -> ShortsmithRejected."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user