Fix render

This commit is contained in:
Andras Schmelczer 2026-07-14 19:28:09 +01:00
parent 68097386df
commit bf3f09aeb6
4 changed files with 96 additions and 80 deletions

View file

@ -283,17 +283,34 @@ def ramble_baseline(items: list[dict]) -> float | None:
def rambling_cues(items: list[dict]) -> list[dict]:
"""Cues running far enough past the storyboard's pace to look hallucinated."""
"""Cues running far enough past the storyboard's pace to look hallucinated.
Cues already marked `rambleRepairExhausted` are excluded: we tried every
re-roll and kept the best take we could get, so re-flagging them would
re-run the identical seeds (the server is deterministic per seed) for the
identical result on every render, and would defeat the cache forever.
"""
baseline = ramble_baseline(items)
if baseline is None:
return []
return [
it
for it in items
if secs_per_char(it["text"], it["durationMs"]) > baseline * RAMBLE_TOLERANCE
if not it.get("rambleRepairExhausted")
and secs_per_char(it["text"], it["durationMs"]) > baseline * RAMBLE_TOLERANCE
]
def within_pace(rate: float, baseline: float) -> bool:
"""Is this take's speech rate sane, in EITHER direction?
Two-sided on purpose. A one-sided "not too long" gate would accept a take
whose ending was cut off (rate far BELOW baseline) and stop re-rolling,
quietly shipping clipped narration in place of a ramble.
"""
return baseline / RAMBLE_TOLERANCE <= rate <= baseline * RAMBLE_TOLERANCE
def repair_rambling_cues(
server: str,
audio_dir: Path,
@ -332,12 +349,17 @@ def repair_rambling_cues(
error = abs(candidate_rate - baseline)
if error < best_error:
best, best_error = (data, sample_rate, duration_ms, seed), error
if candidate_rate <= baseline * RAMBLE_TOLERANCE:
if within_pace(candidate_rate, baseline):
break
if best is None:
# Every re-roll was worse than the take we already had. Record that
# we exhausted the sweep so the next render trusts the cache
# instead of re-running these exact seeds for these exact results.
item["rambleRepairExhausted"] = True
print(
f"[synth] cue {item['cueIndex']}: no re-roll beat the original; keeping it",
f"[synth] cue {item['cueIndex']}: no re-roll beat the original; keeping it. "
"Listen before publishing.",
flush=True,
)
continue
@ -347,11 +369,16 @@ def repair_rambling_cues(
item["durationMs"] = duration_ms
item["seed"] = seed
repaired += 1
settled = secs_per_char(item["text"], duration_ms) / baseline
note = "" if settled <= RAMBLE_TOLERANCE else " STILL LONG: listen before publishing"
settled = secs_per_char(item["text"], duration_ms)
note = ""
if not within_pace(settled, baseline):
# Improved but still off-pace: same reasoning as above, stop here
# rather than re-litigating it on every render.
item["rambleRepairExhausted"] = True
note = " STILL OFF-PACE: listen before publishing"
print(
f"[synth] cue {item['cueIndex']}: {duration_ms}ms on seed {seed} "
f"({settled:.1f}x pace){note}",
f"({settled / baseline:.1f}x pace){note}",
flush=True,
)
return repaired