feat: add storyboard script rewriting

This commit is contained in:
2026-05-17 20:52:52 +08:00
parent db248221f7
commit 096f201470
2 changed files with 54 additions and 25 deletions

View File

@@ -2618,17 +2618,22 @@ def translate_text(req: TranslateReq) -> dict:
def _fallback_script_rewrite_item(segment: ScriptRewriteSegmentReq, author_intent: str = "") -> dict:
text = (segment.current_text or "").strip()
source = (segment.source or "").strip()
intent = (author_intent or "").strip()
if text:
rewritten = text
elif source:
rewritten = f"这一段按原片节奏切到 SKG 肩颈按摩仪,把{source[:28]}转成肩颈放松场景"
else:
rewritten = "这一段延续原片节奏,把画面和口播落到 SKG 肩颈放松体验"
if intent and intent not in rewritten:
rewritten = f"{rewritten} {intent[:48]}"
role = segment.role or ""
templates = {
"开场钩子": "你有没有发现,低头久了以后,脖子和肩膀会先替你喊累。",
"痛点推进": "刷手机、坐电脑、赶通勤叠在一起,肩颈很容易一直绷着放不下来",
"利益证明": "SKG 这种挂脖按摩仪,重点就是贴住肩颈位置,把热敷感和揉按感带到真正紧的地方。",
"方案过渡": "这一段可以直接拍拿起、戴上、贴合,让产品自然进入日常放松场景",
"转化收口": "如果你也想把肩颈放松变成每天的小习惯,可以从这台 SKG 开始。",
"节奏承接": "顺着原片节奏,把这一句落到一个具体的肩颈使用场景里。",
}
rewritten = templates.get(role, templates["节奏承接"])
if source and role not in {"开场钩子", "转化收口"}:
rewritten = f"{rewritten} 原片这一句的节奏可以保留,但内容换成 SKG 的佩戴和放松体验。"
if intent:
rewritten = f"{rewritten} 语气按作者想法处理:{intent[:44]}"
return {"index": segment.index, "text": rewritten[:220]}
@@ -2695,21 +2700,31 @@ def _rewrite_storyboard_script_sync(req: RewriteStoryboardScriptReq) -> list[dic
+ json.dumps(payload, ensure_ascii=False)
+ '\n\n只输出严格 JSON{"items":[{"index":0,"text":"改写后的中文口播"}]}'
)
try:
resp = llm().chat.completions.create(
model=AUDIO_REWRITE_MODEL,
messages=[
{"role": "system", "content": "只返回合法 JSON不要 markdown不要解释。"},
{"role": "user", "content": prompt},
],
response_format={"type": "json_object"},
temperature=0.68 if req.mode == "all" else 0.62,
max_tokens=max(900, min(5000, 180 * len(segments) + 500)),
)
raw = (resp.choices[0].message.content or "").strip()
return _parse_script_rewrite_items(raw, segments, author_intent)
except Exception:
return [_fallback_script_rewrite_item(segment, author_intent) for segment in segments]
models = []
for model in [AUDIO_REWRITE_MODEL, ASR_FALLBACK_MODEL, TRANSLATE_MODEL]:
if model and model not in models:
models.append(model)
for model in models:
try:
resp = llm().chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "只返回合法 JSON不要 markdown不要解释。"},
{"role": "user", "content": prompt},
],
response_format={"type": "json_object"},
temperature=0.68 if req.mode == "all" else 0.62,
max_tokens=max(900, min(5000, 180 * len(segments) + 500)),
)
message = resp.choices[0].message
raw = (message.content or getattr(message, "reasoning_content", "") or "").strip()
items = _parse_script_rewrite_items(raw, segments, author_intent)
if any((item.get("text") or "").strip() for item in items):
return items
except Exception as e:
print(f"[script rewrite fallback] {model}: {e}", flush=True)
continue
return [_fallback_script_rewrite_item(segment, author_intent) for segment in segments]
@app.post("/jobs/{job_id}/script/rewrite")