feat: add storyboard script rewriting
This commit is contained in:
63
api/main.py
63
api/main.py
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user