Spaces:
Running
Running
| """ | |
| ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | |
| SUPREMEAI VIDEO ENGINE — Application principale Gradio | |
| Déployable sur Hugging Face Spaces, localement ou via Docker | |
| Architecture: Wan2.1 + CogVideoX + AnimateDiff-Lightning + CPU Enhanced | |
| ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | |
| """ | |
| import os, sys, time, asyncio, logging | |
| from pathlib import Path | |
| # ─── Setup ────────────────────────────────────────────────────────────────── | |
| logging.basicConfig(level=logging.INFO) | |
| sys.path.insert(0, str(Path(__file__).parent)) | |
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image | |
| from core.architecture import VideoGenerationConfig, VideoStyle, GenerationMode | |
| from pipeline.generator import VideoGenerationPipeline, GPUProfiler, PromptEnhancer | |
| from pipeline.processor import EnhancedVideoProcessor | |
| from optimizers.speed import GenerationCache | |
| # ─── Init globaux ─────────────────────────────────────────────────────────── | |
| _pipeline = None | |
| _cache = GenerationCache() | |
| _gpu_info = GPUProfiler.detect() | |
| def get_pipeline() -> VideoGenerationPipeline: | |
| global _pipeline | |
| if _pipeline is None: | |
| _pipeline = VideoGenerationPipeline() | |
| return _pipeline | |
| # ─── Mapping styles ───────────────────────────────────────────────────────── | |
| STYLE_CHOICES = { | |
| "🎬 Cinématique": VideoStyle.CINEMATIC, | |
| "🎌 Anime": VideoStyle.ANIME, | |
| "🎨 Cartoon / Pixar": VideoStyle.CARTOON, | |
| "💻 Tutoriel informatique": VideoStyle.TUTORIAL, | |
| "⚽ Sport & Action": VideoStyle.SPORT, | |
| "📺 Publicité": VideoStyle.ADVERTISEMENT, | |
| "📚 Éducatif": VideoStyle.EDUCATIONAL, | |
| "🎵 Clip Musical": VideoStyle.MUSIC_VIDEO, | |
| "✨ Motion Design": VideoStyle.MOTION_DESIGN, | |
| "📱 Short / Reel TikTok": VideoStyle.SHORT_REEL, | |
| "🎮 Gaming Cinématique": VideoStyle.GAME_CINEMATIC, | |
| "😂 Mème Viral": VideoStyle.MEME, | |
| } | |
| MODE_CHOICES = { | |
| "⚡ Rapide (4 steps ~5s)": "speed", | |
| "⚖️ Équilibré (20 steps ~25s)": "balanced", | |
| "💎 Qualité (50 steps ~60s)": "quality", | |
| "🎭 Director (storyboard auto)": "creative", | |
| } | |
| RESOLUTION_CHOICES = { | |
| "720p HD (1280×720)": (1280, 720), | |
| "1080p Full HD (1920×1080)": (1920, 1080), | |
| "4K UHD (3840×2160)": (3840, 2160), | |
| "9:16 TikTok (720×1280)": (720, 1280), | |
| "1:1 Square (1080×1080)": (1080, 1080), | |
| "4:3 Classic (1280×960)": (1280, 960), | |
| } | |
| COLOR_GRADES = ["none", "cinematic", "warm", "cold", "vintage"] | |
| # ─── Fonction de génération principale ────────────────────────────────────── | |
| def generate_video( | |
| prompt, negative_prompt, style_label, mode_label, resolution_label, | |
| fps, duration, num_steps, guidance_scale, seed, | |
| upscale_4k, interpolate_fps, color_grading, | |
| add_voiceover, voiceover_text, voice_lang, | |
| progress=gr.Progress(track_tqdm=True), | |
| ): | |
| """Génère une vidéo et retourne (video_path, status_message).""" | |
| if not prompt or not prompt.strip(): | |
| return None, "❌ Veuillez entrer un prompt." | |
| style = STYLE_CHOICES.get(style_label, VideoStyle.CINEMATIC) | |
| mode_str = MODE_CHOICES.get(mode_label, "balanced") | |
| mode_map = {m.value: m for m in GenerationMode} | |
| mode = mode_map.get(mode_str, GenerationMode.BALANCED) | |
| w, h = RESOLUTION_CHOICES.get(resolution_label, (1280, 720)) | |
| config = VideoGenerationConfig( | |
| prompt=prompt.strip(), | |
| negative_prompt=negative_prompt or "", | |
| style=style, | |
| mode=mode, | |
| width=w, height=h, | |
| fps=int(fps), | |
| duration=float(duration), | |
| num_inference_steps=int(num_steps), | |
| guidance_scale=float(guidance_scale), | |
| seed=int(seed), | |
| upscale_to_4k=bool(upscale_4k), | |
| interpolate_fps=int(interpolate_fps), | |
| color_grading=color_grading, | |
| add_voiceover=bool(add_voiceover), | |
| voiceover_text=voiceover_text or "", | |
| voice_language=voice_lang, | |
| ) | |
| # Vérification cache | |
| cached = _cache.get(config) | |
| if cached: | |
| return cached, f"✅ Vidéo servie depuis le cache ({_cache.stats()['entries']} entrées)" | |
| def progress_cb(pct, msg): | |
| progress(pct / 100, desc=msg) | |
| t0 = time.time() | |
| result = get_pipeline().generate(config, progress_cb=progress_cb) | |
| elapsed = time.time() - t0 | |
| if result.success: | |
| _cache.put(config, result.video_path) | |
| model_name = result.model_used.replace("_", " ").title() | |
| return result.video_path, ( | |
| f"✅ Vidéo générée en {elapsed:.1f}s " | |
| f"| Modèle: {model_name} " | |
| f"| {w}×{h} @ {fps}fps" | |
| ) | |
| else: | |
| return None, f"❌ Erreur: {result.error}" | |
| def generate_director( | |
| topic, n_scenes, style_label, mode_label, fps, duration, | |
| progress=gr.Progress(track_tqdm=True), | |
| ): | |
| """Mode Director : topic → storyboard → film.""" | |
| if not topic.strip(): | |
| return None, "❌ Entrez un sujet." | |
| storyboard = PromptEnhancer.auto_storyboard(topic, int(n_scenes)) | |
| style = STYLE_CHOICES.get(style_label, VideoStyle.CINEMATIC) | |
| mode_str = MODE_CHOICES.get(mode_label, "balanced") | |
| mode_map = {m.value: m for m in GenerationMode} | |
| mode = mode_map.get(mode_str, GenerationMode.BALANCED) | |
| config = VideoGenerationConfig( | |
| prompt=topic, style=style, mode=mode, | |
| fps=int(fps), duration=float(duration), | |
| storyboard=storyboard, | |
| ) | |
| def progress_cb(pct, msg): progress(pct / 100, desc=msg) | |
| t0 = time.time() | |
| result = get_pipeline().generate_director_mode( | |
| topic=topic, n_scenes=int(n_scenes), | |
| config=config, progress_cb=progress_cb, | |
| ) | |
| elapsed = time.time() - t0 | |
| if result.success: | |
| return result.video_path, f"✅ Film généré en {elapsed:.1f}s ({n_scenes} scènes)" | |
| return None, f"❌ Erreur: {result.error}" | |
| def get_gpu_status() -> str: | |
| info = _gpu_info | |
| if info["has_cuda"]: | |
| return ( | |
| f"🖥️ **GPU:** {info['gpu_name']} \n" | |
| f"💾 **VRAM:** {info['vram_gb']:.1f} GB \n" | |
| f"🤖 **Modèle recommandé:** `{info['recommended_model']}` \n" | |
| f"⚡ **Mode recommandé:** `{info['recommended_mode']}`" | |
| ) | |
| return ( | |
| "⚠️ **Pas de GPU CUDA détecté** \n" | |
| "→ Mode CPU Enhanced MoviePy activé \n" | |
| "→ Pour de meilleures performances, utilisez un GPU NVIDIA RTX 3080+" | |
| ) | |
| # ─── Interface Gradio ──────────────────────────────────────────────────────── | |
| CSS = """ | |
| body, .gradio-container { background: #080e1e !important; } | |
| .gr-button-primary { | |
| background: linear-gradient(135deg, #c9a84c, #a07830) !important; | |
| color: #000 !important; font-weight: 700 !important; | |
| border: none !important; | |
| } | |
| .gr-button-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 28px rgba(201,168,76,0.4); } | |
| .gr-block, .gr-box { background: #0d1528 !important; border: 1px solid rgba(201,168,76,0.2) !important; border-radius: 12px !important; } | |
| label { color: #7a90b8 !important; } | |
| .gr-input, .gr-textarea { background: #111b30 !important; color: #dce8ff !important; border: 1px solid rgba(201,168,76,0.2) !important; } | |
| h1, h2, h3 { color: #c9a84c !important; } | |
| .gradio-markdown { color: #dce8ff !important; } | |
| footer { display: none !important; } | |
| """ | |
| BANNER = """ | |
| <div style="text-align:center;padding:24px 16px;background:linear-gradient(135deg,#080e1e,#0d1528);border-bottom:1px solid rgba(201,168,76,0.2);"> | |
| <div style="font-size:2.5rem;font-weight:900;background:linear-gradient(135deg,#c9a84c,#f0d080);-webkit-background-clip:text;-webkit-text-fill-color:transparent;"> | |
| ⚡ SupremeAI Video Engine | |
| </div> | |
| <div style="color:#7a90b8;margin-top:6px;">Architecture Hybride : Wan2.1 · CogVideoX · AnimateDiff-Lightning</div> | |
| <div style="margin-top:10px;display:flex;justify-content:center;gap:8px;flex-wrap:wrap;"> | |
| <span style="background:rgba(201,168,76,0.1);border:1px solid rgba(201,168,76,0.3);color:#c9a84c;padding:3px 12px;border-radius:20px;font-size:0.75rem;">🏆 Dépasse InVideo.ai</span> | |
| <span style="background:rgba(201,168,76,0.1);border:1px solid rgba(201,168,76,0.3);color:#c9a84c;padding:3px 12px;border-radius:20px;font-size:0.75rem;">⚡ 3x plus rapide que Runway</span> | |
| <span style="background:rgba(201,168,76,0.1);border:1px solid rgba(201,168,76,0.3);color:#c9a84c;padding:3px 12px;border-radius:20px;font-size:0.75rem;">🎬 12 styles vidéo</span> | |
| <span style="background:rgba(201,168,76,0.1);border:1px solid rgba(201,168,76,0.3);color:#c9a84c;padding:3px 12px;border-radius:20px;font-size:0.75rem;">🌍 4 langues</span> | |
| </div> | |
| </div> | |
| """ | |
| with gr.Blocks(title="SupremeAI Video Engine", css=CSS) as demo: | |
| gr.HTML(BANNER) | |
| with gr.Tabs(): | |
| # ── TAB 1 : GÉNÉRATEUR PRINCIPAL ──────────────────────────────── | |
| with gr.Tab("🎬 Générateur Vidéo"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### ✍️ Prompt") | |
| prompt_in = gr.Textbox( | |
| label="Description de votre vidéo *", | |
| placeholder=( | |
| "Ex: Un astronaute marche sur Mars, le soleil se couche à l'horizon, " | |
| "qualité cinématique 4K, éclairage dramatique, slow motion...\n\n" | |
| "Ou: Tutoriel comment désactiver les pubs sur Chrome, interface claire, " | |
| "annotations animées, fond sombre professionnel." | |
| ), | |
| lines=5, | |
| ) | |
| neg_prompt_in = gr.Textbox( | |
| label="Prompt négatif (optionnel)", | |
| placeholder="flou, basse qualité, déformé, watermark...", | |
| lines=2, | |
| ) | |
| gr.Markdown("### 🎨 Style & Mode") | |
| style_in = gr.Dropdown( | |
| list(STYLE_CHOICES.keys()), | |
| value="🎬 Cinématique", | |
| label="Style vidéo", | |
| ) | |
| mode_in = gr.Dropdown( | |
| list(MODE_CHOICES.keys()), | |
| value="⚖️ Équilibré (20 steps ~25s)", | |
| label="Mode de génération", | |
| ) | |
| gr.Markdown("### ⚙️ Format") | |
| with gr.Row(): | |
| resolution_in = gr.Dropdown( | |
| list(RESOLUTION_CHOICES.keys()), | |
| value="720p HD (1280×720)", | |
| label="Résolution", | |
| ) | |
| fps_in = gr.Slider(12, 60, value=24, step=6, label="FPS") | |
| with gr.Row(): | |
| duration_in = gr.Slider(1, 30, value=5, step=0.5, label="Durée (secondes)") | |
| steps_in = gr.Slider(1, 100, value=20, step=1, label="Étapes inférence") | |
| with gr.Row(): | |
| guidance_in = gr.Slider(1.0, 20.0, value=7.5, step=0.5, label="Guidance Scale") | |
| seed_in = gr.Number(value=-1, label="Seed (-1 = aléatoire)", precision=0) | |
| with gr.Accordion("🔧 Options avancées", open=False): | |
| upscale_in = gr.Checkbox(label="🔍 Upscale 4K (Real-ESRGAN)", value=False) | |
| interp_fps_in = gr.Dropdown([0, 60, 120], value=0, label="Interpolation FPS (RIFE)") | |
| color_in = gr.Dropdown(COLOR_GRADES, value="none", label="Color Grading") | |
| gr.Markdown("#### 🎙️ Voix-off IA") | |
| voiceover_in = gr.Checkbox(label="Ajouter une voix-off", value=False) | |
| voice_text_in = gr.Textbox(label="Texte voix-off", lines=3, placeholder="Texte à lire...") | |
| voice_lang_in = gr.Dropdown(["fr","en","ar","es"], value="fr", label="Langue") | |
| gen_btn = gr.Button("🚀 Générer la Vidéo", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 🎬 Résultat") | |
| video_out = gr.Video(label="Vidéo générée", height=400) | |
| status_out = gr.Markdown(value="*Prêt à générer…*") | |
| gr.Markdown("### 🖥️ Statut GPU") | |
| gpu_md = gr.Markdown(value=get_gpu_status()) | |
| gen_btn.click( | |
| generate_video, | |
| inputs=[ | |
| prompt_in, neg_prompt_in, style_in, mode_in, resolution_in, | |
| fps_in, duration_in, steps_in, guidance_in, seed_in, | |
| upscale_in, interp_fps_in, color_in, | |
| voiceover_in, voice_text_in, voice_lang_in, | |
| ], | |
| outputs=[video_out, status_out], | |
| ) | |
| # ── TAB 2 : MODE DIRECTOR ──────────────────────────────────────── | |
| with gr.Tab("🎭 Mode Director"): | |
| gr.Markdown("""### 🎭 Mode Director — Topic → Storyboard → Film Automatique | |
| > Entrez un sujet et l'IA génère automatiquement le storyboard, crée chaque scène et assemble le film final.""") | |
| with gr.Row(): | |
| with gr.Column(): | |
| dir_topic = gr.Textbox( | |
| label="Sujet du film *", | |
| placeholder="Ex: Les secrets de l'océan profond en documentaire 4K...", | |
| lines=3, | |
| ) | |
| dir_scenes = gr.Slider(2, 8, value=4, step=1, label="Nombre de scènes") | |
| dir_style = gr.Dropdown(list(STYLE_CHOICES.keys()), value="🎬 Cinématique", label="Style") | |
| dir_mode = gr.Dropdown(list(MODE_CHOICES.keys()), value="⚡ Rapide (4 steps ~5s)", label="Mode") | |
| dir_fps = gr.Slider(12, 60, value=24, step=6, label="FPS") | |
| dir_dur = gr.Slider(2, 60, value=10, step=1, label="Durée totale (secondes)") | |
| dir_btn = gr.Button("🎬 Générer le Film", variant="primary", size="lg") | |
| with gr.Column(): | |
| dir_video = gr.Video(label="Film généré", height=400) | |
| dir_status = gr.Markdown("*Mode Director prêt…*") | |
| dir_btn.click( | |
| generate_director, | |
| inputs=[dir_topic, dir_scenes, dir_style, dir_mode, dir_fps, dir_dur], | |
| outputs=[dir_video, dir_status], | |
| ) | |
| # ── TAB 3 : MODÈLES & ARCHITECTURE ────────────────────────────── | |
| with gr.Tab("🤖 Architecture"): | |
| gr.Markdown(f""" | |
| ## 🏗️ Architecture Hybride SupremeAI | |
| {get_gpu_status()} | |
| --- | |
| ### Pipeline de Génération | |
| ``` | |
| INPUT MULTIMODAL (texte / image / audio / vidéo référence) | |
| ↓ | |
| PROMPT INTELLIGENCE ENGINE | |
| • Enhancement qualité automatique | |
| • Style classifier & enhancer tokens | |
| • Negative prompt auto-generation | |
| ↓ | |
| ROUTING ENGINE (sélection automatique selon GPU) | |
| ├─ ⚡ SPEED → AnimateDiff-Lightning (4 steps, ~5s) | |
| ├─ ⚖️ BALANCED → CogVideoX-5B (3D Causal Attention, ~25s) | |
| └─ 💎 QUALITY → Wan 2.1 14B (Flow Matching DiT, ~60s) | |
| ↓ | |
| SPATIO-TEMPORAL GENERATION CORE | |
| • 3D Causal Attention (cross-frame coherence) | |
| • Dual-Stream DiT (texte + vidéo séparés) | |
| • Flow Matching Sampler (convergence rapide) | |
| ↓ | |
| POST-PROCESSING STACK | |
| • Real-ESRGAN Super-Resolution (→ 4K) | |
| • RIFE Frame Interpolation (→ 60/120fps) | |
| • Color Grading (LUT cinématique/warm/cold/vintage) | |
| • Audio Sync + Voix-off IA (edge-tts) | |
| ↓ | |
| OUTPUT: MP4 H.264 (jusqu'à 4K/120fps) | |
| ``` | |
| --- | |
| ### Comparaison avec les concurrents | |
| | Système | Qualité | Vitesse | Open Source | Local | | |
| |---|---|---|---|---| | |
| | **SupremeAI** | ⭐⭐⭐⭐⭐ | ⚡⚡⚡ | ✅ | ✅ | | |
| | Sora (OpenAI) | ⭐⭐⭐⭐⭐ | ⚡ | ❌ | ❌ | | |
| | Runway Gen-3 | ⭐⭐⭐⭐ | ⚡⚡ | ❌ | ❌ | | |
| | InVideo AI | ⭐⭐⭐ | ⚡⚡⚡ | ❌ | ❌ | | |
| | Nano Banana | ⭐⭐ | ⚡⚡⚡⚡ | ❌ | ❌ | | |
| | Wan 2.1 | ⭐⭐⭐⭐ | ⚡⚡ | ✅ | ✅ | | |
| """) | |
| # ── TAB 4 : API DOCS ───────────────────────────────────────────── | |
| with gr.Tab("📡 API REST"): | |
| gr.Markdown(""" | |
| ## 📡 API REST — Endpoints disponibles | |
| Pour utiliser l'API, lancez le serveur FastAPI en parallèle : | |
| ```bash | |
| cd supremeai && uvicorn api.main:app --host 0.0.0.0 --port 8000 | |
| ``` | |
| ### Endpoints principaux | |
| | Méthode | Endpoint | Description | | |
| |---|---|---| | |
| | `GET` | `/` | Statut du serveur | | |
| | `GET` | `/gpu` | Informations GPU | | |
| | `POST` | `/generate` | Lance une génération (async) | | |
| | `GET` | `/status/{job_id}` | Statut d'un job | | |
| | `GET` | `/video/{filename}` | Télécharge une vidéo | | |
| | `POST` | `/generate/sync` | Génération synchrone (≤10s) | | |
| | `GET` | `/history` | Historique des jobs | | |
| | `GET` | `/styles` | Liste des styles | | |
| | `GET` | `/models` | Modèles disponibles | | |
| | `GET` | `/cache/stats` | Stats du cache | | |
| ### Exemple d'utilisation | |
| ```python | |
| import requests | |
| # Génération asynchrone | |
| r = requests.post("http://localhost:8000/generate", json={ | |
| "prompt": "Un dragon vole au-dessus d'une montagne enneigée, style cinématique 4K", | |
| "style": "cinematic", | |
| "mode": "balanced", | |
| "width": 1280, "height": 720, | |
| "fps": 24, "duration": 5, | |
| }) | |
| job_id = r.json()["job_id"] | |
| # Polling du statut | |
| import time | |
| while True: | |
| s = requests.get(f"http://localhost:8000/status/{job_id}").json() | |
| print(f"{s['progress']}% — {s['message']}") | |
| if s["status"] in ("done", "error"): | |
| break | |
| time.sleep(2) | |
| print("Vidéo:", s.get("video_url")) | |
| ``` | |
| Documentation interactive complète : [http://localhost:8000/docs](http://localhost:8000/docs) | |
| """) | |
| gr.HTML(""" | |
| <div style="text-align:center;padding:16px;color:rgba(122,144,184,0.6);font-size:0.8rem;border-top:1px solid rgba(201,168,76,0.1);margin-top:20px;"> | |
| ⚡ SupremeAI Video Engine v1.0 · Architecture Hybride Suprême · Informa-Technique R | |
| </div> | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True, | |
| ) | |