feat(admin): Phase 4 质量词 Admin(平台单层) — QualityWord + 生成侧读配置(无配置回落) + 质量词页
后端:apps/ai QualityWord(stage/slot/text/sort/enabled)+ migration;services.py quality_words/quality_suffix, 4 个 builder 接入(person/model_tryon/storyboard/video)无配置回落原写死值零回归;adminpanel CRUD + 审计。 前端:adminApi quality 系列;Admin 质量词页(按 stage 分组卡 + 编辑模式开关 + 行内增改删 chip)。 测试:adminpanel 23 + accounts 22 = 45 单测过(CRUD/权限/生成读配置+回落/停用词不取); 无头 e2e _admin-p4.mjs 4 断言过 + 0 console error + live 库零残留;tsc+build 绿。 注:apps.ai 3 个 image_edit 路由测试失败为进场前既有(已 stash 比对 HEAD 同样失败),非本 Phase 引入。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6560633959
commit
01d4f235ed
@@ -599,6 +599,26 @@ def _product_cover_url(product) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def quality_words(stage: str, slot: str = "quality") -> list[str]:
|
||||
"""平台单层质量词配置(QualityWord)。无配置/表不存在 → 返回 [],调用方回落写死值,保证零回归。"""
|
||||
try:
|
||||
from apps.ai.models import QualityWord
|
||||
|
||||
return list(
|
||||
QualityWord.objects.filter(stage=stage, slot=slot, enabled=True)
|
||||
.order_by("sort", "created_at")
|
||||
.values_list("text", flat=True)
|
||||
)
|
||||
except Exception: # noqa: BLE001 — 配置读取失败绝不阻断生成
|
||||
return []
|
||||
|
||||
|
||||
def quality_suffix(stage: str, fallback: str, slot: str = "quality", sep: str = ",") -> str:
|
||||
"""取该阶段配置的质量词拼成尾串;无配置回落到 fallback(各 builder 的原写死值)。"""
|
||||
words = quality_words(stage, slot)
|
||||
return sep.join(words) if words else fallback
|
||||
|
||||
|
||||
def build_product_triview_prompt_refs(product, base_prompt: str = "") -> str:
|
||||
"""商品三视图 image_edit 提示词(refs 版):参考图1=商品真实主图,锁包装一致性。"""
|
||||
name = (getattr(product, "title", "") or "商品").strip()
|
||||
@@ -630,7 +650,7 @@ def build_model_tryon_prompt_refs(product, has_model: bool, base_prompt: str = "
|
||||
"请生成一位真人模特自然地展示/佩戴/使用参考图1中商品的电商效果图。",
|
||||
"商品的外形、品牌文字、配色、Logo 必须与参考图1高度一致,不要改动或重新设计。",
|
||||
]
|
||||
lines.append("自然光、真实质感、干净背景、电商主图构图,人物与商品比例真实协调。")
|
||||
lines.append(quality_suffix("model_tryon", "自然光、真实质感、干净背景、电商主图构图,人物与商品比例真实协调。"))
|
||||
if base_prompt and base_prompt.strip():
|
||||
lines.append(base_prompt.strip())
|
||||
return " ".join(lines)
|
||||
@@ -662,7 +682,8 @@ def build_person_frontal_prompt(description: str = "") -> str:
|
||||
用户钦定格式:电商真人模特,氛围正面全身照,<描述>,自然妆容,柔和影棚光,真实质感,单人,纯色背景。"""
|
||||
desc = (description or "").strip()
|
||||
inner = f"{desc}," if desc else ""
|
||||
return f"电商真人模特,氛围正面全身照,{inner}自然妆容,柔和影棚光,真实质感,单人,纯色背景"
|
||||
tail = quality_suffix("person", "自然妆容,柔和影棚光,真实质感,单人,纯色背景")
|
||||
return f"电商真人模特,氛围正面全身照,{inner}{tail}"
|
||||
|
||||
|
||||
def generate_base_asset(*, project, user, kind: str, prompt: str, label: str = "", group_id: str | None = None) -> AITask:
|
||||
@@ -896,7 +917,7 @@ def build_storyboard_frame_prompt(project, version, segment) -> str:
|
||||
]
|
||||
if version.prompt:
|
||||
lines.append(version.prompt.strip())
|
||||
lines.append("电商竖屏 9:16 导演故事板,真实清新、生活化,画面清晰,可直接指导视频生成。")
|
||||
lines.append(quality_suffix("storyboard", "电商竖屏 9:16 导演故事板,真实清新、生活化,画面清晰,可直接指导视频生成。"))
|
||||
return "\n".join(line for line in lines if line)
|
||||
|
||||
|
||||
@@ -923,7 +944,10 @@ def build_video_segment_prompt(project, video_segment, scene, refs, user_prompt:
|
||||
if extra:
|
||||
script_text = (script_text + "\n" + extra).strip() if script_text else extra
|
||||
lines.append("【脚本】" + (script_text or f"第 {video_segment.sort_order + 1} 段"))
|
||||
lines.append(f"{video_segment.target_duration_seconds}s · 9:16 竖屏电商带货短视频,镜头稳定,商品露出清晰,节奏有转化感。")
|
||||
lines.append(
|
||||
f"{video_segment.target_duration_seconds}s · "
|
||||
+ quality_suffix("video", "9:16 竖屏电商带货短视频,镜头稳定,商品露出清晰,节奏有转化感。")
|
||||
)
|
||||
return "\n".join(line for line in lines if line)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user