完成极速成片
This commit is contained in:
@@ -81,7 +81,7 @@ PERSONA_BRIEFS: dict[str, str] = {
|
||||
"urban": "25–32岁都市白领,工位或下班回家,说话像跟同事吐槽,不要主播腔",
|
||||
"bestie": "闺蜜分享口吻,带点兴奋,爱用「你懂的」「我跟你讲」",
|
||||
"ceo": "利落、判断句、少形容词,像拍板不是带货",
|
||||
"reviewer": "先讲怎么试的再给结论,允许提一个小缺点才可信",
|
||||
"reviewer": "先讲怎么试的再给结论;可信度来自过程、适用边界或意外发现,不编造小缺点",
|
||||
"mom": "带娃/家务间隙,讲省事,孩子或家人能沾边",
|
||||
"genz": "宿舍或通勤,短句,像给朋友发语音条",
|
||||
}
|
||||
@@ -103,10 +103,18 @@ _SHOT_SIZE_MARKERS = (
|
||||
"手持", "跟拍", "俯拍", "仰拍", "推近", "拉远", "摇",
|
||||
)
|
||||
_MINOR_CHARACTER_RE = re.compile(
|
||||
r"(?:婴儿|宝宝|宝贝|幼儿|儿童|小孩|小朋友|未成年|男童|女童|baby|toddler|infant)"
|
||||
r"|(?:[0-9零一二三四五六七八九十]{1,3}\s*岁)",
|
||||
r"(?:婴儿|宝宝|宝贝|幼儿|儿童|小孩|小朋友|未成年|男童|女童|baby|toddler|infant)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
_NUMERIC_AGE_RE = re.compile(r"(?<!\d)(\d{1,2})\s*岁")
|
||||
_CHINESE_MINOR_AGE_RE = re.compile(r"(?:[零一二三四五六七八九]岁|十岁|十[一二三四五六七]岁)")
|
||||
_CANNED_DEFECT_RE = re.compile(r"唯一(?:的)?(?:小)?(?:缺点|不足|遗憾)")
|
||||
_NATURAL_TURN_PHRASES = (
|
||||
"我会额外留意的使用细节",
|
||||
"换个场景更能看出差别的地方",
|
||||
"下单前可以先确认的一点",
|
||||
"实测时我更在意的细节",
|
||||
)
|
||||
|
||||
|
||||
_FORMAT_KEY_BY_LABEL = {label: key for key, label in PRESENTATION_FORMATS.items()}
|
||||
@@ -231,7 +239,10 @@ def format_visual_beats(beats: list[tuple[int, int, str]]) -> str:
|
||||
|
||||
def _is_minor_character(name: str, visual_prompt: str) -> bool:
|
||||
"""角色基础资产不得是未成年人,避免真人生图审核拦截与儿童肖像风险。"""
|
||||
return bool(_MINOR_CHARACTER_RE.search(f"{name or ''} {visual_prompt or ''}"))
|
||||
text = f"{name or ''} {visual_prompt or ''}"
|
||||
if _MINOR_CHARACTER_RE.search(text) or _CHINESE_MINOR_AGE_RE.search(text):
|
||||
return True
|
||||
return any(int(age) < 18 for age in _NUMERIC_AGE_RE.findall(text))
|
||||
|
||||
|
||||
def _product_only_visual(duration: int) -> str:
|
||||
@@ -253,6 +264,14 @@ def _product_only_visual(duration: int) -> str:
|
||||
return "【本镜任务】用商品本身传达关键信息,不出现人物。\n【声音】旁白继续,画面不出现未成年人。\n【画面内容】\n" + format_visual_beats(beats)
|
||||
|
||||
|
||||
def _replace_canned_defect_phrase(text: str) -> str:
|
||||
"""不改模型给出的事实,只替换会让测评显得千篇一律的“唯一缺点”话术。"""
|
||||
if not text or not _CANNED_DEFECT_RE.search(text):
|
||||
return text
|
||||
variant = _NATURAL_TURN_PHRASES[sum(map(ord, text)) % len(_NATURAL_TURN_PHRASES)]
|
||||
return _CANNED_DEFECT_RE.sub(variant, text)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# skill 加载(缓存)
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -613,6 +632,11 @@ def build_agent_messages(
|
||||
f"严格按已加载的「{PRESENTATION_FORMATS[fmt]} × {VIDEO_STRUCTURES[structure]}」套路写,"
|
||||
f"不要串成别的结构的套话。\n"
|
||||
)
|
||||
authenticity_line = (
|
||||
"【真实感转折】禁止使用「唯一缺点/唯一不足/唯一的小遗憾」这类模板句,也不要为了显得真实而编造缺点。"
|
||||
"每版从以下角度自然选一个推进:测试过程里的意外发现、适用人群的边界、不同使用场景的反差、"
|
||||
"一个可观察的细节、或使用习惯建议;必须由商品资料或画面可观察事实支持,不能每镜重复同一种。\n"
|
||||
)
|
||||
head = (
|
||||
f"【画幅】{aspect_ratio}\n"
|
||||
f"【表现形式】{PRESENTATION_FORMATS[fmt]}(套路见 playbooks/format-{fmt}.md,已加载)\n"
|
||||
@@ -623,6 +647,7 @@ def build_agent_messages(
|
||||
f"{beats_line}"
|
||||
f"{structure_line}"
|
||||
f"{combo_line}"
|
||||
f"{authenticity_line}"
|
||||
f"【商品信息】\n{_product_context(project, selling_point_ids, persona)}"
|
||||
)
|
||||
if mode == "revise" and base_draft and target_index is not None:
|
||||
@@ -1196,7 +1221,7 @@ def normalize_draft(
|
||||
if not line:
|
||||
continue
|
||||
sp = d.get("speaker")
|
||||
dialogue.append({"speaker": sp if sp in valid_ids else None, "line": line})
|
||||
dialogue.append({"speaker": sp if sp in valid_ids else None, "line": _replace_canned_defect_phrase(line)})
|
||||
# 旁白:结构化对白/lines 优先,其次整句字符串 dialogue,再退到通用字段解析(narration/voiceover/caption/字幕…)
|
||||
narration = ""
|
||||
if isinstance(raw_dialogue, str) and raw_dialogue.strip():
|
||||
@@ -1205,8 +1230,9 @@ def normalize_draft(
|
||||
narration = " ".join(d["line"] for d in dialogue) # 扁平拼接,兼容下游字幕/配音
|
||||
if not narration:
|
||||
narration = _pick_field(seg, _NARRATION_EXACT, _NARRATION_FUZZY)
|
||||
narration = _replace_canned_defect_phrase(narration)
|
||||
# 画面:优先收成秒级分镜;beats 数组会折进 visual,下游故事板/视频直接读这一段。
|
||||
visual = compose_segment_visual(seg)
|
||||
visual = _replace_canned_defect_phrase(compose_segment_visual(seg))
|
||||
norm_segments.append(
|
||||
{
|
||||
"index": i,
|
||||
@@ -1255,7 +1281,7 @@ def normalize_draft(
|
||||
elif index < len(segments) and isinstance(segments[index], dict):
|
||||
composed = compose_segment_visual(segments[index], seconds)
|
||||
if composed:
|
||||
norm["visual"] = composed
|
||||
norm["visual"] = _replace_canned_defect_phrase(composed)
|
||||
|
||||
draft["segments"] = norm_segments
|
||||
draft["segment_count"] = len(norm_segments)
|
||||
|
||||
Reference in New Issue
Block a user