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