优化完善替换角色
This commit is contained in:
@@ -83,54 +83,25 @@ PRODUCT_PROMPT = (
|
||||
"按下面的商品语义重构分镜生成视频。@目标商品只用于锁定外观、材质与包装。"
|
||||
"严格遵守每镜的新商品动作、场景与口播;不要恢复参考片原商品、原动作、原卖点或原台词。"
|
||||
)
|
||||
# 角色复刻提示词:极简单句。之前那版把声音规则写成五大段反复强调,实测是「开头原声、
|
||||
# 中途才切到目标音色」;长提示词会稀释关键指令,这版改为一句话直给。
|
||||
# ⚠️ 句中的 @参考角色 / @参考音频 必须与 references 的 label 完全一致,否则
|
||||
# build_content_items 映射不成「图片N / 音频N」,火山那边就是一串没有指代的字面量。
|
||||
# 角色复刻提示词:极简单句。
|
||||
# ⚠️ 只换画面,不碰声音 —— 成片保留参考视频原声。
|
||||
# 历史(别再走一遍):试过让 Seedance 换声的四条路,提示词声线规则、音频参考走 TOS 直链、
|
||||
# 走 asset:// 素材库引用、以及平台预置样音,全部只做到「中途才切到目标音色」或完全无效。
|
||||
# 编辑模式(参考视频 + duration=-1 + adaptive)对音轨的处理不受这些输入控制。
|
||||
# 因此产品上收敛为:只支持同性别角色替换,声音一律保留原声,前端明确告知用户。
|
||||
CHARACTER_PROMPT = (
|
||||
"将@参考视频中出现的角色替换为@参考角色,口播、旁白、画外音的音色替换为@参考音频,"
|
||||
"其它部分例如构图、运镜、人物动作、场景、商品、剪辑、画面节奏等保持与原视频一致。"
|
||||
)
|
||||
|
||||
# 没有音频参考(没写明性别)时,把声音那半句去掉,免得点名一个不存在的 @参考音频。
|
||||
CHARACTER_PROMPT_NO_VOICE = (
|
||||
"将@参考视频中出现的角色替换为@参考角色,"
|
||||
"其它部分例如构图、运镜、人物动作、场景、商品、剪辑、画面节奏等保持与原视频一致。"
|
||||
)
|
||||
|
||||
|
||||
def build_character_submit_prompt(subject_brief: str = "", *, has_voice_ref: bool = False) -> str:
|
||||
"""角色复刻提交提示词。就是那一句,不再追加角色设定 ——
|
||||
subject_brief 只用于推导性别(决定用哪条音色样音),不进提示词,保持指令干净。"""
|
||||
return CHARACTER_PROMPT if has_voice_ref else CHARACTER_PROMPT_NO_VOICE
|
||||
"""角色复刻提交提示词。就是那一句。
|
||||
|
||||
|
||||
# 平台预置的目标音色样音(公读直链,不走预签名 —— 参考素材要长期可取)。
|
||||
VOICE_REFERENCE_LABEL = "参考音频"
|
||||
VOICE_REFERENCE_URLS = {
|
||||
# ⚠️ 换音色样音时务必换文件名,不要覆盖旧文件:上传设的是 immutable + 一年强缓存,
|
||||
# 同名覆盖后 CDN / 火山侧可能仍拿到旧音频,查起来很难受。
|
||||
"male": "https://airshelf.tos-s3-cn-shanghai.volces.com/system/video-replace/voice-references/male-v3.mp3",
|
||||
"female": "https://airshelf.tos-s3-cn-shanghai.volces.com/system/video-replace/voice-references/female-bv001.mp3",
|
||||
}
|
||||
|
||||
|
||||
def build_voice_reference_ref(gender: str) -> dict | None:
|
||||
"""平台预置音色样音的 reference 项。读不出性别就没有音频参考。
|
||||
|
||||
⚠️ 不带 asset_id:带了会被 _ensure_replace_refs_reviewed 送去火山真人素材审核,
|
||||
而那套是给图片/视频用的,平台音频过不去会把任务卡死。
|
||||
参数保留是为了兼容既有调用点;声音已不再由提示词控制,两个参数都不影响输出。
|
||||
"""
|
||||
url = VOICE_REFERENCE_URLS.get(gender)
|
||||
if not url:
|
||||
return None
|
||||
return {
|
||||
"url": url,
|
||||
"type": "audio",
|
||||
"role": "reference_audio",
|
||||
"label": VOICE_REFERENCE_LABEL,
|
||||
"source": "platform",
|
||||
}
|
||||
return CHARACTER_PROMPT
|
||||
|
||||
|
||||
# 用户在第 3 步填的补充信息(商品名/品类,或角色性别年龄音色)。选填,不填维持原行为。
|
||||
MAX_SUBJECT_BRIEF = 500
|
||||
@@ -140,20 +111,6 @@ def _clean_subject_brief(value) -> str:
|
||||
return str(value or "").strip()[:MAX_SUBJECT_BRIEF]
|
||||
|
||||
|
||||
def _detect_voice_gender(brief: str) -> str:
|
||||
"""从用户填的角色信息里读性别。返回 male / female / ""(读不出)。
|
||||
|
||||
男女都提到(例如「把女的换成男的」)时不下断言 —— 分不清哪个是目标。
|
||||
"""
|
||||
has_male = "男" in brief
|
||||
has_female = "女" in brief
|
||||
if has_male and not has_female:
|
||||
return "male"
|
||||
if has_female and not has_male:
|
||||
return "female"
|
||||
return ""
|
||||
|
||||
|
||||
# 拆解期间的占位提示词。真正的提示词在 worker 拆完后回写。
|
||||
DIGEST_PENDING_PROMPT = "正在提炼参考视频的分镜稿…"
|
||||
|
||||
@@ -730,7 +687,6 @@ def serialize_video_replace_task(task, *, include_deleted_assets: bool = False)
|
||||
"subject_name": payload.get("subject_name") or "",
|
||||
"subject_source": payload.get("subject_source") or "",
|
||||
"subject_brief": payload.get("subject_brief") or "",
|
||||
"voice_gender": payload.get("voice_gender") or "",
|
||||
"product_id": payload.get("product_id") or "",
|
||||
"model_id": payload.get("model_id") or "",
|
||||
"review_stage": "reviewing" if reviewing else "",
|
||||
@@ -793,7 +749,6 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
# 第 3 步用户填的补充信息。商品:名称/品类/卖点;角色:性别/年龄/音色。选填。
|
||||
subject_brief = _clean_subject_brief(params.get("subject_brief"))
|
||||
# 角色描述识别到性别时,成片后调用火山音色转换;识别不到即保留原声。
|
||||
voice_gender = _detect_voice_gender(subject_brief) if replace_mode == "character" else ""
|
||||
|
||||
if has_product:
|
||||
subject_name, image_refs, subject_source = _product_library_refs(team, product_id)
|
||||
@@ -841,8 +796,6 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
"model_id": str(model_id) if model_id else "",
|
||||
"product_facts": product_facts,
|
||||
"subject_brief": subject_brief,
|
||||
"voice_gender": voice_gender,
|
||||
"voice_strategy": "native_audio_reference" if voice_gender else "preserve_original",
|
||||
# adaptive / -1 只用于火山请求;预估积分仍按参考视频实际时长和上传时检测出的比例计算。
|
||||
"billing_duration": max(4, int(round(video_seconds or 4))),
|
||||
"billing_aspect_ratio": billing_ratio,
|
||||
@@ -868,12 +821,9 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
if resolve_digest_model_config() is None:
|
||||
raise ValueError("视频提炼模型未配置,请联系管理员")
|
||||
if replace_mode == "character":
|
||||
# 平台预置的目标音色样音,和参考视频、角色图一起交给 Seedance。
|
||||
voice_ref = build_voice_reference_ref(voice_gender)
|
||||
image_refs = [
|
||||
_owned_ref(video, kind="video", role="reference_video", label="参考视频"),
|
||||
*image_refs,
|
||||
*([voice_ref] if voice_ref else []),
|
||||
]
|
||||
# 商品图/角色图仍要过审才能当生成参考。提前送审 → 审核和提炼并行跑,明确不过审的直接 400。
|
||||
review_state = _ensure_replace_refs_reviewed(team, image_refs)
|
||||
@@ -895,7 +845,7 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
**base_params,
|
||||
"prompt": (
|
||||
DIGEST_PENDING_PROMPT if replace_mode == "product"
|
||||
else build_character_submit_prompt(subject_brief, has_voice_ref=bool(voice_gender))
|
||||
else build_character_submit_prompt()
|
||||
),
|
||||
"references": image_refs,
|
||||
"extra_payload": extra,
|
||||
|
||||
Reference in New Issue
Block a user