fix: 电商测试清单一轮 bug 修复(视频项目角色/场景 + 图片工作台 + 视频收口)
视频项目(ZWQ): - 演员工作台保存后「我的演员」仍 0 个:保存时加入资产库(in_library=True) - 资产详情「应用当前角色」自动送审(不再要手动点灰盾) - 「我的演员」卡 + 待生成 seed 卡补删除入口(垃圾桶,两步确认) - 新增场景未生成就刷新会丢:sceneDrafts 按项目持久化 localStorage - 场景 AI 生成强制叠加「无真人」约束,避免出真人致视频被火山拒 - 进入项目默认落到当前阶段(不再恒显第 1 阶段) - 视频已出但进度卡 3/4:submit/poll/adopt 幂等补推 current_stage→VIDEO, 否则 settle_video_completion 因阶段守卫直接返回、永不收口 completed 图片工作台(PMC): - 生图走 action 全局单飞锁致并发重跑/多平台套图被拒成「失败/少出图」: action 加 concurrent 选项,生图不占单飞锁 - 切模块再切回状态丢/数量少:每批各自落盘 pendingIds(onSubmitted 回传), 切回时全部批次各自续轮询 附:含一处早前未提交的图片创作改动(选火山+传参考图强制切 gpt-image-2 + gen 气泡溢出 CSS)。 新增/通过测试:AttachOfficialModel、商品图删除、视频卡阶段收口、参考图强切模型。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1069,8 +1069,12 @@ def generate_base_asset(*, project, user, kind: str, prompt: str, label: str = "
|
||||
elif kind == BaseAssetGroup.Kind.PERSON:
|
||||
gen_prompt = build_person_frontal_prompt(prompt) # 人物立绘:包成「电商真人模特/正面全身/纯色背景」统一模板
|
||||
else:
|
||||
# 场景图:默认模板只是 {场景描述} 本身(零回归);可在 admin「提示词」页加全局场景风格
|
||||
# 场景图 = 空镜。不论 admin「提示词」页的 scene 模板写没写,都强制叠加「无真人」约束:
|
||||
# 否则模型常自作主张往场景里塞真人模特,下游用这张场景图生成视频时被火山以
|
||||
# 「输入图像可能包含真实人物」拒绝(ZWQ#13)。已含「真人」字样则不重复叠加。
|
||||
gen_prompt = render_prompt("scene", "{场景描述}", 场景描述=(prompt or "").strip())
|
||||
if "真人" not in gen_prompt:
|
||||
gen_prompt = f"{gen_prompt},空镜场景、只有环境与陈设,画面中不要出现任何真人 / 人物 / 模特 / 人脸 / 人手,干净构图"
|
||||
payload = {
|
||||
"model": model_config.name, "endpoint": model_config.endpoint, "prompt": gen_prompt,
|
||||
"kind": kind, "label": label or "", "group_id": str(group_id) if group_id else "",
|
||||
@@ -2069,6 +2073,13 @@ def enqueue_standalone_images(*, team, user, prompt: str, mode: str = "image", c
|
||||
task_type = _STANDALONE_TASK_TYPE.get(mode, AITask.Type.PRODUCT_IMAGE)
|
||||
count = max(1, min(int(count or 1), 12))
|
||||
ref_ids = [str(r) for r in (reference_image_ids or []) if r]
|
||||
# 带参考图的图片创作必须走 image_edit(gpt-image)才真的还原上传素材——火山 Seedream 的图生图只松散
|
||||
# 借色调、不锁主体(与三视图/模特上身图同理,那两条流程也强制 image_edit)。当前模型不支持 image_edit
|
||||
# 就自动切到 gpt-image-2,否则用户选了火山却传了参考图 → 生成完全不参考素材(用户实测的根因)。
|
||||
if ref_ids and not hasattr(build_provider(model_config), "image_edit"):
|
||||
alt = resolve_image_model("gpt-image")
|
||||
if alt is not None:
|
||||
model_config = alt
|
||||
# 本次提交 = 一组(模特上身图组 / 平台套图组):同一 batch_id 串起这批图,前端可成组展示。
|
||||
batch_id = str(uuid.uuid4())
|
||||
tasks: list[AITask] = []
|
||||
|
||||
@@ -270,6 +270,26 @@ class StandaloneImageReferenceTests(TestCase):
|
||||
self.assertIn("严格保留", used_prompt)
|
||||
prov.image_generation.assert_not_called()
|
||||
|
||||
def test_refs_force_image_edit_model_when_volcano_selected(self):
|
||||
"""用户选了火山 Seedream(只有图生图、不会真锁主体)却传了参考图时,必须自动切到支持
|
||||
image_edit 的 gpt-image-2——否则参考图形同虚设。回归保护「选火山+传参考图=完全不参考」。"""
|
||||
from apps.ai.models import ModelProvider
|
||||
|
||||
vp = ModelProvider.objects.create(name="volcengine", display_name="火山")
|
||||
ModelConfig.objects.create(provider=vp, name="seedream-4", display_name="Seedream", capability=ModelConfig.Capability.IMAGE)
|
||||
self._patch_provider()
|
||||
ref = Asset.objects.create(
|
||||
team=self.team, created_by=self.user, name="背心", asset_type=Asset.Type.IMAGE,
|
||||
source=Asset.Source.UPLOAD, category=Asset.Category.UPLOAD,
|
||||
)
|
||||
AssetFile.objects.create(asset=ref, object_key="r.png", bucket="b", content_type="image/png", preview_url="http://x/ref.png", is_primary=True)
|
||||
tasks = enqueue_standalone_images(
|
||||
team=self.team, user=self.user, prompt="不同场景", mode="image", count=1,
|
||||
image_model="volcano", reference_image_ids=[str(ref.id)],
|
||||
)
|
||||
# 任务最终落在支持 image_edit 的模型(gpt-image),而不是用户选的火山 Seedream
|
||||
self.assertIn("gpt-image", tasks[0].model_config.name)
|
||||
|
||||
|
||||
class ImageConversationTests(TestCase):
|
||||
"""图片创作「对话」实体:CRUD + 团队隔离 + 软删 + 生图自动归属对话 + 任务回填。"""
|
||||
|
||||
Reference in New Issue
Block a user