Instructions to use deathlegionteam/LEGION-Video-Gen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use deathlegionteam/LEGION-Video-Gen with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("deathlegionteam/LEGION-Video-Gen", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
| import os | |
| import sys | |
| import json | |
| import time | |
| import logging | |
| import tempfile | |
| from pathlib import Path | |
| from typing import Optional | |
| from datetime import datetime | |
| import requests | |
| import gradio as gr | |
| from PIL import Image, ImageDraw, ImageFont | |
| import numpy as np | |
| # Backend API URL | |
| BACKEND_URL = os.environ.get("BACKEND_URL", "http://localhost:8081") | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s') | |
| logger = logging.getLogger("LegionFrontend") | |
| # --- Dark Theme CSS --- | |
| LEGION_CSS = """ | |
| :root { | |
| --primary: #ff6b35; | |
| --primary-dark: #e55a2b; | |
| --bg-dark: #0a0a0f; | |
| --bg-card: #14141f; | |
| --bg-input: #1a1a2e; | |
| --text-primary: #e0e0e0; | |
| --text-secondary: #8888aa; | |
| --border-color: #2a2a3e; | |
| --accent: #00d4aa; | |
| } | |
| body { | |
| background-color: var(--bg-dark) !important; | |
| color: var(--text-primary) !important; | |
| } | |
| .gradio-container { | |
| background-color: var(--bg-dark) !important; | |
| max-width: 1200px !important; | |
| margin: 0 auto !important; | |
| padding: 20px !important; | |
| } | |
| h1, h2, h3 { | |
| font-family: 'Courier New', monospace !important; | |
| text-transform: uppercase !important; | |
| letter-spacing: 2px !important; | |
| } | |
| h1 { | |
| color: var(--primary) !important; | |
| text-align: center !important; | |
| font-size: 2.5em !important; | |
| text-shadow: 0 0 20px rgba(255, 107, 53, 0.3) !important; | |
| border-bottom: 2px solid var(--border-color) !important; | |
| padding-bottom: 15px !important; | |
| margin-bottom: 25px !important; | |
| } | |
| .tabs { | |
| background: var(--bg-card) !important; | |
| border: 1px solid var(--border-color) !important; | |
| border-radius: 12px !important; | |
| padding: 15px !important; | |
| } | |
| button { | |
| background: linear-gradient(135deg, var(--primary), var(--primary-dark)) !important; | |
| border: none !important; | |
| color: white !important; | |
| font-weight: bold !important; | |
| letter-spacing: 1px !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| button:hover { | |
| transform: translateY(-2px) !important; | |
| box-shadow: 0 5px 20px rgba(255, 107, 53, 0.4) !important; | |
| } | |
| input, textarea, select, .dropdown { | |
| background: var(--bg-input) !important; | |
| border-radius: 8px !important; | |
| } | |
| .slider input[type="range"] { | |
| accent-color: var(--primary) !important; | |
| } | |
| .video-container { | |
| overflow: hidden !important; | |
| } | |
| .status-badge { | |
| background: var(--accent) !important; | |
| color: black !important; | |
| padding: 4px 12px !important; | |
| border-radius: 20px !important; | |
| font-size: 0.8em !important; | |
| } | |
| .footer { | |
| color: var(--text-secondary) !important; | |
| border-top: 1px solid var(--border-color) !important; | |
| margin-top: 30px !important; | |
| } | |
| """ | |
| # ============================================================ | |
| # API Helper Functions | |
| # ============================================================ | |
| def call_api_status() -> dict: | |
| try: | |
| resp = requests.get(f"{BACKEND_URL}/api/status", timeout=5) | |
| return resp.json() | |
| except Exception as e: | |
| return {"status": "error", "detail": str(e)} | |
| def call_api_models() -> list: | |
| try: | |
| resp = requests.get(f"{BACKEND_URL}/api/models", timeout=5) | |
| data = resp.json() | |
| return data.get("models", []) | |
| except Exception as e: | |
| return [{"name": f"Error: {e}", "type": "error"}] | |
| # ============================================================ | |
| # Generation Functions | |
| # ============================================================ | |
| def generate_text_video( | |
| prompt: str, | |
| negative_prompt: str, | |
| num_frames: int, | |
| width: int, | |
| height: int, | |
| inference_steps: int, | |
| guidance_scale: float, | |
| watermark_strength: float, | |
| progress=gr.Progress(), | |
| ) -> Optional[str]: | |
| try: | |
| progress(0, desc="Connecting to API...") | |
| payload = { | |
| "prompt": prompt, | |
| "negative_prompt": negative_prompt, | |
| "num_frames": num_frames, | |
| "width": width, | |
| "height": height, | |
| "num_inference_steps": inference_steps, | |
| "guidance_scale": guidance_scale, | |
| "watermark_strength": watermark_strength, | |
| } | |
| progress(0.2, desc="Generating video...") | |
| resp = requests.post( | |
| f"{BACKEND_URL}/api/generate/text", | |
| json=payload, | |
| timeout=600, | |
| ) | |
| if resp.status_code != 200: | |
| return f"Error: {resp.text}" | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| output_path = f"/tmp/legion_t2v_{timestamp}.mp4" | |
| with open(output_path, "wb") as f: | |
| f.write(resp.content) | |
| progress(1.0, desc="Done!") | |
| return output_path | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| def generate_image_video( | |
| image_file, | |
| prompt: str, | |
| negative_prompt: str, | |
| num_frames: int, | |
| width: int, | |
| height: int, | |
| inference_steps: int, | |
| guidance_scale: float, | |
| watermark_strength: float, | |
| progress=gr.Progress(), | |
| ) -> Optional[str]: | |
| try: | |
| if image_file is None: | |
| return "Error: No image uploaded" | |
| progress(0.2, desc="Uploading image and generating...") | |
| with open(image_file, "rb") as f: | |
| files = {"file": f} | |
| data = { | |
| "prompt": prompt, | |
| "negative_prompt": negative_prompt, | |
| "num_frames": str(num_frames), | |
| "width": str(width), | |
| "height": str(height), | |
| "num_inference_steps": str(inference_steps), | |
| "guidance_scale": str(guidance_scale), | |
| "watermark_strength": str(watermark_strength), | |
| } | |
| resp = requests.post( | |
| f"{BACKEND_URL}/api/generate/image", | |
| files=files, | |
| data=data, | |
| timeout=600, | |
| ) | |
| if resp.status_code != 200: | |
| return f"Error: {resp.text}" | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| output_path = f"/tmp/legion_i2v_{timestamp}.mp4" | |
| with open(output_path, "wb") as f: | |
| f.write(resp.content) | |
| progress(1.0, desc="Done!") | |
| return output_path | |
| except Exception as e: | |
| return f"Error: {str(e)}" | |
| def preview_watermark(text: str, position: str, font_size: int, opacity: float) -> Optional[str]: | |
| try: | |
| frame = Image.new("RGB", (480, 480), (20, 20, 35)) | |
| draw = ImageDraw.Draw(frame) | |
| for i in range(0, 480, 20): | |
| draw.line([(i, 0), (i, 480)], fill=(30, 30, 50), width=1) | |
| draw.line([(0, i), (480, i)], fill=(30, 30, 50), width=1) | |
| try: | |
| font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size) | |
| except: | |
| font = ImageFont.load_default() | |
| w, h = frame.size | |
| bbox = draw.textbbox((0, 0), text, font=font) | |
| text_w = bbox[2] - bbox[0] | |
| text_h = bbox[3] - bbox[1] | |
| margin = 15 | |
| pos_map = { | |
| "top-left": (margin, margin), | |
| "top-right": (w - text_w - margin, margin), | |
| "bottom-left": (margin, h - text_h - margin), | |
| "center": ((w - text_w) // 2, (h - text_h) // 2), | |
| "bottom-right": (w - text_w - margin, h - text_h - margin), | |
| } | |
| x, y = pos_map.get(position, pos_map["bottom-right"]) | |
| draw.rectangle( | |
| [x - 10, y - 10, x + text_w + 10, y + text_h + 10], | |
| fill=(0, 0, 0, int(40 * opacity)) | |
| ) | |
| draw.text((x, y), text, font=font, fill=(255, 255, 255, int(255 * opacity))) | |
| preview_path = "/tmp/qwatermark_preview.png" | |
| frame.save(preview_path) | |
| return preview_path | |
| except Exception as e: | |
| return None | |
| # ============================================================ | |
| # BUILD GRADIO INTERFACE | |
| # ============================================================ | |
| with gr.Blocks( | |
| css=LEGION_CSS, | |
| title="LEGION VIDEO GENERATION", | |
| theme=gr.themes.Soft( | |
| primary_hue="orange", | |
| secondary_hue="blue", | |
| neutral_hue="slate", | |
| ), | |
| ) as app: | |
| # Header | |
| gr.HTML(""" | |
| <div style="text-align: center; margin-bottom: 10px;"> | |
| <h1 style="font-size: 2.8em; margin-bottom: 0;"> | |
| โ๏ธ LEGION VIDEO GENERATION | |
| </h1> | |
| <p style="color: #8888aa; font-size: 1.1em; margin-top: 5px;"> | |
| The Ultimate AI Video Engine โ Text-to-Video & Image-to-Video | |
| </p> | |
| <div style="display: flex; justify-content: center; gap: 20px; margin-top: 10px;"> | |
| <span class="status-badge">๐ฅ T2V + I2V</span> | |
| </div> | |
| </div> | |
| """) | |
| # Main tabs | |
| with gr.Tabs(elem_classes="tabs"): | |
| # ============ TAB 1: TEXT-TO-VIDEO ============ | |
| with gr.TabItem("๐ฌ Text-to-Video", id="tab_t2v"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| prompt_t2v = gr.Textbox( | |
| label="๐ Prompt", | |
| placeholder="Describe the video you want to generate...", | |
| lines=4, | |
| value="A serene mountain lake at sunset with colorful clouds reflecting on the water, gentle ripples, cinematic quality", | |
| ) | |
| neg_prompt_t2v = gr.Textbox( | |
| label="๐ซ Negative Prompt", | |
| lines=2, | |
| value="warped, distorted, flickering, jittery, low quality, blurry, artifacts, ugly, deformed, bad anatomy, bad proportions", | |
| ) | |
| num_frames_t2v = gr.Slider( | |
| label="Frames", minimum=1, maximum=129, value=49, step=1 | |
| ) | |
| steps_t2v = gr.Slider( | |
| label="Inference Steps", minimum=10, maximum=100, value=50, step=1 | |
| ) | |
| guidance_t2v = gr.Slider( | |
| label="Guidance Scale", minimum=1.0, maximum=20.0, value=6.0, step=0.5 | |
| ) | |
| wm_strength_t2v = gr.Slider( | |
| label="QWatermark Strength", minimum=0.0, maximum=1.0, value=0.3, step=0.05 | |
| ) | |
| width_t2v = gr.Dropdown( | |
| label="Width", choices=[256, 384, 480, 720], value=480 | |
| ) | |
| height_t2v = gr.Dropdown( | |
| label="Height", choices=[256, 384, 480, 720], value=480 | |
| ) | |
| gen_btn_t2v = gr.Button("๐ก๏ธ GENERATE VIDEO", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| output_t2v = gr.Video(label="Generated Video", show_label=True) | |
| status_t2v = gr.Textbox(label="Status", interactive=False) | |
| gen_btn_t2v.click( | |
| fn=generate_text_video, | |
| inputs=[ | |
| prompt_t2v, neg_prompt_t2v, num_frames_t2v, | |
| width_t2v, height_t2v, steps_t2v, | |
| guidance_t2v, wm_strength_t2v, | |
| ], | |
| outputs=[output_t2v], | |
| queue=True, | |
| ) | |
| # ============ TAB 2: IMAGE-TO-VIDEO ============ | |
| with gr.TabItem("๐ผ๏ธ Image-to-Video", id="tab_i2v"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| image_i2v = gr.Image( | |
| label="๐ท Input Image", | |
| type="filepath", | |
| height=300, | |
| ) | |
| prompt_i2v = gr.Textbox( | |
| label="๐ Prompt (motion description)", | |
| placeholder="Describe the motion or action...", | |
| lines=3, | |
| value="Gentle motion, cinematic camera movement, atmospheric", | |
| ) | |
| neg_prompt_i2v = gr.Textbox( | |
| label="๐ซ Negative Prompt", | |
| lines=2, | |
| value="warped, distorted, flickering, jittery, low quality, blurry, artifacts", | |
| ) | |
| num_frames_i2v = gr.Slider( | |
| label="Frames", minimum=1, maximum=129, value=49, step=1 | |
| ) | |
| steps_i2v = gr.Slider( | |
| label="Inference Steps", minimum=10, maximum=100, value=50, step=1 | |
| ) | |
| guidance_i2v = gr.Slider( | |
| label="Guidance Scale", minimum=1.0, maximum=20.0, value=6.0, step=0.5 | |
| ) | |
| wm_strength_i2v = gr.Slider( | |
| label="QWatermark Strength", minimum=0.0, maximum=1.0, value=0.3, step=0.05 | |
| ) | |
| width_i2v = gr.Dropdown( | |
| label="Width", choices=[256, 384, 480, 720], value=480 | |
| ) | |
| height_i2v = gr.Dropdown( | |
| label="Height", choices=[256, 384, 480, 720], value=480 | |
| ) | |
| gen_btn_i2v = gr.Button("๐ก๏ธ GENERATE VIDEO", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| output_i2v = gr.Video(label="Generated Video", show_label=True) | |
| status_i2v = gr.Textbox(label="Status", interactive=False) | |
| gen_btn_i2v.click( | |
| fn=generate_image_video, | |
| inputs=[ | |
| image_i2v, prompt_i2v, neg_prompt_i2v, num_frames_i2v, | |
| width_i2v, height_i2v, steps_i2v, | |
| guidance_i2v, wm_strength_i2v, | |
| ], | |
| outputs=[output_i2v], | |
| queue=True, | |
| ) | |
| # ============ TAB 3: QWATERMARK SETTINGS ============ | |
| with gr.TabItem("๐ง QWatermark Settings", id="tab_wm"): | |
| gr.Markdown(""" | |
| ## ๐ง QWatermark Quality Assurance System | |
| The QWatermark system imprints a semi-transparent quality assurance marker | |
| on every generated video. Configure the watermark appearance below. | |
| """) | |
| wm_text = gr.Textbox( | |
| label="Watermark Text", | |
| value="LEGION", | |
| placeholder="Enter watermark text", | |
| ) | |
| wm_position = gr.Dropdown( | |
| label="Position", | |
| choices=["top-left", "top-right", "bottom-left", "bottom-right", "center"], | |
| value="bottom-right", | |
| ) | |
| wm_font_size = gr.Slider( | |
| label="Font Size", minimum=16, maximum=72, value=36, step=2 | |
| ) | |
| wm_opacity = gr.Slider( | |
| label="Opacity", minimum=0.0, maximum=1.0, value=0.3, step=0.05 | |
| ) | |
| preview_btn = gr.Button("๐๏ธ PREVIEW WATERMARK", variant="secondary", size="lg") | |
| wm_preview = gr.Image( | |
| label="Watermark Preview", | |
| height=400, | |
| ) | |
| wm_info = gr.Markdown(""" | |
| **Current Configuration:** | |
| - Text: LEGION | |
| - Position: bottom-right | |
| - System: Semi-transparent overlay with dark background | |
| The QWatermark is applied to every frame during video export. | |
| Adjust strength in generation tabs (0.0 to disable). | |
| """) | |
| preview_btn.click( | |
| fn=preview_watermark, | |
| inputs=[wm_text, wm_position, wm_font_size, wm_opacity], | |
| outputs=[wm_preview], | |
| ) | |
| # Footer | |
| gr.HTML(""" | |
| <div class="footer"> | |
| <p> | |
| <strong>โ๏ธ LEGION VIDEO GENERATION</strong> โ v1.0 | Apache 2.0 License | |
| </p> | |
| <p style="font-size: 0.8em; margin-top: 5px;"> | |
| Text-to-Video | Image-to-Video | QWatermark System | |
| </p> | |
| </div> | |
| """) | |
| # ============================================================ | |
| # Launch | |
| # ============================================================ | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("FRONTEND_PORT", 8080)) | |
| logger.info(f"Starting LEGION Frontend on port {port}") | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=port, | |
| share=False, | |
| show_error=True, | |
| quiet=False, | |
| ) |