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 time | |
| import json | |
| import tempfile | |
| from pathlib import Path | |
| from datetime import datetime | |
| from typing import Optional | |
| import streamlit as st | |
| import requests | |
| from PIL import Image, ImageDraw, ImageFont | |
| import numpy as np | |
| # Add project root to path | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| # Backend API URL | |
| BACKEND_URL = os.environ.get("BACKEND_URL", "http://localhost:8081") | |
| # Page config | |
| st.set_page_config( | |
| page_title="LEGION Video Generation", | |
| page_icon="⚔️", | |
| layout="wide", | |
| initial_sidebar_state="expanded", | |
| ) | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| /* Main container */ | |
| .main > div { | |
| padding: 1rem 2rem; | |
| } | |
| /* Headers */ | |
| h1 { | |
| font-family: 'Courier New', monospace; | |
| text-transform: uppercase; | |
| letter-spacing: 3px; | |
| color: #ff6b35; | |
| border-bottom: 2px solid #2a2a3e; | |
| padding-bottom: 12px; | |
| } | |
| h2 { | |
| font-family: 'Courier New', monospace; | |
| text-transform: uppercase; | |
| letter-spacing: 2px; | |
| color: #e0e0e0; | |
| } | |
| h3 { | |
| font-family: 'Courier New', monospace; | |
| color: #ff6b35; | |
| } | |
| /* Cards */ | |
| .card { | |
| background: #14141f; | |
| border: 1px solid #2a2a3e; | |
| border-radius: 12px; | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| } | |
| /* Buttons */ | |
| .stButton > button { | |
| background: linear-gradient(135deg, #ff6b35, #e55a2b) !important; | |
| border: none !important; | |
| color: white !important; | |
| font-weight: bold !important; | |
| letter-spacing: 1px !important; | |
| width: 100%; | |
| border-radius: 8px !important; | |
| padding: 12px 24px !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| .stButton > button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 20px rgba(255, 107, 53, 0.4); | |
| } | |
| /* Input fields */ | |
| .stTextInput > div > div > input, | |
| .stTextArea > div > div > textarea { | |
| background: #1a1a2e !important; | |
| border: 1px solid #2a2a3e !important; | |
| border-radius: 8px !important; | |
| color: #e0e0e0 !important; | |
| } | |
| /* Sliders */ | |
| .stSlider > div > div > div > div { | |
| background: #ff6b35 !important; | |
| } | |
| /* Status */ | |
| .status-badge { | |
| background: #00d4aa; | |
| color: black; | |
| padding: 4px 12px; | |
| border-radius: 20px; | |
| font-size: 0.8em; | |
| display: inline-block; | |
| } | |
| /* Footer */ | |
| .footer { | |
| color: #8888aa; | |
| border-top: 1px solid #2a2a3e; | |
| margin-top: 40px; | |
| padding-top: 15px; | |
| text-align: center; | |
| } | |
| /* Video container */ | |
| .stVideo { | |
| border-radius: 12px; | |
| overflow: hidden; | |
| } | |
| /* Tabs */ | |
| .stTabs [data-baseweb="tab-list"] { | |
| background: #14141f; | |
| border-radius: 12px 12px 0 0; | |
| border: 1px solid #2a2a3e; | |
| } | |
| .stTabs [data-baseweb="tab"] { | |
| color: #e0e0e0; | |
| font-family: 'Courier New', monospace; | |
| letter-spacing: 1px; | |
| } | |
| .stTabs [aria-selected="true"] { | |
| background: #ff6b35 !important; | |
| color: white !important; | |
| } | |
| /* Sidebar */ | |
| .css-1d391kg { | |
| background: #0a0a0f; | |
| } | |
| /* Info boxes */ | |
| .stAlert { | |
| background: #1a1a2e !important; | |
| border: 1px solid #2a2a3e !important; | |
| } | |
| /* Select box */ | |
| .stSelectbox > div > div { | |
| background: #1a1a2e !important; | |
| border: 1px solid #2a2a3e !important; | |
| border-radius: 8px !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # ============================================================ | |
| # Sidebar | |
| # ============================================================ | |
| with st.sidebar: | |
| st.markdown("## ⚔️ LEGION") | |
| st.markdown("### Video Generation Engine") | |
| st.markdown("---") | |
| # Status check | |
| try: | |
| resp = requests.get(f"{BACKEND_URL}/api/status", timeout=3) | |
| status_data = resp.json() | |
| status_ok = status_data.get("status") == "ok" | |
| mock_mode = status_data.get("mock_mode", True) | |
| except Exception: | |
| status_ok = False | |
| mock_mode = True | |
| if status_ok: | |
| st.success("✅ Backend Connected") | |
| if mock_mode: | |
| st.info("🔄 Mock Mode (No GPU)") | |
| else: | |
| st.success("🚀 GPU Mode") | |
| else: | |
| st.error("❌ Backend Offline") | |
| st.markdown("---") | |
| st.markdown("### About") | |
| st.markdown(""" | |
| **LEGION** is a state-of-the-art video generation system with 8.3B parameters. | |
| - Text-to-Video | |
| - Image-to-Video | |
| - QWatermark System | |
| """) | |
| st.markdown("---") | |
| st.markdown("**v1.0** | Apache 2.0") | |
| # ============================================================ | |
| # Main Content | |
| # ============================================================ | |
| st.markdown( | |
| "<h1>⚔️ LEGION VIDEO GENERATION</h1>", | |
| unsafe_allow_html=True | |
| ) | |
| st.markdown( | |
| '<p style="color: #8888aa; font-size: 1.1em; margin-top: -10px; margin-bottom: 25px;">' | |
| 'The Ultimate AI Video Engine — Text-to-Video & Image-to-Video</p>', | |
| unsafe_allow_html=True | |
| ) | |
| # Tabs | |
| tab1, tab2, tab3 = st.tabs(["🎬 Text-to-Video", "🖼️ Image-to-Video", "💧 QWatermark"]) | |
| # ============================================================ | |
| # TAB 1: TEXT-TO-VIDEO | |
| # ============================================================ | |
| with tab1: | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| prompt = st.text_area( | |
| "📝 Prompt", | |
| value="A serene mountain lake at sunset with colorful clouds reflecting on the water, gentle ripples, cinematic quality", | |
| height=120, | |
| help="Describe the video you want to generate", | |
| ) | |
| negative_prompt = st.text_area( | |
| "🚫 Negative Prompt", | |
| value="warped, distorted, flickering, jittery, low quality, blurry, artifacts, ugly, deformed, bad anatomy", | |
| height=60, | |
| ) | |
| with st.expander("⚙️ Advanced Settings", expanded=False): | |
| adv_col1, adv_col2 = st.columns(2) | |
| with adv_col1: | |
| num_frames = st.slider("Frames", 1, 129, 49, help="Number of frames to generate") | |
| width = st.selectbox("Width", [256, 384, 480, 720], index=2) | |
| with adv_col2: | |
| steps = st.slider("Inference Steps", 10, 100, 50) | |
| height = st.selectbox("Height", [256, 384, 480, 720], index=2) | |
| col_adv = st.columns(2) | |
| with col_adv[0]: | |
| guidance = st.slider("Guidance Scale", 1.0, 20.0, 6.0, 0.5) | |
| with col_adv[1]: | |
| wm_strength = st.slider("QWatermark Strength", 0.0, 1.0, 0.3, 0.05) | |
| generate_btn = st.button("🛡️ GENERATE VIDEO", type="primary", use_container_width=True) | |
| with col2: | |
| video_placeholder = st.empty() | |
| status_placeholder = st.empty() | |
| if generate_btn: | |
| if not prompt.strip(): | |
| st.error("Please enter a prompt") | |
| else: | |
| with st.spinner("🎬 Generating video... This may take a moment."): | |
| try: | |
| payload = { | |
| "prompt": prompt, | |
| "negative_prompt": negative_prompt, | |
| "num_frames": num_frames, | |
| "width": width, | |
| "height": height, | |
| "num_inference_steps": steps, | |
| "guidance_scale": guidance, | |
| "watermark_strength": wm_strength, | |
| } | |
| resp = requests.post( | |
| f"{BACKEND_URL}/api/generate/text", | |
| json=payload, | |
| timeout=600, | |
| ) | |
| if resp.status_code == 200: | |
| 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) | |
| video_placeholder.video(output_path) | |
| status_placeholder.success("✅ Video generated successfully!") | |
| else: | |
| status_placeholder.error(f"❌ Error: {resp.text[:200]}") | |
| except Exception as e: | |
| status_placeholder.error(f"❌ Error: {str(e)}") | |
| # ============================================================ | |
| # TAB 2: IMAGE-TO-VIDEO | |
| # ============================================================ | |
| with tab2: | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| uploaded_file = st.file_uploader( | |
| "📷 Upload Input Image", | |
| type=["jpg", "jpeg", "png", "webp"], | |
| help="Upload an image to animate", | |
| ) | |
| if uploaded_file is not None: | |
| image = Image.open(uploaded_file) | |
| st.image(image, caption="Input Image", use_column_width=True) | |
| # Save to temp | |
| temp_dir = tempfile.mkdtemp() | |
| img_path = os.path.join(temp_dir, uploaded_file.name) | |
| image.save(img_path) | |
| i2v_prompt = st.text_area( | |
| "📝 Motion Prompt", | |
| value="Gentle motion, cinematic camera movement, atmospheric", | |
| height=80, | |
| help="Describe the motion or action", | |
| ) | |
| with st.expander("⚙️ Advanced Settings", expanded=False): | |
| i2v_col1, i2v_col2 = st.columns(2) | |
| with i2v_col1: | |
| i2v_frames = st.slider("Frames", 1, 129, 49, key="i2v_frames") | |
| i2v_width = st.selectbox("Width", [256, 384, 480, 720], index=2, key="i2v_width") | |
| with i2v_col2: | |
| i2v_steps = st.slider("Inference Steps", 10, 100, 50, key="i2v_steps") | |
| i2v_height = st.selectbox("Height", [256, 384, 480, 720], index=2, key="i2v_height") | |
| i2v_guidance = st.slider("Guidance Scale", 1.0, 20.0, 6.0, 0.5, key="i2v_guidance") | |
| i2v_wm = st.slider("QWatermark Strength", 0.0, 1.0, 0.3, 0.05, key="i2v_wm") | |
| i2v_btn = st.button("🛡️ GENERATE VIDEO", type="primary", use_container_width=True, key="i2v_btn") | |
| with col2: | |
| i2v_video_placeholder = st.empty() | |
| i2v_status_placeholder = st.empty() | |
| if i2v_btn: | |
| if uploaded_file is None: | |
| st.error("Please upload an image first") | |
| else: | |
| with st.spinner("🎬 Generating video from image..."): | |
| try: | |
| with open(img_path, "rb") as f: | |
| files = {"file": f} | |
| data = { | |
| "prompt": i2v_prompt, | |
| "negative_prompt": "warped, distorted, flickering, jittery, low quality, blurry", | |
| "num_frames": str(i2v_frames), | |
| "width": str(i2v_width), | |
| "height": str(i2v_height), | |
| "num_inference_steps": str(i2v_steps), | |
| "guidance_scale": str(i2v_guidance), | |
| "watermark_strength": str(i2v_wm), | |
| } | |
| resp = requests.post( | |
| f"{BACKEND_URL}/api/generate/image", | |
| files=files, | |
| data=data, | |
| timeout=600, | |
| ) | |
| if resp.status_code == 200: | |
| 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) | |
| i2v_video_placeholder.video(output_path) | |
| i2v_status_placeholder.success("✅ Video generated successfully!") | |
| else: | |
| i2v_status_placeholder.error(f"❌ Error: {resp.text[:200]}") | |
| except Exception as e: | |
| i2v_status_placeholder.error(f"❌ Error: {str(e)}") | |
| # ============================================================ | |
| # TAB 3: QWATERMARK SETTINGS | |
| # ============================================================ | |
| with tab3: | |
| st.markdown("## 💧 QWatermark Quality Assurance System") | |
| st.markdown(""" | |
| The QWatermark system imprints a semi-transparent quality assurance marker on every generated video. | |
| Configure the watermark appearance below. | |
| """) | |
| wm_col1, wm_col2 = st.columns(2) | |
| with wm_col1: | |
| wm_text = st.text_input("Watermark Text", value="LEGION") | |
| wm_position = st.selectbox( | |
| "Position", | |
| ["bottom-right", "bottom-left", "top-right", "top-left", "center"], | |
| index=0, | |
| ) | |
| with wm_col2: | |
| wm_font_size = st.slider("Font Size", 16, 72, 36, 2) | |
| wm_opacity = st.slider("Opacity", 0.0, 1.0, 0.3, 0.05) | |
| if st.button("👁️ PREVIEW WATERMARK", use_container_width=True): | |
| 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", wm_font_size) | |
| except: | |
| font = ImageFont.load_default() | |
| w, h = frame.size | |
| bbox = draw.textbbox((0, 0), wm_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(wm_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 * wm_opacity)), | |
| ) | |
| draw.text((x, y), wm_text, font=font, fill=(255, 255, 255, int(255 * wm_opacity))) | |
| st.image(frame, caption="Watermark Preview", use_column_width=True) | |
| except Exception as e: | |
| st.error(f"Preview error: {e}") | |
| st.markdown("---") | |
| st.info(""" | |
| **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). | |
| """) | |
| # ============================================================ | |
| # Footer | |
| # ============================================================ | |
| st.markdown("---") | |
| st.markdown( | |
| '<div class="footer">' | |
| '<p><strong>⚔️ LEGION VIDEO GENERATION</strong> — v1.0 | Apache 2.0 License</p>' | |
| '<p style="font-size: 0.8em;">Text-to-Video · Image-to-Video · QWatermark System</p>' | |
| '</div>', | |
| unsafe_allow_html=True, | |
| ) | |
| # ============================================================ | |
| # Run | |
| # ============================================================ | |
| if __name__ == "__main__": | |
| # Streamlit runs via `streamlit run frontend/streamlit_app.py` | |
| pass |