Spaces:
Runtime error
Runtime error
| import os | |
| import random | |
| import requests | |
| from huggingface_hub import InferenceClient | |
| from moviepy.editor import * | |
| from moviepy.config import change_settings | |
| # specific config for ImageMagick on Linux/HF Spaces | |
| change_settings({"IMAGEMAGICK_BINARY": "/usr/bin/convert"}) | |
| def get_env(key): | |
| val = os.getenv(key) | |
| if not val: | |
| print(f"⚠️ Missing Env Var: {key}") | |
| return val | |
| # --- 1. AI WRITING ENGINE --- | |
| def generate_script(): | |
| """Generates the raw ad script using Mistral/Llama.""" | |
| token = get_env("HF_TOKEN") | |
| client = InferenceClient(token=token) | |
| # The Prompt: Aggressive, Gen Z, No fluff | |
| prompt = """ | |
| ROLE: Marketing Director for Upniso (Gen Z Creator Brand). | |
| TONE: Rebellious, High-Voltage, Anti-Corporate. | |
| RULE: NO EMOJIS. NO HASHTAGS IN SCRIPT. | |
| TASK: Write a 4-line video script + Metadata. | |
| OUTPUT FORMAT: Return ONLY text separated by '||'. | |
| Structure: | |
| 1. Hook (Shocking statement) | |
| 2. Pain (Why current life sucks) | |
| 3. Vision (Upniso is the answer) | |
| 4. Call to Action (Short) | |
| 5. Caption (For social media) | |
| Example: | |
| You are sleeping on your potential||The 9 to 5 is a cage||Break out and build your empire||Join Upniso now||Time to wake up. Link in bio. | |
| """ | |
| try: | |
| response = client.text_generation( | |
| prompt, | |
| model="mistralai/Mistral-7B-Instruct-v0.2", | |
| max_new_tokens=250, | |
| temperature=0.85 | |
| ) | |
| # Parse logic | |
| parts = response.split("||") | |
| if len(parts) < 5: | |
| # Fallback if AI hallucinates format | |
| return { | |
| "hook": "WAKE UP.", | |
| "pain": "Your art deserves better.", | |
| "vision": "Build with Upniso.", | |
| "cta": "Join Us.", | |
| "caption": "No more excuses." | |
| } | |
| return { | |
| "hook": parts[0].strip(), | |
| "pain": parts[1].strip(), | |
| "vision": parts[2].strip(), | |
| "cta": parts[3].strip(), | |
| "caption": parts[4].strip() | |
| } | |
| except Exception as e: | |
| print(f"LLM Error: {e}") | |
| return None | |
| # --- 2. VIDEO PRODUCTION ENGINE --- | |
| def fetch_stock_video(query): | |
| """Downloads a video from Pexels.""" | |
| api_key = get_env("PEXELS_API_KEY") | |
| headers = {'Authorization': api_key} | |
| url = f"https://api.pexels.com/videos/search?query={query}&per_page=3&orientation=portrait" | |
| try: | |
| r = requests.get(url, headers=headers) | |
| data = r.json() | |
| video = random.choice(data['videos']) | |
| # Get highest quality link | |
| link = video['video_files'][0]['link'] | |
| filename = f"temp_{random.randint(1,1000)}.mp4" | |
| with open(filename, 'wb') as f: | |
| f.write(requests.get(link).content) | |
| return filename | |
| except Exception: | |
| return None | |
| def build_video(script): | |
| """Edits the video clips together with text.""" | |
| print("🎬 Starting Video Render...") | |
| # 1. Fetch Visuals | |
| clips = [] | |
| keywords = ["storm", "fire", "cyberpunk", "running"] # Aggressive keywords | |
| texts = [script['hook'], script['pain'], script['vision'], script['cta']] | |
| for i, text in enumerate(texts): | |
| vid_file = fetch_stock_video(keywords[i]) | |
| if vid_file: | |
| # Process Video | |
| clip = VideoFileClip(vid_file).subclip(0, 3) # 3 sec per clip | |
| clip = clip.resize(height=1280) | |
| clip = clip.crop(x1=clip.w/2 - 360, width=720, height=1280) # 9:16 Aspect | |
| # Create Text Overlay | |
| # Note: Using default font to avoid errors, white text, black stroke | |
| txt = TextClip(text.upper(), color='white', font="Liberation-Sans-Bold", fontsize=60, method='caption', size=(650, None)) | |
| txt = txt.set_pos('center').set_duration(3) | |
| combined = CompositeVideoClip([clip, txt]) | |
| clips.append(combined) | |
| # Clean up temp file | |
| os.remove(vid_file) | |
| if not clips: | |
| return None | |
| final = concatenate_videoclips(clips) | |
| # Export | |
| output_path = "daily_ad.mp4" | |
| final.write_videofile(output_path, fps=24, codec='libx264', audio_codec='aac') | |
| return output_path |