import gradio as gr import os import tempfile import shutil from typing import Optional, Union from huggingface_hub import InferenceClient from pathlib import Path # Initialize Hugging Face Inference Client with fal-ai provider client = InferenceClient( provider="fal-ai", api_key=os.environ.get("HF_TOKEN"), bill_to="huggingface", ) def cleanup_temp_files(): """Clean up old temporary video files to prevent storage overflow.""" try: temp_dir = tempfile.gettempdir() # Clean up old .mp4 files in temp directory for file_path in Path(temp_dir).glob("*.mp4"): try: # Remove files older than 5 minutes import time if file_path.stat().st_mtime < (time.time() - 300): file_path.unlink(missing_ok=True) except Exception: pass except Exception as e: print(f"Cleanup error: {e}") def generate_video( prompt: str, duration: int = 8, size: str = "1280x720", api_key: Optional[str] = None ) -> Optional[str]: """Generate video using Sora-2 through Hugging Face Inference API with fal-ai provider.""" cleanup_temp_files() try: if api_key: temp_client = InferenceClient( provider="fal-ai", api_key=api_key, bill_to="huggingface", ) else: temp_client = client if not os.environ.get("HF_TOKEN") and not api_key: return None video_bytes = temp_client.text_to_video( prompt, model="akhaliq/sora-2", ) temp_file = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) try: temp_file.write(video_bytes) temp_file.flush() video_path = temp_file.name finally: temp_file.close() return video_path except Exception as e: return None def generate_video_from_image( image: Union[str, bytes], prompt: str, api_key: Optional[str] = None ) -> Optional[str]: """Generate a video from a single input image + prompt using Sora-2 image-to-video.""" cleanup_temp_files() if not prompt or prompt.strip() == "": return None try: if api_key: temp_client = InferenceClient( provider="fal-ai", api_key=api_key, bill_to="huggingface", ) else: temp_client = client if not os.environ.get("HF_TOKEN") and not api_key: return None if isinstance(image, str): with open(image, "rb") as f: input_image = f.read() elif isinstance(image, (bytes, bytearray)): input_image = image else: return None video_bytes = temp_client.image_to_video( input_image, prompt=prompt, model="akhaliq/sora-2-image-to-video", ) temp_file = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) try: temp_file.write(video_bytes) temp_file.flush() video_path = temp_file.name finally: temp_file.close() return video_path except Exception as e: return None def generate_with_auth( prompt: str, profile: gr.OAuthProfile | None ) -> Optional[str]: """Wrapper function that checks if user is logged in before generating video.""" if profile is None: raise gr.Error("Click Sign in with Hugging Face button to use this app for free") if not prompt or prompt.strip() == "": return None return generate_video( prompt, duration=8, size="1280x720", api_key=None ) def generate_with_auth_image( prompt: str, image_path: Optional[str], profile: gr.OAuthProfile | None ) -> Optional[str]: """Checks login status then calls image->video generator.""" if profile is None: raise gr.Error("Click Sign in with Hugging Face button to use this app for free") if not image_path: return None return generate_video_from_image(image=image_path, prompt=prompt, api_key=None) def create_ui(): css = ''' .logo-dark{display: none} .dark .logo-dark{display: block !important} .dark .logo-light{display: none} #sub_title{margin-top: -20px !important} .mobile-notice { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 10px; margin: 20px auto; max-width: 600px; text-align: center; } .mobile-notice a { color: #fff; text-decoration: underline; font-weight: bold; } ''' with gr.Blocks(title="Sora-2", theme=gr.themes.Soft(), css=css) as demo: gr.HTML("""
Generate stunning videos using OpenAI's Sora-2 model
⚠️ You must Sign in with Hugging Face using the button to use this app.
Built with anycoder
Turn a single image into a short video with a guiding prompt.