auto-save 2026-05-13 20:40 (~4)

This commit is contained in:
2026-05-13 20:40:23 +08:00
parent bbe98641f1
commit 66f2495296
4 changed files with 60 additions and 10 deletions

View File

@@ -36,6 +36,11 @@ VIDEO_MODEL_ALIASES = {
"kling": os.getenv("VIDEO_MODEL_KLING", "kling").strip() or "kling",
"veo3": os.getenv("VIDEO_MODEL_VEO3", "veo3").strip() or "veo3",
}
VIDEO_API_BASE_URL = os.getenv("VIDEO_API_BASE_URL", "").strip()
VIDEO_API_KEY = os.getenv("VIDEO_API_KEY", "").strip()
VIDEO_CREATE_PATH = os.getenv("VIDEO_CREATE_PATH", "/videos").strip() or "/videos"
VIDEO_STATUS_PATH = os.getenv("VIDEO_STATUS_PATH", "/videos/{id}").strip() or "/videos/{id}"
VIDEO_CONTENT_PATH = os.getenv("VIDEO_CONTENT_PATH", "/videos/{id}/content").strip() or "/videos/{id}/content"
VIDEO_DURATION_FIELD = os.getenv("VIDEO_DURATION_FIELD", "seconds").strip() or "seconds"
# OpenAI 客户端OpenAI 兼容网关,含 SKG ezlink
@@ -191,6 +196,32 @@ def public_api_base() -> str:
return (LLM_BASE_URL or "https://api.openai.com/v1").rstrip("/")
def video_api_base() -> str:
return (VIDEO_API_BASE_URL or LLM_BASE_URL or "https://api.openai.com/v1").rstrip("/")
def video_api_key() -> str:
return VIDEO_API_KEY or LLM_API_KEY
def video_path(template: str, **values: str) -> str:
path = template.format(**values)
return path if path.startswith("/") else f"/{path}"
def ensure_video_api_configured() -> None:
base = video_api_base()
# 已探测SKG ezlink 当前只开了 chat/images/videos 返回 404。
# 没有显式 VIDEO_API_BASE_URL 时,不再把这个 404 伪装成一次“生成失败”。
if not VIDEO_API_BASE_URL and "ai.skg.com/ezlink" in base:
raise HTTPException(
503,
"当前 SKG ezlink 网关未开通生视频 /videos 端点;请配置 VIDEO_API_BASE_URL/VIDEO_API_KEY 接 Seedance、Kling 或 Veo 3 的真实视频 API 后再生成。",
)
if not video_api_key():
raise HTTPException(503, "VIDEO_API_KEY 或 LLM_API_KEY 未配置,无法调用生视频 API")
def storyboard_ref_path(job_id: str, ref: dict | None) -> Path | None:
if not ref:
return None
@@ -758,6 +789,8 @@ def health() -> dict:
"rewrite": REWRITE_MODEL,
"video": VIDEO_MODEL,
"video_aliases": VIDEO_MODEL_ALIASES,
"video_base_url": video_api_base() if VIDEO_API_BASE_URL else "",
"video_configured": bool(VIDEO_API_BASE_URL and video_api_key()),
},
}
@@ -1641,7 +1674,7 @@ def download_generated_video(client, base: str, headers: dict, provider_id: str,
url = direct_url if direct_url.startswith("http") else f"{base}{direct_url if direct_url.startswith('/') else '/' + direct_url}"
r = client.get(url, headers=headers if url.startswith(base) else None)
else:
r = client.get(f"{base}/videos/{provider_id}/content", headers=headers)
r = client.get(f"{base}{video_path(VIDEO_CONTENT_PATH, id=provider_id)}", headers=headers)
r.raise_for_status()
out_mp4.write_bytes(r.content)
@@ -1652,8 +1685,8 @@ def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_pa
out_dir = job_dir(job_id) / "storyboard_videos" / local_id
ref_img = out_dir / "reference.jpg"
out_mp4 = out_dir / "video.mp4"
base = public_api_base()
headers = {"Authorization": f"Bearer {LLM_API_KEY}"}
base = video_api_base()
headers = {"Authorization": f"Bearer {video_api_key()}"}
try:
prepare_video_reference(ref_path, ref_img)
@@ -1663,7 +1696,7 @@ def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_pa
payload[VIDEO_DURATION_FIELD] = seconds
with ref_img.open("rb") as fh:
create = client.post(
f"{base}/videos",
f"{base}{video_path(VIDEO_CREATE_PATH)}",
headers=headers,
data=payload,
files={"input_reference": ("reference.jpg", fh, "image/jpeg")},
@@ -1679,7 +1712,7 @@ def render_storyboard_video(job_id: str, local_id: str, provider_id: str, ref_pa
deadline = time.time() + 420
while status in {"queued", "in_progress"} and time.time() < deadline:
time.sleep(8)
poll = client.get(f"{base}/videos/{video_api_id}", headers=headers)
poll = client.get(f"{base}{video_path(VIDEO_STATUS_PATH, id=video_api_id)}", headers=headers)
poll.raise_for_status()
pdata = poll.json()
status = normalize_video_status(pdata.get("status"))
@@ -1712,8 +1745,7 @@ def generate_storyboard_video(job_id: str, idx: int, req: GenerateStoryboardVide
frame = next((f for f in job.frames if f.index == idx), None)
if not frame:
raise HTTPException(404, "frame not found")
if not LLM_API_KEY:
raise HTTPException(500, "LLM_API_KEY 未配置,无法调用视频生成 API")
ensure_video_api_configured()
prompt = req.prompt.strip()
if not prompt:
raise HTTPException(400, "prompt required")