kritnatee's picture
download
raw
6.67 kB
"""
run-full-pipeline.py — End-to-End Video Pipeline
Script → Scene Planning → B-roll Generation → Video Assembly → Quality Check
Usage:
python run-full-pipeline.py --script script.txt --output final.mp4
python run-full-pipeline.py --script script.txt --gemini-key KEY --generate-images --output final.mp4
"""
import argparse, json, os, subprocess, sys, time, shutil
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PIPELINE_DIR = os.path.dirname(SCRIPT_DIR)
def run_scene_planner(script_path, images_dir, output_json, gemini_key=None):
"""Step 1: Plan scenes with transitions."""
print("\n" + "="*60)
print("STEP 1: Scene Planning")
print("="*60)
cmd = [sys.executable, os.path.join(SCRIPT_DIR, "scene-planner.py"),
script_path, "--images-dir", images_dir, "--output", output_json]
if gemini_key:
cmd.extend(["--gemini-key", gemini_key])
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
if result.returncode != 0:
print(f"ERROR: {result.stderr}")
return False
return True
def generate_broll_images(scenes_json, images_dir):
"""Step 2: Generate B-roll images via ComfyUI API."""
print("\n" + "="*60)
print("STEP 2: B-roll Image Generation")
print("="*60)
# Check if ComfyUI is available
try:
import urllib.request
req = urllib.request.Request("http://127.0.0.1:8188/system_stats")
urllib.request.urlopen(req, timeout=3)
print(" ComfyUI detected!")
except:
print(" ComfyUI not running - skipping image generation")
print(" Using existing images from", images_dir)
return True
# Generate images from scene prompts
cmd = [sys.executable, os.path.join(SCRIPT_DIR, "comfyui-client.py"),
"--prompt-file", scenes_json, "--output-dir", images_dir]
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
if result.returncode != 0:
print(f" Warning: {result.stderr[:200]}")
return True
def assemble_video(scenes_json, images_dir, output_path, fps=24, overlap=0.5):
"""Step 3: Assemble video with Ken Burns + transitions."""
print("\n" + "="*60)
print("STEP 3: Video Assembly")
print("="*60)
cmd = [sys.executable, os.path.join(SCRIPT_DIR, "make-video-v3.py"),
"--scenes", scenes_json, "--images-dir", images_dir,
"--output", output_path, "--fps", str(fps), "--overlap", str(overlap)]
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
if result.returncode != 0:
print(f"ERROR: {result.stderr[-500:]}")
return False
return True
def check_quality(video_path):
"""Step 4: Quality check."""
print("\n" + "="*60)
print("STEP 4: Quality Check")
print("="*60)
# File info
size_mb = os.path.getsize(video_path) / (1024*1024)
print(f" File: {video_path}")
print(f" Size: {size_mb:.1f} MB")
# ffprobe
try:
cmd = ["ffprobe", "-v", "error", "-show_entries",
"format=duration,bit_rate:stream=codec_name,width,height,r_frame_rate",
"-of", "json", video_path]
result = subprocess.run(cmd, capture_output=True, text=True)
info = json.loads(result.stdout)
fmt = info.get("format", {})
streams = info.get("streams", [{}])
video_stream = next((s for s in streams if s.get("codec_name") == "h264"), streams[0] if streams else {})
duration = float(fmt.get("duration", 0))
bitrate = int(fmt.get("bit_rate", 0))
width = video_stream.get("width", 0)
height = video_stream.get("height", 0)
fps = video_stream.get("r_frame_rate", "0/1")
print(f" Duration: {duration:.1f}s")
print(f" Resolution: {width}x{height}")
print(f" Bitrate: {bitrate/1000:.0f} kbps")
print(f" FPS: {fps}")
# Quality score
score = 0
if width >= 1920: score += 2
elif width >= 1280: score += 1
if bitrate > 5000000: score += 2
elif bitrate > 2000000: score += 1
if duration > 10: score += 1
score += 2 # Base score for having transitions
print(f"\n Quality Score: {score}/7")
if score >= 5:
print(" Rating: GOOD")
elif score >= 3:
print(" Rating: ACCEPTABLE")
else:
print(" Rating: NEEDS IMPROVEMENT")
return {"duration": duration, "bitrate": bitrate, "width": width, "height": height, "score": score}
except Exception as e:
print(f" Quality check failed: {e}")
return None
def main():
parser = argparse.ArgumentParser(description="End-to-End Video Pipeline")
parser.add_argument("--script", required=True, help="Script file (.txt)")
parser.add_argument("--images-dir", default=os.path.join(PIPELINE_DIR, "images"), help="Images directory")
parser.add_argument("--output", default=os.path.join(PIPELINE_DIR, "video", "final.mp4"), help="Output video")
parser.add_argument("--gemini-key", help="Gemini API key (optional)")
parser.add_argument("--generate-images", action="store_true", help="Generate B-roll via ComfyUI")
parser.add_argument("--fps", type=int, default=24)
parser.add_argument("--overlap", type=float, default=0.5)
parser.add_argument("--skip-planning", action="store_true", help="Skip scene planning (use existing scenes.json)")
args = parser.parse_args()
start_time = time.time()
scenes_json = os.path.join(PIPELINE_DIR, "scripts", "scenes.json")
print("\n" + "#"*60)
print("# VIDEO PIPELINE — START")
print("#"*60)
print(f" Script: {args.script}")
print(f" Images: {args.images_dir}")
print(f" Output: {args.output}")
# Step 1: Scene planning
if not args.skip_planning:
if not run_scene_planner(args.script, args.images_dir, scenes_json, args.gemini_key):
sys.exit(1)
# Step 2: Generate images (optional)
if args.generate_images:
generate_broll_images(scenes_json, args.images_dir)
# Step 3: Assemble video
if not assemble_video(scenes_json, args.images_dir, args.output, args.fps, args.overlap):
sys.exit(1)
# Step 4: Quality check
quality = check_quality(args.output)
# Summary
elapsed = time.time() - start_time
print("\n" + "#"*60)
print("# PIPELINE COMPLETE")
print("#"*60)
print(f" Output: {args.output}")
print(f" Time: {elapsed:.0f}s")
if quality:
print(f" Score: {quality['score']}/7")
print()
if __name__ == "__main__":
main()

Xet Storage Details

Size:
6.67 kB
·
Xet hash:
a6f07dc3854d297475f2a7149c7d28a29d5d2eaf9926c760e45be103210a1fdb

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.