memex-in commited on
Commit
db7de06
·
verified ·
1 Parent(s): aba327e

Upload 5 files

Browse files
Files changed (6) hide show
  1. .gitattributes +1 -0
  2. app.py +238 -0
  3. app_no_ui.py +205 -0
  4. config-example.py +2 -0
  5. final_video.mp4 +3 -0
  6. requirements.txt +6 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ final_video.mp4 filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import os
3
+ import shutil
4
+ import subprocess
5
+ import tempfile
6
+ from typing import List
7
+ import logging
8
+
9
+ import streamlit as st
10
+ from moviepy import concatenate_videoclips, VideoFileClip
11
+ from pydantic import BaseModel, Field
12
+ from pydantic_ai import Agent, RunContext
13
+ from pydantic_ai.models.gemini import GeminiModel
14
+ from pydantic_ai.providers.google_gla import GoogleGLAProvider
15
+ from config import api_key
16
+ import nest_asyncio
17
+ nest_asyncio.apply()
18
+ import re
19
+
20
+ # Configure logging
21
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
22
+
23
+ # Configure your Gemini API key
24
+ gemini_llm = GeminiModel(
25
+ 'gemini-2.0-flash', provider=GoogleGLAProvider(api_key=api_key)
26
+ )
27
+
28
+
29
+ class ChapterDescription(BaseModel):
30
+ """Describes a chapter in the video."""
31
+ title: str = Field(description="Title of the chapter.")
32
+ explanation: str = Field(description="Detailed explanation of the chapter's content, including how Manim should visualize it. Be very specific with Manim instructions, including animations, shapes, positions, colors, and timing. Include LaTeX for mathematical formulas. Specify scene transitions. Example: 'Create a number line. Animate a point moving along the number line to illustrate addition. Use Transform to show the equation changing. Transition to a new Scene.'")
33
+
34
+ class VideoOutline(BaseModel):
35
+ """Describes the outline of the video."""
36
+ title: str = Field(description="Title of the entire video.")
37
+ chapters: List[ChapterDescription] = Field(description="List of chapters in the video.")
38
+
39
+ class ManimCode(BaseModel):
40
+ """Describes the Manim code for a chapter."""
41
+ code: str = Field(description="Complete Manim code for the chapter. Include all necessary imports. The code should create a single scene. Add comments to explain the code. Do not include any comments that are not valid Python comments. Ensure the code is runnable.")
42
+
43
+ outline_agent = Agent(
44
+ model=gemini_llm,
45
+ result_type=VideoOutline,
46
+ system_prompt="""
47
+ You are a video script writer. Your job is to create a clear and concise outline for an educational video explaining a concept.
48
+ The video should have a title and a list of chapters (maximum 3). Each chapter should have a title and a detailed explanation.
49
+ The explanation should be very specific about how the concept should be visualized using Manim. Include detailed instructions
50
+ for animations, shapes, positions, colors, and timing. Use LaTeX for mathematical formulas. Specify scene transitions.
51
+ Do not include code, only explanations.
52
+ """
53
+ )
54
+
55
+ manim_agent = Agent(
56
+ model=gemini_llm,
57
+ result_type=ManimCode,
58
+ system_prompt="""
59
+ You are a Manim code generator. Your job is to create Manim code for a single chapter of a video, given a detailed explanation of the chapter's content and how it should be visualized.
60
+ The code should be complete and runnable. Include all necessary imports. The code should create a single scene. Add comments to explain the code.
61
+ Do not include any comments that are not valid Python comments. Ensure the code is runnable. Do not include any text outside of the code block.
62
+
63
+ """
64
+ )
65
+
66
+ code_fixer_agent = Agent(
67
+ model=gemini_llm,
68
+ result_type=ManimCode,
69
+ system_prompt="""
70
+ You are a Manim code debugging expert. You will receive Manim code that failed to execute and the error message.
71
+ Your task is to analyze the code and the error, identify the issue, and provide corrected, runnable Manim code.
72
+ Ensure the corrected code addresses the error and still aims to achieve the visualization described in the original code.
73
+ Include all necessary imports and ensure the code creates a single scene. Add comments to explain the changes you made.
74
+ Do not include any comments that are not valid Python comments. Ensure the code is runnable. Do not include any text outside of the code block.
75
+ """
76
+ )
77
+
78
+ def generate_manim_code(chapter_description: ChapterDescription) -> str:
79
+ """Generates initial Manim code for a single chapter."""
80
+ logging.info(f"Generating Manim code for chapter: {chapter_description.title}")
81
+ result = manim_agent.run_sync(f"title: {chapter_description.title}. Explanation: {chapter_description.explanation}")
82
+ return result.data.code
83
+
84
+ def fix_manim_code(error: str, current_code: str) -> str:
85
+ """Attempts to fix the Manim code that resulted in an error."""
86
+ logging.info(f"Attempting to fix Manim code due to error: {error}")
87
+ result = code_fixer_agent.run_sync(f"Error: {error}\nCurrent Code: {current_code}")
88
+ return result.data.code
89
+
90
+ def generate_video_outline(concept: str) -> VideoOutline:
91
+ """Generates the video outline."""
92
+ logging.info(f"Generating video outline for concept: {concept}")
93
+ result = outline_agent.run_sync(concept)
94
+ return result.data
95
+
96
+ def create_video_from_code(code: str, chapter_number: int) -> str:
97
+ """Creates a video from Manim code and returns the video file path using subprocess.Popen."""
98
+ with open("temp.py", "w") as temp_file:
99
+ temp_file.write(code)
100
+ temp_file_name = temp_file.name
101
+
102
+ process = None
103
+ try:
104
+ command = ["manim", temp_file_name, "-ql", "--disable_caching"]
105
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True)
106
+ stdout, stderr = process.communicate(timeout=60) # Add a timeout to prevent indefinite blocking
107
+
108
+ if process.returncode == 0:
109
+ logging.info(f"Manim execution successful for chapter {chapter_number}.")
110
+ logging.debug(f"Manim stdout:\n{stdout}")
111
+ logging.debug(f"Manim stderr:\n{stderr}")
112
+ else:
113
+ error_msg = f"Manim execution failed for chapter {chapter_number} with return code {process.returncode}:\nStdout:\n{stdout}\nStderr:\n{stderr}"
114
+ logging.error(str(error_msg).split('\n')[-1])
115
+ raise subprocess.CalledProcessError(process.returncode, command, output=stdout.encode(), stderr=stderr.encode())
116
+
117
+ except subprocess.TimeoutExpired:
118
+ logging.error(f"Manim process timed out for chapter {chapter_number}.")
119
+ if process:
120
+ process.kill()
121
+ raise
122
+ except FileNotFoundError:
123
+ logging.error("Error: The 'manim' command was not found. Ensure Manim is installed and in your system's PATH.")
124
+ raise
125
+ finally:
126
+ pass
127
+ # if os.path.exists(temp_file_name):
128
+ # os.remove(temp_file_name)
129
+
130
+ # Construct the video file name. Manim names the file based on the class name.
131
+ # Extract the class name from the python code.
132
+ match = re.search(r"class\s+(\w+)\(Scene\):", code)
133
+ if match:
134
+ class_name = match.group(1)
135
+ video_file_name = f"{class_name}.mp4"
136
+ return os.path.join("./media/videos/temp/480p15/", video_file_name)
137
+ else:
138
+ raise ValueError(f"Could not extract class name from Manim code for chapter {chapter_number}")
139
+
140
+ async def generate_video(concept: str):
141
+ """Generates a video explanation for a given concept using Manim with error correction."""
142
+ logging.info(f"Generating video for concept: {concept}")
143
+ outline = generate_video_outline(concept)
144
+ logging.info(f"Video outline: {outline}")
145
+
146
+ video_files = []
147
+ for i, chapter in enumerate(outline.chapters):
148
+ logging.info(f"Processing chapter {i + 1}: {chapter.title}")
149
+ manim_code = generate_manim_code(chapter)
150
+ logging.debug(f"Generated Manim code for chapter {i + 1}:\n{manim_code}")
151
+
152
+ success = False
153
+ attempts = 0
154
+ max_attempts = 2 # Try fixing the code once
155
+
156
+ while attempts < max_attempts and not success:
157
+ try:
158
+ video_file = create_video_from_code(manim_code, i + 1)
159
+ video_files.append(video_file)
160
+ logging.info(f"Video file created for chapter {i + 1}: {video_file}")
161
+ success = True
162
+ except subprocess.CalledProcessError as e:
163
+ attempts += 1
164
+ logging.error(f"Manim execution failed for chapter {i + 1} (Attempt {attempts}): {e}")
165
+ logging.info(f"Attempting to fix the code...")
166
+ manim_code = fix_manim_code(str(e), manim_code)
167
+ logging.debug(f"Fixed Manim code (Attempt {attempts}):\n{manim_code}")
168
+ except ValueError as e:
169
+ logging.error(f"Error processing Manim code for chapter {i + 1}: {e}")
170
+ st.error(f"Error processing chapter {i + 1}: {e}")
171
+ return None # Stop processing if a critical error occurs with code structure
172
+ except FileNotFoundError:
173
+ logging.error("Manim not found. Please ensure it's installed and in your PATH.")
174
+ st.error("Manim not found. Please ensure it's installed and in your PATH.")
175
+ return None
176
+ except subprocess.TimeoutExpired:
177
+ logging.error(f"Manim process timed out for chapter {i + 1}. Attempting to fix...")
178
+ manim_code = fix_manim_code(f"Manim process timed out.", manim_code)
179
+ logging.debug(f"Fixed Manim code (Attempt {attempts}):\n{manim_code}")
180
+
181
+ if not success:
182
+ logging.error(f"Failed to generate video for chapter {i + 1} after {max_attempts} attempts. Skipping chapter.")
183
+ st.warning(f"Failed to generate video for chapter {i + 1}. Skipping.")
184
+ continue
185
+
186
+ # Combine the video files
187
+ final_video_path = None
188
+ if video_files:
189
+ logging.info("Combining video files...")
190
+ try:
191
+ clips = [VideoFileClip(vf) for vf in video_files if os.path.exists(vf)]
192
+ if clips:
193
+ final_video_path = f"final_video.mp4"
194
+ final_clip = concatenate_videoclips(clips)
195
+ final_clip.write_videofile(final_video_path, codec="libx264", audio_codec="aac")
196
+ final_clip.close()
197
+ logging.info(f"Final video created: {final_video_path}")
198
+ st.success("Video generation complete!")
199
+ else:
200
+ logging.warning("No valid video files to combine.")
201
+ st.warning("No valid video files were generated.")
202
+ except Exception as e:
203
+ logging.error(f"Error combining video files: {e}")
204
+ st.error(f"Error combining video files: {e}")
205
+
206
+ # Clean up intermediate video files
207
+ for video_file in video_files:
208
+ try:
209
+ if os.path.exists(video_file):
210
+ os.remove(video_file)
211
+ logging.info(f"Deleted intermediate video file: {video_file}")
212
+ except Exception as e:
213
+ logging.error(f"Error deleting intermediate video file {video_file}: {e}")
214
+ else:
215
+ logging.warning("No video files to combine.")
216
+ st.warning("No video files were generated.")
217
+
218
+ return final_video_path
219
+
220
+ def main():
221
+ st.title("Explanatory Video Generator")
222
+ concept = st.text_input("Enter the concept for the video:")
223
+
224
+ if st.button("Generate Video"):
225
+ if concept:
226
+ with st.spinner("Generating video... This might take a few minutes."):
227
+ final_video_file = asyncio.run(generate_video(concept))
228
+ if final_video_file and os.path.exists(final_video_file):
229
+ st.video(final_video_file)
230
+ elif final_video_file:
231
+ st.error("Error: Final video file not found.")
232
+ else:
233
+ st.info("Video generation process completed without creating a final video.")
234
+ else:
235
+ st.warning("Please enter a concept.")
236
+
237
+ if __name__ == "__main__":
238
+ main()
app_no_ui.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import os
3
+ import shutil
4
+ import subprocess
5
+ import tempfile
6
+ from typing import List
7
+ import logging
8
+
9
+ from moviepy import concatenate_videoclips, VideoFileClip
10
+ from pydantic import BaseModel, Field
11
+ from pydantic_ai import Agent, RunContext
12
+ from pydantic_ai.models.gemini import GeminiModel
13
+ from pydantic_ai.providers.google_gla import GoogleGLAProvider
14
+ from config import api_key
15
+ import nest_asyncio
16
+ nest_asyncio.apply()
17
+
18
+ # Configure logging
19
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
20
+
21
+ # Configure your Gemini API key
22
+ gemini_llm = GeminiModel(
23
+ 'gemini-2.0-flash', provider=GoogleGLAProvider(api_key=api_key)
24
+ )
25
+
26
+
27
+ class ChapterDescription(BaseModel):
28
+ """Describes a chapter in the video."""
29
+ title: str = Field(description="Title of the chapter.")
30
+ explanation: str = Field(description="Detailed explanation of the chapter's content, including how Manim should visualize it. Be very specific with Manim instructions, including animations, shapes, positions, colors, and timing. Include LaTeX for mathematical formulas. Specify scene transitions. Example: 'Create a number line. Animate a point moving along the number line to illustrate addition. Use Transform to show the equation changing. Transition to a new Scene.'")
31
+
32
+ class VideoOutline(BaseModel):
33
+ """Describes the outline of the video."""
34
+ title: str = Field(description="Title of the entire video.")
35
+ chapters: List[ChapterDescription] = Field(description="List of chapters in the video.")
36
+
37
+ class ManimCode(BaseModel):
38
+ """Describes the Manim code for a chapter."""
39
+ code: str = Field(description="Complete Manim code for the chapter. Include all necessary imports. The code should create a single scene. Add comments to explain the code. Do not include any comments that are not valid Python comments. Ensure the code is runnable.")
40
+
41
+ outline_agent = Agent(
42
+ model=gemini_llm,
43
+ result_type=VideoOutline,
44
+ system_prompt="""
45
+ You are a video script writer. Your job is to create a clear and concise outline for an educational video explaining a concept.
46
+ The video should have a title and a list of chapters (maximum 3). Each chapter should have a title and a detailed explanation.
47
+ The explanation should be very specific about how the concept should be visualized using Manim. Include detailed instructions
48
+ for animations, shapes, positions, colors, and timing. Use LaTeX for mathematical formulas. Specify scene transitions.
49
+ Do not include code, only explanations.
50
+ """
51
+ )
52
+
53
+ manim_agent = Agent(
54
+ model=gemini_llm,
55
+ result_type=ManimCode,
56
+ system_prompt="""
57
+ You are a Manim code generator. Your job is to create Manim code for a single chapter of a video, given a detailed explanation of the chapter's content and how it should be visualized.
58
+ The code should be complete and runnable. Include all necessary imports. The code should create a single scene. Add comments to explain the code.
59
+ Do not include any comments that are not valid Python comments. Ensure the code is runnable. Do not include any text outside of the code block.
60
+
61
+ """
62
+ )
63
+
64
+ code_fixer_agent = Agent(
65
+ model=gemini_llm,
66
+ result_type=ManimCode,
67
+ system_prompt="""
68
+ You are a Manim code debugging expert. You will receive Manim code that failed to execute and the error message.
69
+ Your task is to analyze the code and the error, identify the issue, and provide corrected, runnable Manim code.
70
+ Ensure the corrected code addresses the error and still aims to achieve the visualization described in the original code.
71
+ Include all necessary imports and ensure the code creates a single scene. Add comments to explain the changes you made.
72
+ Do not include any comments that are not valid Python comments. Ensure the code is runnable. Do not include any text outside of the code block.
73
+ """
74
+ )
75
+
76
+ def generate_manim_code(chapter_description: ChapterDescription) -> str:
77
+ """Generates initial Manim code for a single chapter."""
78
+ logging.info(f"Generating Manim code for chapter: {chapter_description.title}")
79
+ result = manim_agent.run_sync(f"title: {chapter_description.title}. Explanation: {chapter_description.explanation}")
80
+ return result.data.code
81
+
82
+ def fix_manim_code(error: str, current_code: str) -> str:
83
+ """Attempts to fix the Manim code that resulted in an error."""
84
+ logging.info(f"Attempting to fix Manim code due to error: {error}")
85
+ result = code_fixer_agent.run_sync(f"Error: {error}\nCurrent Code: {current_code}")
86
+ return result.data.code
87
+
88
+ def generate_video_outline(concept: str) -> VideoOutline:
89
+ """Generates the video outline."""
90
+ logging.info(f"Generating video outline for concept: {concept}")
91
+ result = outline_agent.run_sync(concept)
92
+ return result.data
93
+
94
+ def create_video_from_code(code: str, chapter_number: int) -> str:
95
+ """Creates a video from Manim code and returns the video file path using subprocess.Popen."""
96
+ with open("temp.py", "w") as temp_file:
97
+ temp_file.write(code)
98
+ temp_file_name = temp_file.name
99
+
100
+ process = None
101
+ try:
102
+ command = ["manim", temp_file_name, "-ql", "--disable_caching"]
103
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True)
104
+ stdout, stderr = process.communicate(timeout=60) # Add a timeout to prevent indefinite blocking
105
+
106
+ if process.returncode == 0:
107
+ logging.info(f"Manim execution successful for chapter {chapter_number}.")
108
+ logging.debug(f"Manim stdout:\n{stdout}")
109
+ logging.debug(f"Manim stderr:\n{stderr}")
110
+ else:
111
+ error_msg = f"Manim execution failed for chapter {chapter_number} with return code {process.returncode}:\nStdout:\n{stdout}\nStderr:\n{stderr}"
112
+ logging.error(str(error_msg).split('\n')[-1])
113
+ raise subprocess.CalledProcessError(process.returncode, command, output=stdout.encode(), stderr=stderr.encode())
114
+
115
+ except subprocess.TimeoutExpired:
116
+ logging.error(f"Manim process timed out for chapter {chapter_number}.")
117
+ if process:
118
+ process.kill()
119
+ raise
120
+ except FileNotFoundError:
121
+ logging.error("Error: The 'manim' command was not found. Ensure Manim is installed and in your system's PATH.")
122
+ raise
123
+ finally:
124
+ pass
125
+ # if os.path.exists(temp_file_name):
126
+ # os.remove(temp_file_name)
127
+
128
+ # Construct the video file name. Manim names the file based on the class name.
129
+ # Extract the class name from the python code.
130
+ import re
131
+ match = re.search(r"class\s+(\w+)\(Scene\):", code)
132
+ if match:
133
+ class_name = match.group(1)
134
+ video_file_name = f"{class_name}.mp4"
135
+ return video_file_name
136
+ else:
137
+ raise ValueError(f"Could not extract class name from Manim code for chapter {chapter_number}")
138
+
139
+ async def main(concept: str):
140
+ """Generates a video explanation for a given concept using Manim with error correction."""
141
+ logging.info(f"Generating video for concept: {concept}")
142
+ outline = generate_video_outline(concept)
143
+ logging.info(f"Video outline: {outline}")
144
+
145
+ video_files = []
146
+ for i, chapter in enumerate(outline.chapters):
147
+ logging.info(f"Processing chapter {i + 1}: {chapter.title}")
148
+ manim_code = generate_manim_code(chapter)
149
+ logging.debug(f"Generated Manim code for chapter {i + 1}:\n{manim_code}")
150
+
151
+ success = False
152
+ attempts = 0
153
+ max_attempts = 2 # Try fixing the code once
154
+
155
+ while attempts < max_attempts and not success:
156
+ try:
157
+ video_file = create_video_from_code(manim_code, i + 1)
158
+ video_files.append(video_file)
159
+ logging.info(f"Video file created for chapter {i + 1}: {video_file}")
160
+ success = True
161
+ except subprocess.CalledProcessError as e:
162
+ attempts += 1
163
+ logging.error(f"Manim execution failed for chapter {i + 1} (Attempt {attempts}): {e}")
164
+ logging.info(f"Attempting to fix the code...")
165
+ manim_code = fix_manim_code(str(e), manim_code)
166
+ logging.debug(f"Fixed Manim code (Attempt {attempts}):\n{manim_code}")
167
+ except ValueError as e:
168
+ logging.error(f"Error processing Manim code for chapter {i + 1}: {e}")
169
+ return # Stop processing if a critical error occurs with code structure
170
+ except FileNotFoundError:
171
+ logging.error("Manim not found. Please ensure it's installed and in your PATH.")
172
+ return
173
+ except subprocess.TimeoutExpired:
174
+ logging.error(f"Manim process timed out for chapter {i + 1}. Attempting to fix...")
175
+ manim_code = fix_manim_code(f"Manim process timed out.", manim_code)
176
+ logging.debug(f"Fixed Manim code (Attempt {attempts}):\n{manim_code}")
177
+
178
+ if not success:
179
+ logging.error(f"Failed to generate video for chapter {i + 1} after {max_attempts} attempts. Skipping chapter.")
180
+ continue
181
+
182
+ # Combine the video files
183
+ if video_files:
184
+ logging.info("Combining video files...")
185
+ clips = [VideoFileClip("./media/videos/temp/480p15/"+video_file) for video_file in video_files]
186
+ final_video_path = f"final.mp4"
187
+ final_clip = concatenate_videoclips(clips)
188
+ final_clip.write_videofile(final_video_path, codec="libx264", audio_codec="aac")
189
+ final_clip.close()
190
+
191
+ logging.info(f"Final video created: {final_video_path}")
192
+
193
+ # Clean up intermediate video files
194
+ for video_file in video_files:
195
+ try:
196
+ os.remove(video_file)
197
+ logging.info(f"Deleted intermediate video file: {video_file}")
198
+ except Exception as e:
199
+ logging.error(f"Error deleting intermediate video file {video_file}: {e}")
200
+ else:
201
+ logging.warning("No video files to combine.")
202
+
203
+ if __name__ == "__main__":
204
+ concept = input("Enter your Prompt: ") # Replace with your concept
205
+ asyncio.run(main(concept))
config-example.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Rename this file to config.py and add your api key below
2
+ api_key='<google-gemini-api-key>'
final_video.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5de09a7c396fb719ad7a6ddd02eeb8ec6e8b8d97914e510b664dacae6c606ef4
3
+ size 134152
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ pydantic_ai
2
+ manim
3
+ moviepy
4
+ pydantic
5
+ nest_asyncio
6
+ streamlit