feat(video-prompt): 台词带说话人照脚本原样 + 时长/比例只走参数不写正文
- _segment_script_text:有结构化对白(dialogue)就按「说话人:台词」原样放(说话人 id 用 script_entities
解析成名字,如 室友/学生女主),回退扁平 narration;新增 with_dialogue/with_exposure 开关
- build_video_segment_prompt:视频脚本用带说话人台词、不带「商品露出」行(露出靠尾句统一要求);
正文去掉 {时长}s · 9:16 竖屏(时长/比例本就 API 参数 duration/ratio 传,不再重复写进文字)
- 尾句改为:电商带货短视频,商品露出清晰,节奏有转化感。不要字幕,不要背景音乐,但是要有音效,逼真的音效
- 迁移 0014 同步刷新 DB 里 video_segment 模板(DB 覆盖代码默认),admin「视频」卡随之更新
真渲染 v3·场1 与产品对齐版一致;后端测试通过。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c2c2dfdc77
commit
ee842da19c
@@ -0,0 +1,29 @@
|
|||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
# 视频提示词模板更新:时长/比例靠 API 参数传(不写正文)、台词带说话人(在 build 里)、
|
||||||
|
# 尾句改风格 + 音效/字幕要求。DB 模板覆盖代码默认,故这里同步刷新 video_segment 那行。
|
||||||
|
NEW = (
|
||||||
|
"{设定}{分镜}【脚本】{脚本}\n"
|
||||||
|
"电商带货短视频,商品露出清晰,节奏有转化感。不要字幕,不要背景音乐,但是要有音效,逼真的音效。"
|
||||||
|
)
|
||||||
|
OLD = "{设定}{分镜}【脚本】{脚本}\n{时长}s · 9:16 竖屏电商带货短视频,镜头稳定,商品露出清晰,节奏有转化感。"
|
||||||
|
|
||||||
|
|
||||||
|
def _set(apps, template):
|
||||||
|
PromptTemplate = apps.get_model("ai", "PromptTemplate")
|
||||||
|
PromptTemplate.objects.filter(key="video_segment").update(template=template)
|
||||||
|
|
||||||
|
|
||||||
|
def forwards(apps, schema_editor):
|
||||||
|
_set(apps, NEW)
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(apps, schema_editor):
|
||||||
|
_set(apps, OLD)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("ai", "0013_seed_prompt_templates")]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(forwards, backwards)]
|
||||||
@@ -1094,16 +1094,33 @@ def _scene_context(project) -> str:
|
|||||||
return " · ".join(parts)
|
return " · ".join(parts)
|
||||||
|
|
||||||
|
|
||||||
def _segment_script_text(segment) -> str:
|
def _segment_script_text(segment, entities=None, *, with_dialogue: bool = False, with_exposure: bool = True) -> str:
|
||||||
"""本镜脚本文本(画面 + 口播/旁白 + 商品露出),拼进故事板/视频提示词的【分镜脚本】。"""
|
"""本镜脚本文本(画面 + 台词/口播 + 商品露出),拼进故事板/视频提示词的【分镜脚本】。
|
||||||
|
with_dialogue:有结构化对白时按「说话人:台词」原样放(说话人 id 用 entities 解析成名字),回退扁平 narration。
|
||||||
|
with_exposure:是否带「商品露出:…」一行。"""
|
||||||
parts = []
|
parts = []
|
||||||
visual = (segment.visual_prompt or "").strip()
|
visual = (segment.visual_prompt or "").strip()
|
||||||
if visual:
|
if visual:
|
||||||
parts.append(f"画面:{visual}")
|
parts.append(f"画面:{visual}")
|
||||||
narration = (segment.narration or "").strip()
|
dialogue = getattr(segment, "dialogue", None) if with_dialogue else None
|
||||||
if narration:
|
name_by_id = {e.get("id"): (e.get("name") or "").strip() for e in (entities or []) if isinstance(e, dict)}
|
||||||
parts.append(f"口播/旁白:{narration}")
|
lines = []
|
||||||
if getattr(segment, "product_exposure", ""):
|
if isinstance(dialogue, list):
|
||||||
|
for d in dialogue:
|
||||||
|
if not isinstance(d, dict):
|
||||||
|
continue
|
||||||
|
line = (d.get("line") or "").strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
spk = name_by_id.get(d.get("speaker")) or ""
|
||||||
|
lines.append(f"{spk}:{line}" if spk else line)
|
||||||
|
if lines: # 有对白 → 用带说话人的台词
|
||||||
|
parts.append("台词:\n" + "\n".join(lines))
|
||||||
|
else: # 无对白 → 回退扁平口播/旁白
|
||||||
|
narration = (segment.narration or "").strip()
|
||||||
|
if narration:
|
||||||
|
parts.append(f"口播/旁白:{narration}")
|
||||||
|
if with_exposure and getattr(segment, "product_exposure", ""):
|
||||||
parts.append(f"商品露出:{segment.product_exposure.strip()}")
|
parts.append(f"商品露出:{segment.product_exposure.strip()}")
|
||||||
return "\n".join(parts)
|
return "\n".join(parts)
|
||||||
|
|
||||||
@@ -1141,12 +1158,15 @@ def build_video_segment_prompt(project, video_segment, scene, refs, user_prompt:
|
|||||||
storyboard_idx = n
|
storyboard_idx = n
|
||||||
else:
|
else:
|
||||||
setup_parts.append(f"@图{n}是{r.get('label') or ''}({_ENTITY_TYPE_CN.get(r.get('type'), '参考')})")
|
setup_parts.append(f"@图{n}是{r.get('label') or ''}({_ENTITY_TYPE_CN.get(r.get('type'), '参考')})")
|
||||||
script_text = _segment_script_text(scene) if scene is not None else ""
|
# 视频脚本:用带说话人的台词(原样照脚本),不带「商品露出」那行(露出靠模板尾句统一要求)
|
||||||
|
entities = (project.metadata or {}).get("script_entities", [])
|
||||||
|
script_text = _segment_script_text(scene, entities, with_dialogue=True, with_exposure=False) if scene is not None else ""
|
||||||
extra = (user_prompt or "").strip()
|
extra = (user_prompt or "").strip()
|
||||||
if extra:
|
if extra:
|
||||||
script_text = (script_text + "\n" + extra).strip() if script_text else extra
|
script_text = (script_text + "\n" + extra).strip() if script_text else extra
|
||||||
# 正文可在 admin「提示词·视频」页改。占位符:{设定}=@图N点名、{分镜}=分镜图引用、{脚本}=本段脚本、{时长}。
|
# 正文可在 admin「提示词·视频」页改。占位符:{设定}=@图N点名、{分镜}=分镜图引用、{脚本}=本段脚本、{时长}。
|
||||||
default = "{设定}{分镜}【脚本】{脚本}\n{时长}s · 9:16 竖屏电商带货短视频,镜头稳定,商品露出清晰,节奏有转化感。"
|
# 时长/比例靠 API 参数传(duration/ratio),不写进正文;尾句给风格 + 音效/字幕要求。
|
||||||
|
default = "{设定}{分镜}【脚本】{脚本}\n电商带货短视频,商品露出清晰,节奏有转化感。不要字幕,不要背景音乐,但是要有音效,逼真的音效。"
|
||||||
rendered = render_prompt(
|
rendered = render_prompt(
|
||||||
"video_segment", default,
|
"video_segment", default,
|
||||||
设定=("【设定】" + ",".join(setup_parts) + "。\n" if setup_parts else ""),
|
设定=("【设定】" + ",".join(setup_parts) + "。\n" if setup_parts else ""),
|
||||||
|
|||||||
Reference in New Issue
Block a user