feat(prompts): admin「提示词」页 —— 视频线 6 条生图/视频提示词正文+比例可在后台改,不再写死

诉求:生图/视频提示词全写死在代码里,产品方看不到也改不了(之前那版只做成「质量后缀」不是正文)。
现新增可编辑「提示词模板」体系,覆盖视频项目生产线 6 条:人物立绘 / 人物三视图 / 商品三视图 /
场景图 / 分镜图 / 视频。

后端:
- 新模型 PromptTemplate(key 固定 6 条 + template 正文 + ratio 比例 + enabled);迁移 0012/0013
  种入默认正文(= 各 builder 现写死文本,零回归)。
- render_prompt(key, default, **字段):读 DB 模板,留空/停用回落默认;安全替换 {占位符}(中文名),
  未知占位符原样保留(改错不致命)。prompt_ratio_size:比例→gpt-image 尺寸。
- 6 个 builder/调用点改走模板;5 条图比例可改(gpt-image 仅 1:1/竖/横),视频固定 Seedance 9:16。
  场景图新增可编辑「场景风格」包装(默认仅 {场景描述},零回归)。人物/分镜/视频原质量后缀并入模板。
- adminpanel CRUD:GET /prompt-templates、PATCH /<id>(改正文/比例/启用,key 不可改、不增删,带审计)。

前端:admin 新增「提示词」侧栏页(/admin/prompts):6 卡,每卡=占位符提示+正文文本框+比例按钮+
启用开关+保存。复用 .btn/.card-hard 共享类,仅 token 配色,单橙锚点。

验证:Django 套件 102 全绿(含新模型/API/生成侧立即生效 + 人物提示词改读模板);tsc+vite build 绿;
无头(独立 sqlite 栈)真开 /admin/prompts:6 卡齐、文本框/比例/占位符齐、0 控制台错误。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-23 03:19:07 +08:00
co-authored by Claude Opus 4.8
parent 304a083184
commit 9c2a3bc365
13 changed files with 485 additions and 64 deletions
+26
View File
@@ -135,3 +135,29 @@ class QualityWord(TimeStampedModel):
def __str__(self) -> str:
return f"{self.stage}/{self.slot}/{self.text}"
class PromptTemplate(TimeStampedModel):
"""平台可编辑的「生图/视频提示词模板」(视频项目生产线 6 条)。后台超管在 admin 改正文,
生成侧据 key 读取本表;留空/停用 → 回落各 builder 的写死默认(零回归)。
正文里 {占位符}(如 {商品}/{描述}/{脚本})运行时替换;未知占位符原样保留,改错不致命。
ratio:成品比例(空=按写死默认),gpt-image 仅 1:1 / portrait(竖) / landscape(横)三种。"""
class Key(models.TextChoices):
PERSON_PORTRAIT = "person_portrait", "人物立绘"
PERSON_TRIVIEW = "person_triview", "人物三视图"
PRODUCT_TRIVIEW = "product_triview", "商品三视图"
SCENE = "scene", "场景图"
STORYBOARD_FRAME = "storyboard_frame", "分镜图"
VIDEO_SEGMENT = "video_segment", "视频"
key = models.CharField(max_length=32, choices=Key.choices, unique=True)
template = models.TextField(blank=True, default="")
ratio = models.CharField(max_length=12, blank=True, default="") # "" / "1:1" / "portrait" / "landscape"
enabled = models.BooleanField(default=True)
class Meta:
ordering = ["key"]
def __str__(self) -> str:
return f"prompt:{self.key}"