fix: repair video ai production cli toolchain
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled

This commit is contained in:
冰朔 2026-06-24 23:10:29 +08:00
parent a77bc6b884
commit 8c33ca43d6
3 changed files with 56 additions and 15 deletions

View File

@ -32,6 +32,26 @@ import time
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT / "engines"))
DEFAULT_PYTHON = "/Users/bingshuolingdianyuanhe/.workbuddy/binaries/python/envs/default/bin/python3"
def resolve_python_bin():
"""Pick the Python that has the video AI dependencies installed."""
candidates = [
os.environ.get("PYTHON_BIN"),
os.environ.get("PYTHON"),
DEFAULT_PYTHON,
sys.executable,
"python3",
]
for candidate in candidates:
if not candidate:
continue
candidate_path = Path(candidate)
if candidate_path.is_absolute() and not candidate_path.exists():
continue
return str(candidate)
return sys.executable
class EP01Shot03ProductionCLI:
@ -47,6 +67,7 @@ class EP01Shot03ProductionCLI:
self.config_dir = PROJECT_ROOT / "plans" / "script-to-screen"
self.output_dir = PROJECT_ROOT / "outputs" / "ep01" / "shot03"
self.assets_dir = PROJECT_ROOT / "assets"
self.python_bin = resolve_python_bin()
# 确保输出目录存在
self.output_dir.mkdir(parents=True, exist_ok=True)
@ -70,6 +91,7 @@ class EP01Shot03ProductionCLI:
print(f" 镜头: {self.shot_id}")
print(f" 输出: {self.output_dir}")
print(f" Dry Run: {self.dry_run}")
print(f" Python: {self.python_bin}")
def _load_config(self):
"""加载 E1-SHOT03 配置,从剧本原文+分镜文件读取真实台词"""
@ -241,7 +263,7 @@ class EP01Shot03ProductionCLI:
print(f" 📤 生成资产包...")
result = subprocess.run(
[
"python", str(PROJECT_ROOT / "engines" / "char-hero-design-packer" / "char-hero-design-packer.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "char-hero-design-packer" / "char-hero-design-packer.py"),
"--character", self.config["character"],
"--generate-all"
],
@ -287,7 +309,7 @@ class EP01Shot03ProductionCLI:
if len(reference_images) >= 2:
# 多参考图模式
cmd = [
"python", str(PROJECT_ROOT / "engines" / "multi-reference-video-adapter" / "multi-reference-video-adapter.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "multi-reference-video-adapter.py"),
"--prompt", self.config["prompt"],
"--references"] + reference_images + [
"--output", str(output_path),
@ -333,7 +355,7 @@ class EP01Shot03ProductionCLI:
output_with_plaque = self.output_dir / "video_with_plaque.mp4"
# TODO: 实际调用 planar-tracker.py
# cmd = ["python", str(PROJECT_ROOT / "engines" / "planar-tracker.py"), ...]
# cmd = [self.python_bin, str(PROJECT_ROOT / "engines" / "planar-tracker.py"), ...]
return {
"output_path": str(output_with_plaque),
@ -349,7 +371,7 @@ class EP01Shot03ProductionCLI:
output_path = self.output_dir / "dialogue.mp3"
cmd = [
"python", str(PROJECT_ROOT / "engines" / "voice-emotion-compiler" / "voice-emotion-compiler.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "voice-emotion-compiler.py"),
"--text", self.config["dialogue"],
"--emotion", self.config["emotion"],
"--output", str(output_path)
@ -383,7 +405,7 @@ class EP01Shot03ProductionCLI:
output_path = self.output_dir / "video_synced.mp4"
cmd = [
"python", str(PROJECT_ROOT / "engines" / "lipsync-adapter" / "lipsync-adapter.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "lipsync-adapter.py"),
"--video", str(video_path),
"--audio", str(audio_path),
"--output", str(output_path)
@ -417,12 +439,14 @@ class EP01Shot03ProductionCLI:
raise Exception(f"视频不存在: {video_path}")
output_path = self.output_dir / "video_with_subtitles.mp4"
srt_path = self.output_dir / "dialogue.srt"
self._write_single_line_srt(srt_path, self.config["dialogue"], float(self.config.get("duration", 3)))
# 调用 subtitle-renderer.py
cmd = [
"python", str(PROJECT_ROOT / "engines" / "subtitle-renderer.py"),
"--input", str(video_path),
"--text", self.config["dialogue"],
self.python_bin, str(PROJECT_ROOT / "engines" / "subtitle-renderer.py"),
"--srt", str(srt_path),
"--video", str(video_path),
"--output", str(output_path)
]
@ -467,7 +491,7 @@ class EP01Shot03ProductionCLI:
# 混音
print(f" 混音...")
cmd = [
"python", str(PROJECT_ROOT / "engines" / "audio-mixer" / "audio-mixer.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "audio-mixer.py"),
"--dialogue", str(dialogue_path),
"--output", str(self.output_dir / "mixed_audio.mp3")
]
@ -502,7 +526,7 @@ class EP01Shot03ProductionCLI:
return {"skipped": True, "reason": "no video found"}
cmd = [
"python", str(PROJECT_ROOT / "engines" / "shot-qc-automation" / "shot-qc-automation.py"),
self.python_bin, str(PROJECT_ROOT / "engines" / "shot-qc-automation.py"),
"--video", str(video_path),
"--character", self.config["character"],
"--output", str(self.output_dir / "qc_report.json")
@ -582,6 +606,21 @@ class EP01Shot03ProductionCLI:
return True
def _write_single_line_srt(self, srt_path, text, duration):
"""Write a one-line SRT from the locked source dialogue."""
duration_ms = max(500, int(duration * 1000))
end_seconds = duration_ms // 1000
end_ms = duration_ms % 1000
srt_path.parent.mkdir(parents=True, exist_ok=True)
content = (
"1\n"
f"00:00:00,000 --> 00:00:{end_seconds:02d},{end_ms:03d}\n"
f"{text}\n"
)
with open(srt_path, "w", encoding="utf-8") as f:
f.write(content)
return srt_path
def main():
parser = argparse.ArgumentParser(description="EP01-SHOT03-PRODUCTION-CLI")

View File

@ -34,10 +34,13 @@ def load_api_config():
"""从仓库 .env、本机密钥文件和环境变量加载配置"""
config = {}
env_files = [
Path(os.environ["VIDEO_AI_SECRETS_FILE"]) if os.environ.get("VIDEO_AI_SECRETS_FILE") else None,
Path("/Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env"),
PROJECT_ROOT / ".env",
Path.home() / "guanghulab-local-secrets" / "video-ai-system.env",
]
for env_file in env_files:
if env_file is None:
continue
if not env_file.exists():
continue
with open(env_file, "r", encoding="utf-8") as f:

View File

@ -5,7 +5,7 @@ Subtitle Renderer · 字幕渲染引擎
SRT 字幕文件渲染为 PNG 序列再通过 FFmpeg 合成到视频中
依赖
pip install cairosvg Pillow pysrt
pip install Pillow pysrt
用法
# 基本用法SRT → PNG 序列)
@ -50,11 +50,10 @@ except ImportError:
sys.exit(1)
try:
import cairosvg
from PIL import Image, ImageDraw, ImageFont
except ImportError:
print("[ERROR] 缺少依赖:cairosvg Pillow")
print("请先安装pip install cairosvg Pillow")
print("[ERROR] 缺少依赖:Pillow")
print("请先安装pip install Pillow")
sys.exit(1)