auto-save 2026-05-18 06:33 (~5)
This commit is contained in:
59
api/main.py
59
api/main.py
@@ -1134,6 +1134,17 @@ def _asset_url(job_id: str, asset_id: str) -> str:
|
||||
return f"/jobs/{job_id}/assets/{asset_id}.jpg"
|
||||
|
||||
|
||||
def _delete_subject_asset_file(job_id: str, asset_id: str) -> None:
|
||||
if not asset_id:
|
||||
return
|
||||
p = job_dir(job_id) / "assets" / f"{asset_id}.jpg"
|
||||
if p.exists():
|
||||
try:
|
||||
p.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def _find_frame(job: Job, idx: int) -> KeyFrame:
|
||||
frame = next((f for f in job.frames if f.index == idx), None)
|
||||
if not frame:
|
||||
@@ -3560,6 +3571,7 @@ class GenerateSubjectAssetsReq(BaseModel):
|
||||
subject_style: Literal["transparent_human", "source_actor"] = "transparent_human"
|
||||
reconstruction_mode: Literal["same", "similar"] = "same"
|
||||
prompt: str = ""
|
||||
replace_views: bool = False
|
||||
|
||||
|
||||
class UpdateProductRefsReq(BaseModel):
|
||||
@@ -3974,6 +3986,17 @@ def generate_subject_assets(job_id: str, idx: int, element_id: str, req: Generat
|
||||
if sheet:
|
||||
model_src = sheet
|
||||
|
||||
try:
|
||||
with Image.open(_source_frame_path(job_id, idx)) as src_im:
|
||||
source_is_portrait = src_im.height > src_im.width
|
||||
except Exception:
|
||||
source_is_portrait = False
|
||||
canvas_clause = (
|
||||
"Canvas and aspect ratio: the reference video frame is vertical, so output a vertical portrait 9:16-style image, not a square canvas and not a horizontal layout. "
|
||||
if source_is_portrait
|
||||
else "Canvas and aspect ratio: keep a single clean reference-image canvas with the same broad orientation as the source evidence. "
|
||||
)
|
||||
|
||||
target = (el.name_en or el.name_zh).strip()
|
||||
bg_phrase = "pure white" if req.background == "white" else "pure black"
|
||||
similar_actor = req.subject_kind == "living" and req.subject_style == "source_actor" and req.reconstruction_mode == "similar"
|
||||
@@ -4036,6 +4059,7 @@ def generate_subject_assets(job_id: str, idx: int, element_id: str, req: Generat
|
||||
+ single_view_clause
|
||||
+ identity_clause
|
||||
+ identity_lock_clause
|
||||
+ canvas_clause
|
||||
+ prompt_extra_clause
|
||||
+ actor_style_clause
|
||||
+ "The subject must be complete, centered, full body or full object, head-to-feet visible when applicable, not cropped by the canvas. "
|
||||
@@ -4082,12 +4106,45 @@ def generate_subject_assets(job_id: str, idx: int, element_id: str, req: Generat
|
||||
if e.id == element_id:
|
||||
e.subject_kind = req.subject_kind
|
||||
e.cutout_background = req.background
|
||||
e.subject_assets = (e.subject_assets or []) + generated
|
||||
current_assets = e.subject_assets or []
|
||||
if req.replace_views:
|
||||
replaced_views = {asset.view for asset in generated}
|
||||
for old_asset in current_assets:
|
||||
if old_asset.view in replaced_views:
|
||||
_delete_subject_asset_file(job_id, old_asset.id)
|
||||
current_assets = [asset for asset in current_assets if asset.view not in replaced_views]
|
||||
e.subject_assets = current_assets + generated
|
||||
new_frames.append(f)
|
||||
update(job, frames=new_frames, message=f"主体资产包生成完成 · {el.name_zh} · {len(generated)} 张")
|
||||
return job
|
||||
|
||||
|
||||
@app.delete("/jobs/{job_id}/frames/{idx}/elements/{element_id}/subject-assets/{asset_id}", response_model=Job)
|
||||
def delete_subject_asset(job_id: str, idx: int, element_id: str, asset_id: str) -> Job:
|
||||
"""删除某张主体白底视图。"""
|
||||
job = JOBS.get(job_id)
|
||||
if not job:
|
||||
raise HTTPException(404, "job not found")
|
||||
frame = _find_frame(job, idx)
|
||||
el = next((e for e in frame.elements if e.id == element_id), None)
|
||||
if not el:
|
||||
raise HTTPException(404, "element not found")
|
||||
assets = el.subject_assets or []
|
||||
if not any(asset.id == asset_id for asset in assets):
|
||||
raise HTTPException(404, "subject asset not found")
|
||||
|
||||
_delete_subject_asset_file(job_id, asset_id)
|
||||
new_frames = []
|
||||
for f in job.frames:
|
||||
if f.index == idx:
|
||||
for e in f.elements:
|
||||
if e.id == element_id:
|
||||
e.subject_assets = [asset for asset in (e.subject_assets or []) if asset.id != asset_id]
|
||||
new_frames.append(f)
|
||||
update(job, frames=new_frames, message=f"主体视图已删除 · {el.name_zh}")
|
||||
return job
|
||||
|
||||
|
||||
@app.delete("/jobs/{job_id}/frames/{idx}/elements/{element_id}/cutouts/{cutout_id}", response_model=Job)
|
||||
def delete_cutout(job_id: str, idx: int, element_id: str, cutout_id: str) -> Job:
|
||||
"""删除该元素的某张提取图"""
|
||||
|
||||
Reference in New Issue
Block a user