File size: 5,052 Bytes
aa5de1c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import gradio as gr
import os
import google.generativeai as genai
# Import other SDKs for Runway, ElevenLabs, Tavily
# For example: from elevenlabs import generate, play, set_api_key
import subprocess
import json
import time

# --- 1. LOAD API KEYS FROM SECRETS ---
# This is the secure way to do it in Hugging Face Spaces
genai.configure(api_key=os.environ.get('GEMINI_API_KEY'))
# set_api_key(os.environ.get('ELEVENLABS_API_KEY'))
# ... and so on for other APIs

# --- 2. DEFINE THE CORE VIDEO GENERATION FUNCTION ---
# This function will take the client's prompt and do all the work.
def generate_video_from_topic(topic_prompt):
    print(f"Starting video generation for topic: {topic_prompt}")
    
    # Placeholder for the final video path
    final_video_path = None
    
    try:
        # STEP A: RESEARCH (Tavily) - Optional but recommended
        # research_results = tavily_client.search(query=f"Key points about {topic_prompt}")
        # facts = research_results['results']
        
        # STEP B: SCRIPT & SCENE PROMPTS (Gemini)
        # We ask Gemini for a structured JSON output
        gemini_model = genai.GenerativeModel('gemini-pro')
        prompt = f"""
        Create a short video script about '{topic_prompt}'.
        The video should be about 30 seconds long.
        Return a JSON object with two keys: 'narration_script' (a string) and 'scene_prompts' (a list of 4 detailed, cinematic visual prompts for an AI video generator).
        
        Example:
        {{
          "narration_script": "This is the complete narration for the video.",
          "scene_prompts": ["prompt 1", "prompt 2", "prompt 3", "prompt 4"]
        }}
        """
        response = gemini_model.generate_content(prompt)
        script_data = json.loads(response.text)
        
        narration = script_data['narration_script']
        scene_prompts = script_data['scene_prompts']
        print(f"Generated Narration: {narration}")
        print(f"Generated Scene Prompts: {scene_prompts}")

        # STEP C: VOICE OVER (ElevenLabs)
        # audio_bytes = generate(text=narration, voice="Adam", model="eleven_multilingual_v2")
        # with open("audio.mp3", "wb") as f:
        #     f.write(audio_bytes)
        # print("Audio file generated.")
        
        # --- MOCKUP for now ---
        # Since API calls cost money, let's use a placeholder for testing
        print("MOCK: Skipping real API calls for audio. Using a placeholder.")
        # Create a silent audio file of the right length for testing
        narration_duration = len(narration.split()) / 2.5 # Estimate duration
        subprocess.run(['ffmpeg', '-f', 'lavfi', '-i', 'anullsrc=r=44100:cl=mono', '-t', str(narration_duration), '-q:a', '9', '-acodec', 'libmp3lame', 'audio.mp3', '-y'])


        # STEP D: VISUALS (Runway/Hailuo)
        video_clips = []
        for i, scene_prompt in enumerate(scene_prompts):
            print(f"Generating video for scene {i+1}: {scene_prompt}")
            # MOCKUP: Create a simple placeholder video clip
            clip_path = f"scene_{i+1}.mp4"
            subprocess.run([
                'ffmpeg', '-f', 'lavfi', '-i', f'smptebars=size=1920x1080:rate=30',
                '-t', '4', '-pix_fmt', 'yuv420p', clip_path, '-y'
            ])
            video_clips.append(clip_path)

        # STEP E: STITCHING (FFmpeg)
        # Create a file list for ffmpeg
        with open("file_list.txt", "w") as f:
            for clip in video_clips:
                f.write(f"file '{clip}'\n")

        # Concatenate video clips
        subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', 'file_list.txt', '-c', 'copy', 'combined_video.mp4', '-y'])
        
        # Add audio to the combined video
        final_video_path = f"final_video_{int(time.time())}.mp4"
        subprocess.run([
            'ffmpeg', '-i', 'combined_video.mp4', '-i', 'audio.mp3', '-c:v', 'copy',
            '-c:a', 'aac', '-shortest', final_video_path, '-y'
        ])
        print(f"Final video created at: {final_video_path}")

    except Exception as e:
        print(f"An error occurred: {e}")
        # You can return an error message to the Gradio interface
        raise gr.Error(f"Failed to generate video. Error: {e}")

    # Return the path to the final video so Gradio can display it
    return final_video_path


# --- 3. CREATE THE GRADIO INTERFACE ---
with gr.Blocks() as demo:
    gr.Markdown("# 🤖 My Personal AI Video Studio")
    gr.Markdown("Enter a topic to generate a short-form video for social media. Used for fulfilling Fiverr orders.")
    
    with gr.Row():
        topic_input = gr.Textbox(label="Video Topic", placeholder="e.g., 'The benefits of a standing desk'")
        generate_button = gr.Button("Generate Video", variant="primary")
        
    with gr.Row():
        video_output = gr.Video(label="Generated Video")
        
    generate_button.click(
        fn=generate_video_from_topic,
        inputs=topic_input,
        outputs=video_output
    )

# --- 4. LAUNCH THE APP ---
demo.launch()