import gradio as gr import requests import json import re from typing import List, Dict, Any import os # Hugging Face configuration HF_TOKEN = os.getenv("HUGGING_FACE_API_TOKEN", "") HF_API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev" def parse_script(script_text: str) -> Dict[str, Any]: """Parse script text and extract scenes and characters""" lines = script_text.strip().split('\n') scenes = [] characters = set() current_scene = None for line in lines: line = line.strip() if not line: continue # Scene headers (INT./EXT.) if line.upper().startswith(('INT.', 'EXT.', 'SCENE')): if current_scene: scenes.append(current_scene) current_scene = { 'location': line, 'dialogue': [], 'action': [] } # Character dialogue (ALL CAPS followed by dialogue) elif line.isupper() and len(line.split()) <= 3 and current_scene: characters.add(line) current_scene['dialogue'].append({'character': line, 'lines': []}) # Dialogue lines elif current_scene and current_scene['dialogue'] and not line.isupper(): current_scene['dialogue'][-1]['lines'].append(line) # Action lines elif current_scene and not line.isupper(): current_scene['action'].append(line) if current_scene: scenes.append(current_scene) return { 'scenes': scenes, 'characters': list(characters), 'total_scenes': len(scenes) } def generate_shot_list(script_data: Dict[str, Any]) -> List[Dict[str, Any]]: """Generate shot list from parsed script""" shots = [] shot_id = 1 for scene_idx, scene in enumerate(script_data['scenes']): # Establishing shot shots.append({ 'id': shot_id, 'type': 'Establishing Shot', 'description': f"Wide shot of {scene['location']}", 'scene': scene_idx + 1, 'location': scene['location'] }) shot_id += 1 # Character shots dialogue_chars = set() for dialogue in scene['dialogue']: char = dialogue['character'] if char not in dialogue_chars: shots.append({ 'id': shot_id, 'type': 'Medium Shot', 'description': f"Medium shot of {char}", 'scene': scene_idx + 1, 'character': char, 'location': scene['location'] }) dialogue_chars.add(char) shot_id += 1 # Action shots for action in scene['action']: if len(action) > 20: # Only significant action lines shots.append({ 'id': shot_id, 'type': 'Action Shot', 'description': action[:100] + "..." if len(action) > 100 else action, 'scene': scene_idx + 1, 'location': scene['location'] }) shot_id += 1 return shots def generate_image(prompt: str) -> str: """Generate image using Hugging Face API""" if not HF_TOKEN: return "https://via.placeholder.com/512x512?text=No+API+Key" headers = { "Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json" } payload = { "inputs": f"{prompt}, cinematic, professional, high quality" } try: response = requests.post(HF_API_URL, headers=headers, json=payload, timeout=30) if response.status_code == 200: # Save image and return path import base64 image_data = response.content image_b64 = base64.b64encode(image_data).decode() return f"data:image/png;base64,{image_b64}" else: return f"https://via.placeholder.com/512x512?text=API+Error+{response.status_code}" except Exception as e: return f"https://via.placeholder.com/512x512?text=Error" def process_script(script_text: str, generate_images: bool = True): """Main function to process script and generate shot list""" if not script_text.strip(): return "Please enter a script.", "", "" # Parse script script_data = parse_script(script_text) # Generate shot list shots = generate_shot_list(script_data) # Create summary summary = f""" ## Script Analysis Summary - **Total Scenes:** {script_data['total_scenes']} - **Characters:** {', '.join(script_data['characters'])} - **Generated Shots:** {len(shots)} """ # Create shot list display shot_list_html = "
Scene: {shot['scene']}
Description: {shot['description']}
{f"Character: {shot.get('character', 'N/A')}
" if shot.get('character') else ""}Location: {shot.get('location', 'N/A')}