Download server.py from red-kit/loop-gpt-video-long: direct link, hf CLI and curl.
- Browser
- Download file 5.84 kB
-
https://huggingface.co/red-kit/loop-gpt-video-long/resolve/main/server.py
- Command line
-
hf download hf://red-kit/loop-gpt-video-long/server.py
-
curl -L -o server.py https://huggingface.co/red-kit/loop-gpt-video-long/resolve/main/server.py
5.84 kB
| import os | |
| import sys | |
| import subprocess | |
| import base64 | |
| import tempfile | |
| import traceback | |
| # Install latest diffusers (supports SkyReelsV2DiffusionForcingPipeline) + dependencies | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "--upgrade", | |
| "diffusers", "flask", "accelerate", "sentencepiece", "protobuf", "imageio[ffmpeg]", | |
| "transformers", "huggingface_hub", "ftfy", "einops"]) | |
| import torch | |
| from flask import Flask, request, jsonify | |
| print(f"[video-long] torch version: {torch.__version__}", flush=True) | |
| print(f"[video-long] CUDA available: {torch.cuda.is_available()}", flush=True) | |
| if torch.cuda.is_available(): | |
| print(f"[video-long] GPU: {torch.cuda.get_device_name(0)}", flush=True) | |
| print(f"[video-long] VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB", flush=True) | |
| app = Flask(__name__) | |
| pipe = None | |
| def load_model(): | |
| global pipe | |
| from diffusers import ( | |
| AutoModel, | |
| SkyReelsV2DiffusionForcingPipeline, | |
| UniPCMultistepScheduler, | |
| ) | |
| print("[video-long] Loading SkyReels-V2-DF-1.3B-540P...", flush=True) | |
| model_id = "Skywork/SkyReels-V2-DF-1.3B-540P-Diffusers" | |
| vae = AutoModel.from_pretrained( | |
| model_id, | |
| subfolder="vae", | |
| torch_dtype=torch.float32, | |
| ) | |
| pipe = SkyReelsV2DiffusionForcingPipeline.from_pretrained( | |
| model_id, | |
| vae=vae, | |
| torch_dtype=torch.bfloat16, | |
| ) | |
| # Flow shift 8.0 for T2V | |
| pipe.scheduler = UniPCMultistepScheduler.from_config( | |
| pipe.scheduler.config, flow_shift=8.0 | |
| ) | |
| pipe.to("cuda") | |
| print("[video-long] Model loaded on CUDA!", flush=True) | |
| def health(): | |
| if pipe is not None: | |
| return jsonify({"status": "healthy"}), 200 | |
| return jsonify({"status": "loading"}), 503 | |
| def debug(): | |
| if pipe is None: | |
| return jsonify({"status": "loading"}), 503 | |
| import inspect | |
| sig = inspect.signature(pipe.__call__) | |
| params = {} | |
| for name, param in sig.parameters.items(): | |
| params[name] = str(param.default) if param.default != inspect.Parameter.empty else "required" | |
| return jsonify({ | |
| "pipeline_class": type(pipe).__name__, | |
| "parameters": params, | |
| "device": str(pipe.device) if hasattr(pipe, 'device') else 'unknown', | |
| }) | |
| def generate(): | |
| try: | |
| from diffusers.utils import export_to_video | |
| data = request.get_json(force=True) | |
| # Support both HF format (inputs) and backend format (prompt) | |
| prompt = data.get("inputs", "") or data.get("prompt", "") | |
| params = data.get("parameters", {}) | |
| # Diffusion Forcing params - defaults for ~10s video | |
| num_frames = int(params.get("num_frames", 257)) # 257=10s, 737=30s, 1457=60s | |
| height = int(params.get("height", 544)) # 544 for 540P | |
| width = int(params.get("width", 960)) # 960 for 540P | |
| steps = int(params.get("num_inference_steps", 30)) | |
| fps = int(params.get("fps", 24)) | |
| base_num_frames = int(params.get("base_num_frames", 97)) | |
| ar_step = int(params.get("ar_step", 5)) # 5 for async (better quality, faster for long) | |
| causal_block_size = int(params.get("causal_block_size", 5)) | |
| overlap_history = int(params.get("overlap_history", 17)) | |
| addnoise_condition = int(params.get("addnoise_condition", 20)) | |
| guidance_scale = float(params.get("guidance_scale", 5.0)) | |
| print(f"[video-long] Generating {num_frames} frames ({num_frames/fps:.1f}s): {prompt[:100]}", flush=True) | |
| print(f"[video-long] Params: {width}x{height}, steps={steps}, ar_step={ar_step}", flush=True) | |
| # Build kwargs - only pass causal_block_size when ar_step > 0 | |
| call_kwargs = dict( | |
| prompt=prompt, | |
| num_inference_steps=steps, | |
| height=height, | |
| width=width, | |
| num_frames=num_frames, | |
| base_num_frames=base_num_frames, | |
| ar_step=ar_step, | |
| overlap_history=overlap_history, | |
| addnoise_condition=addnoise_condition, | |
| ) | |
| if ar_step > 0: | |
| call_kwargs["causal_block_size"] = causal_block_size | |
| print(f"[video-long] Pipeline call kwargs: {call_kwargs}", flush=True) | |
| output = pipe(**call_kwargs).frames[0] | |
| # Write to temp file | |
| with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp: | |
| tmp_path = tmp.name | |
| export_to_video(output, tmp_path, fps=fps) | |
| with open(tmp_path, "rb") as f: | |
| video_bytes = f.read() | |
| os.unlink(tmp_path) | |
| video_b64 = base64.b64encode(video_bytes).decode("utf-8") | |
| duration = len(output) / fps | |
| print(f"[video-long] Done: {len(output)} frames, {duration:.1f}s, {len(video_bytes)} bytes", flush=True) | |
| return jsonify({ | |
| "video": video_b64, | |
| "format": "mp4", | |
| "frames": len(output), | |
| "duration": duration, | |
| "success": True, | |
| "video_base64": video_b64, | |
| "duration_seconds": duration, | |
| "model": "skyreels-v2-df-1.3b", | |
| }) | |
| except Exception as e: | |
| tb = traceback.format_exc() | |
| print(f"[video-long] ERROR: {e}", flush=True) | |
| print(f"[video-long] TRACEBACK:\n{tb}", flush=True) | |
| return jsonify({"error": str(e), "traceback": tb, "success": False}), 200 | |
| # Also add /api/generate-video route for backend compatibility | |
| def api_generate_video(): | |
| """Handle the backend's /api/generate-video format by forwarding to generate()""" | |
| return generate() | |
| if __name__ == "__main__": | |
| load_model() | |
| app.run(host="0.0.0.0", port=8000) | |