auto-save 2026-05-14 05:05 (~6)

This commit is contained in:
2026-05-14 05:05:22 +08:00
parent f1f3a0fbe5
commit f2663eb90e
6 changed files with 312 additions and 17 deletions

View File

@@ -96,7 +96,7 @@ AssetBackground = Literal["white", "black"]
AssetSize = Literal["source", "1024", "1536", "2048"]
AssetQuality = Literal["hd"]
SubjectKind = Literal["object", "living"]
SubjectView = Literal["front", "back", "left", "right", "side", "side_walk", "top", "bottom", "expression"]
SubjectView = str
FRAME_TARGET_LABELS: dict[FrameExtractTarget, str] = {
"balanced": "综合关键帧",
"subject": "清晰主体",
@@ -690,16 +690,43 @@ def _make_reference_contact_sheet(job_id: str, frame_indices: list[int], out_pat
return out_path
def _subject_view_labels(kind: SubjectKind) -> list[tuple[SubjectView, str]]:
SUBJECT_VIEW_LABELS: dict[str, str] = {
"front": "正面",
"back": "背面",
"left": "左侧",
"right": "右侧",
"side": "侧面",
"side_walk": "侧面走路",
"top": "顶部视角",
"bottom": "底部视角",
"expression_neutral": "中性表情",
"expression_happy": "开心表情",
"expression_angry": "生气表情",
"expression_sad": "难过表情",
"expression_relaxed": "放松表情",
"action_walk": "走路动作",
"action_sit": "坐姿动作",
"action_hold": "手持动作",
"action_use": "使用动作",
}
def _subject_view_labels(kind: SubjectKind, requested: list[str] | None = None) -> list[tuple[SubjectView, str]]:
if requested:
normalized: list[str] = []
for raw in requested:
key = "".join(ch for ch in str(raw).strip().lower() if ch.isalnum() or ch == "_")
if key and key not in normalized:
normalized.append(key)
return [(key, SUBJECT_VIEW_LABELS.get(key, key.replace("_", " "))) for key in normalized[:12]]
if kind == "living":
return [
("front", "正面站立"),
("back", "背面站立"),
("side", "侧面站立"),
("side_walk", "侧面走路"),
("top", "顶部视角"),
("bottom", "底部视角"),
("expression", "表情参考"),
("expression_neutral", "中性表情"),
("expression_relaxed", "放松表情"),
]
return [
("front", "正面"),
@@ -1911,6 +1938,7 @@ class GenerateSubjectAssetsReq(BaseModel):
quality: AssetQuality = "hd"
size: AssetSize = "source"
source_frame_indices: list[int] | None = None
views: list[str] | None = None
@app.post("/jobs/{job_id}/frames/{idx}/elements", response_model=Job)
@@ -2205,11 +2233,14 @@ def generate_subject_assets(job_id: str, idx: int, element_id: str, req: Generat
models = [IMAGE_MODEL, "gemini-3.1-flash-image-preview", "gemini-2.5-flash-image"]
generated: list[SubjectAsset] = []
try:
for view, view_label in _subject_view_labels(req.subject_kind):
for view, view_label in _subject_view_labels(req.subject_kind, req.views):
if view == "side_walk":
view_prompt = "side view in a natural walking pose, same identity and proportions"
elif view == "expression":
view_prompt = "clear expression reference, frontal or three-quarter standing pose, preserving the same identity"
elif view.startswith("expression_"):
emotion = view_label.replace("表情", "")
view_prompt = f"clear {emotion} facial expression reference, frontal or three-quarter standing pose, preserving the same identity"
elif view.startswith("action_"):
view_prompt = f"{view_label} reference pose, same identity and proportions"
else:
view_prompt = f"{view_label} view"
prompt = (