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
@@ -98,7 +98,9 @@ and your whole answer becomes unparseable. This is the single most common way \
|
||||
this task fails.
|
||||
- meta.id is a lowercase slug (letters, digits, - and _). meta.title is the \
|
||||
title a human reads, not a filename.
|
||||
- version is 1. Keep meta at 1080x1920 and audio preset "sonar".
|
||||
- version is 1. Keep meta at 1080x1920.
|
||||
- audio.preset — pick the one whose mood fits the shape you chose:
|
||||
{presets}
|
||||
- The closing shot carries the domain, uppercase, no protocol: {domain}
|
||||
|
||||
# 4. Grounding — this is the part that matters
|
||||
@@ -144,6 +146,14 @@ Return the JSON object now."""
|
||||
|
||||
PALETTE_FALLBACK = "ink, amber, amber_dark, muted, dim, red"
|
||||
|
||||
#: Si el caller no trae la paleta de audio, el prompt solo ofrece lo que
|
||||
#: cualquier shortsmith renderiza.
|
||||
PRESETS_FALLBACK = {"sonar": "low drone and sonar pings", "none": "digital silence"}
|
||||
|
||||
|
||||
def _describe_presets(presets: dict[str, str]) -> str:
|
||||
return "\n".join(f' "{name}" — {note}' for name, note in sorted(presets.items()))
|
||||
|
||||
|
||||
@dataclass
|
||||
class SpecResult:
|
||||
@@ -305,12 +315,14 @@ LLMCall = Callable[[str, str], Awaitable[str]]
|
||||
|
||||
class ShortSpecWriter:
|
||||
def __init__(self, llm_call: LLMCall, templates: dict[str, dict],
|
||||
refresh_templates: Optional[Callable[[], Awaitable[dict]]] = None):
|
||||
refresh_templates: Optional[Callable[[], Awaitable[dict]]] = None,
|
||||
presets: Optional[dict[str, str]] = None):
|
||||
self.llm_call = llm_call
|
||||
self.templates = templates
|
||||
#: Se vuelve a pedir el contrato si una validación falla: el
|
||||
#: renderizador puede haberse actualizado a mitad de la run.
|
||||
self.refresh_templates = refresh_templates
|
||||
self.presets = presets or dict(PRESETS_FALLBACK)
|
||||
|
||||
def build_prompt(self, topic: str, context: str, article_url: Optional[str],
|
||||
domain: str) -> str:
|
||||
@@ -322,6 +334,7 @@ class ShortSpecWriter:
|
||||
shapes=NARRATIVE_SHAPES,
|
||||
templates=describe_templates(self.templates),
|
||||
colors=_palette(self.templates),
|
||||
presets=_describe_presets(self.presets),
|
||||
domain=domain,
|
||||
target_min=TARGET_MIN_DURATION,
|
||||
target_max=TARGET_MAX_DURATION,
|
||||
@@ -359,7 +372,7 @@ class ShortSpecWriter:
|
||||
|
||||
last_spec = spec
|
||||
try:
|
||||
validate_spec(spec, self.templates)
|
||||
validate_spec(spec, self.templates, presets=self.presets)
|
||||
except SpecInvalid as e:
|
||||
history.append(e.errors)
|
||||
feedback = _format_errors(e.errors)
|
||||
|
||||
Reference in New Issue
Block a user