auto-save 2026-05-13 21:24 (~6)
This commit is contained in:
48
api/main.py
48
api/main.py
@@ -115,6 +115,11 @@ class GeneratedVideo(BaseModel):
|
||||
created_at: float = 0.0
|
||||
|
||||
|
||||
class VideoSourceRef(BaseModel):
|
||||
kind: Literal["image", "source_video"] = "image"
|
||||
url: str = ""
|
||||
|
||||
|
||||
class StoryboardScene(BaseModel):
|
||||
"""分镜头编排:每个 selected 分镜对应一个 scene 描述
|
||||
v2: 4 图槽 + 时长(复制粘贴模式)— 主体 / 场景 / 产品 / 动作 各一张图
|
||||
@@ -265,6 +270,9 @@ def storyboard_ref_path(job_id: str, ref: dict | None) -> Path | None:
|
||||
except Exception:
|
||||
return None
|
||||
if kind == "keyframe":
|
||||
clean = job_dir(job_id) / "cleaned" / f"{frame_idx:03d}.jpg"
|
||||
if clean.exists():
|
||||
return clean
|
||||
p = job_dir(job_id) / "frames" / f"{frame_idx:03d}.jpg"
|
||||
return p if p.exists() else None
|
||||
if kind == "cutout":
|
||||
@@ -1643,6 +1651,7 @@ class GenerateStoryboardVideoReq(BaseModel):
|
||||
scene_image: dict | None = None
|
||||
product_image: dict | None = None
|
||||
action_image: dict | None = None
|
||||
source_ref: VideoSourceRef | None = None
|
||||
model: str = ""
|
||||
size: str = "720x1280"
|
||||
|
||||
@@ -1749,18 +1758,27 @@ def ark_reference_data_url(ref_img: Path) -> str:
|
||||
return f"data:{mime};base64,{base64.b64encode(ref_img.read_bytes()).decode('ascii')}"
|
||||
|
||||
|
||||
def submit_video_create(client, url: str, headers: dict, ref_img: Path, payload: dict):
|
||||
def submit_video_create(client, url: str, headers: dict, ref_img: Path, payload: dict, source_ref: VideoSourceRef | None = None):
|
||||
if video_uses_ark():
|
||||
content = [{"type": "text", "text": payload["prompt"]}]
|
||||
if source_ref and source_ref.kind == "source_video" and source_ref.url:
|
||||
content.append(
|
||||
{
|
||||
"type": "video_url",
|
||||
"video_url": {"url": source_ref.url},
|
||||
"role": "reference_video",
|
||||
}
|
||||
)
|
||||
content.append(
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {"url": ark_reference_data_url(ref_img)},
|
||||
"role": "first_frame",
|
||||
}
|
||||
)
|
||||
data = {
|
||||
"model": payload["model"],
|
||||
"content": [
|
||||
{"type": "text", "text": payload["prompt"]},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {"url": ark_reference_data_url(ref_img)},
|
||||
"role": "first_frame",
|
||||
},
|
||||
],
|
||||
"content": content,
|
||||
"ratio": size_to_video_ratio(str(payload.get("size", ""))),
|
||||
"duration": int(float(str(payload.get(VIDEO_DURATION_FIELD, 5)))),
|
||||
"watermark": False,
|
||||
@@ -1783,7 +1801,7 @@ def submit_video_create(client, url: str, headers: dict, ref_img: Path, payload:
|
||||
)
|
||||
|
||||
|
||||
def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_path: Path, prompt: str, model: str, seconds: str, size: str) -> None:
|
||||
def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_path: Path, prompt: str, model: str, seconds: str, size: str, source_ref: VideoSourceRef | None = None) -> None:
|
||||
import httpx
|
||||
|
||||
out_dir = job_dir(job_id) / "storyboard_videos" / local_id
|
||||
@@ -1801,7 +1819,10 @@ def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_pa
|
||||
create = None
|
||||
create_errors: list[str] = []
|
||||
for create_path in VIDEO_CREATE_PATHS:
|
||||
resp = submit_video_create(client, f"{base}{video_path(create_path)}", headers, ref_img, payload)
|
||||
resp = submit_video_create(client, f"{base}{video_path(create_path)}", headers, ref_img, payload, source_ref)
|
||||
if video_uses_ark() and source_ref and resp.status_code in {400, 422}:
|
||||
create_errors.append(f"{video_path(create_path)} + reference_video -> HTTP {resp.status_code}: {resp.text[:160]}")
|
||||
resp = submit_video_create(client, f"{base}{video_path(create_path)}", headers, ref_img, payload, None)
|
||||
if resp.status_code < 400:
|
||||
create = resp
|
||||
break
|
||||
@@ -1881,7 +1902,10 @@ def generate_storyboard_video(job_id: str, idx: int, req: GenerateStoryboardVide
|
||||
created_at=time.time(),
|
||||
)
|
||||
update(job, generated_videos=[item] + job.generated_videos, message=f"视频生成已提交 · 分镜 {idx + 1}")
|
||||
bg.add_task(render_storyboard_video, job_id, local_id, "", ref_path, prompt, model, seconds, req.size)
|
||||
source_ref = req.source_ref
|
||||
if source_ref and source_ref.kind == "source_video" and not source_ref.url:
|
||||
source_ref = None
|
||||
bg.add_task(render_storyboard_video, job_id, local_id, "", ref_path, prompt, model, seconds, req.size, source_ref)
|
||||
return job
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user