perf(8502): 并行生图(6并发)+超时重试;视频URL直连预览/下载;路径隔离

This commit is contained in:
Tony Zhang
2025-12-17 12:21:22 +08:00
parent ebcf165c3f
commit 1e210ffccf
12 changed files with 1168 additions and 201 deletions

View File

@@ -12,6 +12,7 @@ from pathlib import Path
import config
from modules import storage
from modules.db_manager import db
from modules import path_utils
logger = logging.getLogger(__name__)
@@ -76,15 +77,7 @@ class VideoGenerator:
logger.info(f"Recovering task {task_id}: status={status}")
if status == "succeeded" and video_url:
downloaded_path = self._download_video(video_url, os.path.basename(output_path))
if downloaded_path:
# 如果下载的文件名和目标路径不一致 (download_video 使用 filename 参数拼接到 TEMP_DIR)
# 需要移动或确认。 _download_video 返回完整路径。
# 如果 output_path 是绝对路径且不同,则移动。
if os.path.abspath(downloaded_path) != os.path.abspath(output_path):
import shutil
shutil.move(downloaded_path, output_path)
return True
return self._download_video_to(video_url, output_path)
return False
except Exception as e:
logger.error(f"Failed to recover video task {task_id}: {e}")
@@ -144,7 +137,15 @@ class VideoGenerator:
if status == "succeeded":
logger.info(f"Scene {scene_id} video generated successfully")
# 下载视频
video_path = self._download_video(result_url, f"scene_{scene_id}_video.mp4")
out_dir = path_utils.project_videos_dir(project_id) if project_id else config.TEMP_DIR
fname = path_utils.unique_filename(
prefix="scene_video",
ext="mp4",
project_id=project_id,
scene_id=scene_id,
extra=(task_id[-8:] if isinstance(task_id, str) else None),
)
video_path = self._download_video(result_url, fname, output_dir=out_dir)
if video_path:
generated_videos[scene_id] = video_path
# Update DB
@@ -235,13 +236,26 @@ class VideoGenerator:
content_url = None
if status == "succeeded":
if "content" in result:
content = result["content"]
if isinstance(content, list) and len(content) > 0:
item = content[0]
content_url = item.get("video_url") or item.get("url")
elif isinstance(content, dict):
content_url = content.get("video_url") or content.get("url")
# Try multiple known shapes for volcengine response
content = result.get("content")
# sometimes nested: data.content or data.result.content, etc.
if not content and isinstance(result.get("result"), dict):
content = result["result"].get("content")
def _extract_url(obj):
if isinstance(obj, dict):
return obj.get("video_url") or obj.get("url")
return None
if isinstance(content, list) and content:
# pick the first item that has a usable url
for item in content:
u = _extract_url(item)
if u:
content_url = u
break
elif isinstance(content, dict):
content_url = _extract_url(content)
return status, content_url
@@ -249,8 +263,26 @@ class VideoGenerator:
logger.error(f"Check task failed: {e}")
return "unknown", None
def _download_video(self, url: str, filename: str) -> str:
"""下载视频到临时目录"""
def _download_video_to(self, url: str, output_path: str) -> bool:
"""下载视频到指定路径(避免 TEMP_DIR 固定文件名导致覆盖)"""
if not url or not output_path:
return False
try:
out_p = Path(output_path)
out_p.parent.mkdir(parents=True, exist_ok=True)
response = requests.get(url, stream=True, timeout=60)
response.raise_for_status()
with open(out_p, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
return True
except Exception as e:
logger.error(f"Download video failed: {e}")
return False
def _download_video(self, url: str, filename: str, output_dir: Optional[Path] = None) -> str:
"""下载视频到临时目录(默认使用 config.TEMP_DIR可指定 output_dir 避免覆盖)"""
if not url:
return None
@@ -258,10 +290,13 @@ class VideoGenerator:
response = requests.get(url, stream=True, timeout=60)
response.raise_for_status()
output_path = config.TEMP_DIR / filename
out_dir = output_dir or config.TEMP_DIR
out_dir.mkdir(parents=True, exist_ok=True)
output_path = out_dir / filename
with open(output_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
if chunk:
f.write(chunk)
return str(output_path)
except Exception as e: