Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -38,7 +38,6 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
38 |
try:
|
39 |
research_results = tavily_client.search(query=f"Key facts and interesting points about {topic_prompt}", search_depth="basic")
|
40 |
facts = "\n".join([res['content'] for res in research_results['results']])
|
41 |
-
print(f"Tavily Research Results:\n{facts}")
|
42 |
except Exception as e:
|
43 |
print(f"Tavily API failed: {e}. Proceeding without research.")
|
44 |
facts = "No research data available."
|
@@ -47,15 +46,8 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
47 |
progress(0.2, desc="βοΈ Writing script with Gemini...")
|
48 |
gemini_model = genai.GenerativeModel('gemini-1.5-flash')
|
49 |
prompt = f"""
|
50 |
-
You are a creative director for viral short-form videos.
|
51 |
-
|
52 |
-
---
|
53 |
-
{facts}
|
54 |
-
---
|
55 |
-
Create a script for a 30-45 second video.
|
56 |
-
Your output MUST be a valid JSON object with two keys:
|
57 |
-
1. "narration_script": A string containing the full voiceover narration. Make it engaging and concise.
|
58 |
-
2. "scene_prompts": A list of exactly 4 strings. Each string must be a highly detailed, visually rich, and cinematic prompt for a text-to-video AI like Runway Gen-2. Describe camera angles, lighting, and mood.
|
59 |
"""
|
60 |
response = gemini_model.generate_content(prompt)
|
61 |
|
@@ -64,7 +56,6 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
64 |
script_data = json.loads(cleaned_text)
|
65 |
narration = script_data['narration_script']
|
66 |
scene_prompts = script_data['scene_prompts']
|
67 |
-
print(f"Gemini Script:\n{narration}\nPrompts:\n{scene_prompts}")
|
68 |
except (json.JSONDecodeError, KeyError) as e:
|
69 |
raise gr.Error(f"Gemini did not return valid JSON. Error: {e}. Response was: {response.text}")
|
70 |
|
@@ -73,17 +64,20 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
73 |
audio_path = f"audio_{job_id}.mp3"
|
74 |
intermediate_files.append(audio_path)
|
75 |
|
76 |
-
# !!!!!!!!!!! THIS IS THE CORRECTED
|
77 |
-
|
|
|
78 |
text=narration,
|
79 |
-
voice="Adam",
|
80 |
model="eleven_multilingual_v2"
|
81 |
)
|
82 |
-
|
|
|
83 |
with open(audio_path, "wb") as f:
|
84 |
-
for chunk in
|
85 |
f.write(chunk)
|
86 |
print(f"Audio file saved: {audio_path}")
|
|
|
87 |
|
88 |
# STEP 4: VISUALS (Runway)
|
89 |
video_clip_paths = []
|
@@ -123,8 +117,7 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
123 |
video_response = requests.get(video_url, stream=True)
|
124 |
with open(clip_path, "wb") as f:
|
125 |
for chunk in video_response.iter_content(chunk_size=1024):
|
126 |
-
if chunk:
|
127 |
-
f.write(chunk)
|
128 |
print(f"Video clip saved: {clip_path}")
|
129 |
|
130 |
# STEP 5: STITCHING (FFmpeg)
|
@@ -140,10 +133,7 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
140 |
subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', file_list_path, '-c', 'copy', combined_video_path, '-y'], check=True)
|
141 |
|
142 |
final_video_path = f"final_video_{job_id}.mp4"
|
143 |
-
subprocess.run([
|
144 |
-
'ffmpeg', '-i', combined_video_path, '-i', audio_path, '-c:v', 'copy',
|
145 |
-
'-c:a', 'aac', '-shortest', final_video_path, '-y'
|
146 |
-
], check=True)
|
147 |
print(f"Final video created at: {final_video_path}")
|
148 |
|
149 |
progress(1.0, desc="β
Done!")
|
@@ -163,31 +153,19 @@ def generate_video_from_topic(topic_prompt, progress=gr.Progress(track_tqdm=True
|
|
163 |
|
164 |
# --- 4. CREATE AND LAUNCH THE GRADIO INTERFACE ---
|
165 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
166 |
-
gr.Markdown(
|
167 |
-
|
168 |
-
# π€ My Personal AI Video Studio
|
169 |
-
Enter a topic to generate a short-form video. This private tool is used for fulfilling freelance orders.
|
170 |
-
"""
|
171 |
-
)
|
172 |
|
173 |
with gr.Row():
|
174 |
-
topic_input = gr.Textbox(
|
175 |
-
label="Video Topic",
|
176 |
-
placeholder="e.g., 'The history of coffee' or 'Benefits of our new CRM software'",
|
177 |
-
scale=3
|
178 |
-
)
|
179 |
generate_button = gr.Button("Generate Video", variant="primary", scale=1)
|
180 |
|
181 |
with gr.Row():
|
182 |
video_output = gr.Video(label="Generated Video")
|
183 |
|
184 |
-
generate_button.click(
|
185 |
-
fn=generate_video_from_topic,
|
186 |
-
inputs=topic_input,
|
187 |
-
outputs=video_output
|
188 |
-
)
|
189 |
|
190 |
-
gr.Markdown("--- \n ### Examples of Good Topics:\n - A product: 'The new waterproof Chrono-Watch X1'\n - A concept: 'The science of sleep'
|
191 |
|
192 |
|
193 |
if __name__ == "__main__":
|
|
|
38 |
try:
|
39 |
research_results = tavily_client.search(query=f"Key facts and interesting points about {topic_prompt}", search_depth="basic")
|
40 |
facts = "\n".join([res['content'] for res in research_results['results']])
|
|
|
41 |
except Exception as e:
|
42 |
print(f"Tavily API failed: {e}. Proceeding without research.")
|
43 |
facts = "No research data available."
|
|
|
46 |
progress(0.2, desc="βοΈ Writing script with Gemini...")
|
47 |
gemini_model = genai.GenerativeModel('gemini-1.5-flash')
|
48 |
prompt = f"""
|
49 |
+
You are a creative director for viral short-form videos. Based on the topic '{topic_prompt}' and research, create a script.
|
50 |
+
Your output MUST be a valid JSON object with "narration_script" (string) and "scene_prompts" (a list of 4 detailed, cinematic prompts).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
"""
|
52 |
response = gemini_model.generate_content(prompt)
|
53 |
|
|
|
56 |
script_data = json.loads(cleaned_text)
|
57 |
narration = script_data['narration_script']
|
58 |
scene_prompts = script_data['scene_prompts']
|
|
|
59 |
except (json.JSONDecodeError, KeyError) as e:
|
60 |
raise gr.Error(f"Gemini did not return valid JSON. Error: {e}. Response was: {response.text}")
|
61 |
|
|
|
64 |
audio_path = f"audio_{job_id}.mp3"
|
65 |
intermediate_files.append(audio_path)
|
66 |
|
67 |
+
# !!!!!!!!!!! THIS IS THE FINAL, CORRECTED SECTION !!!!!!!!!!!
|
68 |
+
# The API returns a stream (generator), so we must iterate over it.
|
69 |
+
audio_stream = elevenlabs_client.generate.from_text(
|
70 |
text=narration,
|
71 |
+
voice="Adam",
|
72 |
model="eleven_multilingual_v2"
|
73 |
)
|
74 |
+
|
75 |
+
# Write the streamed audio chunks to a file.
|
76 |
with open(audio_path, "wb") as f:
|
77 |
+
for chunk in audio_stream:
|
78 |
f.write(chunk)
|
79 |
print(f"Audio file saved: {audio_path}")
|
80 |
+
# !!!!!!!!!!! END OF CORRECTED SECTION !!!!!!!!!!!
|
81 |
|
82 |
# STEP 4: VISUALS (Runway)
|
83 |
video_clip_paths = []
|
|
|
117 |
video_response = requests.get(video_url, stream=True)
|
118 |
with open(clip_path, "wb") as f:
|
119 |
for chunk in video_response.iter_content(chunk_size=1024):
|
120 |
+
if chunk: f.write(chunk)
|
|
|
121 |
print(f"Video clip saved: {clip_path}")
|
122 |
|
123 |
# STEP 5: STITCHING (FFmpeg)
|
|
|
133 |
subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', file_list_path, '-c', 'copy', combined_video_path, '-y'], check=True)
|
134 |
|
135 |
final_video_path = f"final_video_{job_id}.mp4"
|
136 |
+
subprocess.run(['ffmpeg', '-i', combined_video_path, '-i', audio_path, '-c:v', 'copy', '-c:a', 'aac', '-shortest', final_video_path, '-y'], check=True)
|
|
|
|
|
|
|
137 |
print(f"Final video created at: {final_video_path}")
|
138 |
|
139 |
progress(1.0, desc="β
Done!")
|
|
|
153 |
|
154 |
# --- 4. CREATE AND LAUNCH THE GRADIO INTERFACE ---
|
155 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
156 |
+
gr.Markdown("# π€ My Personal AI Video Studio")
|
157 |
+
gr.Markdown("Enter a topic to generate a short-form video. This private tool is used for fulfilling freelance orders.")
|
|
|
|
|
|
|
|
|
158 |
|
159 |
with gr.Row():
|
160 |
+
topic_input = gr.Textbox(label="Video Topic", placeholder="e.g., 'The history of coffee'", scale=3)
|
|
|
|
|
|
|
|
|
161 |
generate_button = gr.Button("Generate Video", variant="primary", scale=1)
|
162 |
|
163 |
with gr.Row():
|
164 |
video_output = gr.Video(label="Generated Video")
|
165 |
|
166 |
+
generate_button.click(fn=generate_video_from_topic, inputs=topic_input, outputs=video_output)
|
|
|
|
|
|
|
|
|
167 |
|
168 |
+
gr.Markdown("--- \n ### Examples of Good Topics:\n - A product: 'The new waterproof Chrono-Watch X1'\n - A concept: 'The science of sleep'")
|
169 |
|
170 |
|
171 |
if __name__ == "__main__":
|