全能创作:定妆/台词/换款与剧情方向硬约束,资源可下载
修角色定妆修改不重出图、角色图混入商品、宠物旁白腔、换款同点复读、剧情反转方向漂移,并补会话资源下载与外观/空消息闸门。
This commit is contained in:
@@ -258,23 +258,43 @@ def _plot_twist_direction_continuation(
|
||||
)
|
||||
if isinstance(direction, dict):
|
||||
title = str(direction.get("title") or choice).strip()
|
||||
conflict = str(direction.get("conflict") or "").strip()
|
||||
product_role = str(direction.get("product_role") or "").strip()
|
||||
reversal = str(direction.get("reversal") or "").strip()
|
||||
tone = str(direction.get("tone") or "").strip()
|
||||
detail = ";".join(
|
||||
str(direction.get(key) or "").strip()
|
||||
for key in ("conflict", "product_role", "reversal", "tone")
|
||||
if str(direction.get(key) or "").strip()
|
||||
part for part in (conflict, product_role, reversal, tone) if part
|
||||
)
|
||||
payload_dir = {
|
||||
"id": str(direction.get("id") or "").strip(),
|
||||
"title": title,
|
||||
"conflict": conflict,
|
||||
"product_role": product_role,
|
||||
"reversal": reversal,
|
||||
"tone": tone,
|
||||
}
|
||||
else:
|
||||
title = choice.strip() or "用户自定义方向"
|
||||
conflict = product_role = reversal = tone = ""
|
||||
detail = title
|
||||
payload_dir = {
|
||||
"id": "",
|
||||
"title": title,
|
||||
"conflict": "",
|
||||
"product_role": "",
|
||||
"reversal": "",
|
||||
"tone": "",
|
||||
}
|
||||
memory = dict(conversation.memory or {})
|
||||
memory["plot_twist_story_direction"] = title
|
||||
memory["plot_twist_story_direction_detail"] = detail
|
||||
memory["plot_twist_story_direction_payload"] = payload_dir
|
||||
conversation.memory = memory
|
||||
conversation.save(update_fields=["memory", "updated_at"])
|
||||
return (
|
||||
f"用户已选择剧情方向【{title}】。方向细节:{detail}。"
|
||||
"现在只调用 write_strategy 写创作策略卡,必须沿用该冲突、商品作用与反转;"
|
||||
"不要再展示方向卡、不要复述选择、不要直接写方案或出片。"
|
||||
"现在只调用 write_strategy 写创作策略卡,策略的创作方向与后续方案/分镜必须严格沿用该冲突、商品作用与反转,"
|
||||
"不得改写成另一套常见带货故事;不要再展示方向卡、不要复述选择、不要直接写方案或出片。"
|
||||
)
|
||||
|
||||
|
||||
@@ -2245,6 +2265,12 @@ class CreationConversationViewSet(TeamScopedViewSetMixin, ModelViewSet):
|
||||
memory["product_info_resolved"] = True
|
||||
if clean_ans and not any(kw in clean_ans for kw in ("按图片", "设计品牌", "不用再问")):
|
||||
memory["product_brand_and_name"] = clean_ans
|
||||
bm = re.search(r"品牌[::是为]?\s*([^\n,,。!!]+)", clean_ans)
|
||||
nm = re.search(r"(?:品名|商品名|产品名)[::是为]?\s*([^\n,,。!!]+)", clean_ans)
|
||||
if bm:
|
||||
memory["product_brand"] = bm.group(1).strip()
|
||||
if nm:
|
||||
memory["product_name"] = nm.group(1).strip()
|
||||
for r in (conversation.pinned_refs or []):
|
||||
if isinstance(r, dict) and r.get("type") in ("asset", "product"):
|
||||
r["name"] = clean_ans
|
||||
@@ -2255,8 +2281,9 @@ class CreationConversationViewSet(TeamScopedViewSetMixin, ModelViewSet):
|
||||
continuation_instruction = "用户要求直接根据图片内容设计品牌与品名推进创作。直接基于图片外观特征推进方案,不要重复追问品牌。"
|
||||
conversation.memory = memory
|
||||
conversation.save(update_fields=["memory", "pinned_refs", "updated_at"])
|
||||
text = ""
|
||||
record_user_message = False
|
||||
# 保留用户原文气泡,便于回看刚填的品牌/品名;不要清空 text,
|
||||
# 否则会落到「消息不能为空」且对话里看不到这次回答。
|
||||
force_creative_turn = True
|
||||
else:
|
||||
continuation_instruction = (
|
||||
"用户刚用输入框回答了你上一句问题。直接基于这条真实回答继续原任务;"
|
||||
@@ -2265,26 +2292,78 @@ class CreationConversationViewSet(TeamScopedViewSetMixin, ModelViewSet):
|
||||
if params_changed:
|
||||
continuation_instruction += " 会话参数已更新,旧方案作废,按新参数重新产出。"
|
||||
|
||||
# 用户对刚生成的角色给出确认/重刷反馈
|
||||
# 用户对刚生成的角色给出确认/重刷/外观修改反馈
|
||||
clean_text = text.strip()
|
||||
if re.search(r"^(使用这[个位只]角色|就用这[个位只]角色|就用[她他它]|满意|确认使用|合适|可以)[继续创作。!! ]*$", clean_text) or clean_text in ("使用这个角色继续创作", "使用这个宠物角色继续创作"):
|
||||
memory_now = dict(conversation.memory or {})
|
||||
person_confirm_pending = bool(memory_now.get("person_confirm_pending"))
|
||||
is_platform_person = memory_now.get("person_source") == "platform_generate"
|
||||
confirmed_person = (
|
||||
bool(re.search(
|
||||
r"^(使用这[个位只]角色|就用这[个位只]角色|就用[她他它]|满意|确认使用|合适|可以)[继续创作。!! ]*$",
|
||||
clean_text,
|
||||
))
|
||||
or clean_text in (
|
||||
"使用这个角色继续创作",
|
||||
"使用这个宠物角色继续创作",
|
||||
)
|
||||
or (person_confirm_pending and clean_text in ("继续", "继续创作"))
|
||||
)
|
||||
regenerate_button = bool(re.search(
|
||||
r"^(重新生成|再生成|重刷|换一个|换位|不满意).{0,6}(角色|人物|模特|宠物)?[。!! ]*$",
|
||||
clean_text,
|
||||
))
|
||||
upload_person = bool(re.search(
|
||||
r"(上传|发一张|发个).{0,8}(人物|角色|模特|宠物)|我上传",
|
||||
clean_text,
|
||||
))
|
||||
if confirmed_person:
|
||||
if person_confirm_pending:
|
||||
memory_now["person_confirm_pending"] = False
|
||||
conversation.memory = memory_now
|
||||
conversation.save(update_fields=["memory", "updated_at"])
|
||||
force_creative_turn = True
|
||||
continuation_instruction = (
|
||||
"用户已确认使用当前生成的角色出镜。直接基于该角色继续推进创作方案"
|
||||
"(若尚未选商品则确定商品,已选好商品则开始写创作策略和方案),不要再次追问角色来源。"
|
||||
)
|
||||
elif re.search(r"^(重新生成|再生成|重刷|换一个|换位|不满意).{0,6}(角色|人物|模特|宠物)?[。!! ]*$", clean_text) and (conversation.memory or {}).get("person_source") == "platform_generate":
|
||||
person_prompt = str((conversation.memory or {}).get("person_prompt") or "").strip()
|
||||
elif is_platform_person and (regenerate_button or (person_confirm_pending and clean_text and not upload_person)):
|
||||
prev_prompt = str(memory_now.get("person_prompt") or "").strip()
|
||||
if regenerate_button:
|
||||
appearance_prompt = prev_prompt
|
||||
elif prev_prompt:
|
||||
appearance_prompt = f"{prev_prompt};按用户最新要求调整:{clean_text}"
|
||||
else:
|
||||
appearance_prompt = clean_text
|
||||
# 卸掉上一张平台定妆锁定,避免新旧角色叠在 pinned_refs 里
|
||||
old_model_id = str(memory_now.get("person_model_id") or "").strip()
|
||||
if old_model_id:
|
||||
conversation.pinned_refs = [
|
||||
ref for ref in (conversation.pinned_refs or [])
|
||||
if not (
|
||||
isinstance(ref, dict)
|
||||
and ref.get("type") in {"model", "character"}
|
||||
and str(ref.get("id") or "") == old_model_id
|
||||
)
|
||||
]
|
||||
memory_now["person_confirm_pending"] = False
|
||||
memory_now.pop("person_source_ready", None)
|
||||
memory_now.pop("person_model_id", None)
|
||||
conversation.memory = memory_now
|
||||
conversation.save(update_fields=["memory", "pinned_refs", "updated_at"])
|
||||
try:
|
||||
user_msg = append_message(conversation, role="user", text=clean_text)
|
||||
generating = submit_generated_person_reference(
|
||||
conversation=conversation,
|
||||
user=request.user,
|
||||
appearance_prompt=person_prompt,
|
||||
appearance_prompt=appearance_prompt,
|
||||
)
|
||||
return JsonResponse({
|
||||
"conversation_id": str(conversation.id),
|
||||
"agent_status": conversation.agent_status,
|
||||
"messages": [CreationMessageSerializer(generating).data],
|
||||
"messages": [
|
||||
CreationMessageSerializer(user_msg).data,
|
||||
CreationMessageSerializer(generating).data,
|
||||
],
|
||||
}, status=202)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -2775,7 +2854,9 @@ class CreationConversationViewSet(TeamScopedViewSetMixin, ModelViewSet):
|
||||
)
|
||||
if params_changed:
|
||||
continuation_instruction += " 会话参数已经更新,旧方案作废,按新参数重新产出方案。"
|
||||
elif not text and not refs:
|
||||
elif not text and not refs and not (force_creative_turn or continuation_instruction):
|
||||
# 追问卡(品牌品名/点选闸门等)会把正文清空、改走 continuation;
|
||||
# 这时没有 text/refs 也是合法推进,不能误报「消息不能为空」。
|
||||
return JsonResponse({"detail": "消息不能为空"}, status=400)
|
||||
|
||||
# 同一账号同时只允许一个整理方案 turn(含本会话已在 planning 的二次发送)
|
||||
|
||||
Reference in New Issue
Block a user