auto-save 2026-05-13 15:17 (~6)

This commit is contained in:
2026-05-13 15:17:18 +08:00
parent 02df0c5a60
commit 6390472c27
6 changed files with 124 additions and 24 deletions

View File

@@ -73,6 +73,17 @@ class StoryboardScene(BaseModel):
reference_ids: list[str] = [] # 参考图:选用该分镜里已提取的 element ids 作 reference
class StoryboardImage(BaseModel):
"""用户从各处"上推"到分镜头编排区的图片"""
ref_id: str # uuid hex 8
kind: Literal["keyframe", "cutout"] # keyframe = 关键帧本身 / cutout = 元素提取图
frame_idx: int
element_id: str | None = None # cutout 时
cutout_id: str | None = None # cutout 时versioned id老数据可能 == element_id
label: str = "" # 显示用名字
created_at: float = 0.0
class KeyElement(BaseModel):
"""关键帧里识别 / 用户提取的元素 · 多次提取累积多张图,让用户挑选满意的"""
id: str # uuid hex 8
@@ -121,6 +132,7 @@ class Job(BaseModel):
height: int = 0
frames: list[KeyFrame] = Field(default_factory=list)
transcript: list[TranscriptSegment] = Field(default_factory=list)
storyboard_images: list[StoryboardImage] = Field(default_factory=list)
error: str = ""
@@ -1434,6 +1446,55 @@ def update_storyboard(job_id: str, idx: int, req: UpdateStoryboardReq) -> Job:
return job
class PushStoryboardImageReq(BaseModel):
kind: Literal["keyframe", "cutout"]
frame_idx: int
element_id: str | None = None
cutout_id: str | None = None
label: str = ""
@app.post("/jobs/{job_id}/storyboard-images", response_model=Job)
def push_storyboard_image(job_id: str, req: PushStoryboardImageReq) -> Job:
"""把一张图(关键帧本身或元素提取图)推送到分镜头编排区"""
import time as _time
job = JOBS.get(job_id)
if not job:
raise HTTPException(404, "job not found")
# 防重复推送:相同 frame_idx + element_id + cutout_id 已存在就跳过
for existing in job.storyboard_images:
if (existing.kind == req.kind
and existing.frame_idx == req.frame_idx
and existing.element_id == req.element_id
and existing.cutout_id == req.cutout_id):
return job
img = StoryboardImage(
ref_id=uuid.uuid4().hex[:8],
kind=req.kind,
frame_idx=req.frame_idx,
element_id=req.element_id,
cutout_id=req.cutout_id,
label=req.label.strip(),
created_at=_time.time(),
)
update(job, storyboard_images=job.storyboard_images + [img], message=f"上推到分镜头编排 · {req.label or req.kind}")
return job
@app.delete("/jobs/{job_id}/storyboard-images/{ref_id}", response_model=Job)
def remove_storyboard_image(job_id: str, ref_id: str) -> Job:
"""从分镜头编排区移除一张图"""
job = JOBS.get(job_id)
if not job:
raise HTTPException(404, "job not found")
before = len(job.storyboard_images)
new_list = [x for x in job.storyboard_images if x.ref_id != ref_id]
if len(new_list) == before:
raise HTTPException(404, "storyboard image not found")
update(job, storyboard_images=new_list, message="从分镜头编排移除一张图")
return job
@app.get("/jobs/{job_id}/frames/{idx}/elements/{element_id}/cutouts/{cutout_id}.jpg")
def get_cutout_versioned(job_id: str, idx: int, element_id: str, cutout_id: str):
p = job_dir(job_id) / "elements" / f"{idx:03d}_{element_id}_{cutout_id}.jpg"