Chand11 commited on
Commit
f62f93a
·
verified ·
1 Parent(s): cb78db1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -54
app.py CHANGED
@@ -12,7 +12,7 @@ try:
12
  GENAI_AVAILABLE = True
13
  except ImportError:
14
  GENAI_AVAILABLE = False
15
- print("")
16
 
17
  # Get API key from environment
18
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
@@ -70,6 +70,26 @@ def fix_all_known_errors(code):
70
  # 8. Replace Tex with MathTex
71
  code = re.sub(r'\bTex\(', 'MathTex(', code)
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  return code
74
 
75
  def generate_code_with_gemini(prompt):
@@ -88,67 +108,75 @@ def generate_code_with_gemini(prompt):
88
 
89
  model = genai.GenerativeModel(model_name)
90
 
91
- full_prompt = f"""Generate Manim code. CRITICAL RULES:
 
 
 
 
92
 
93
- 1. COLORS - ONLY these 10: BLUE, RED, GREEN, YELLOW, ORANGE, PURPLE, PINK, TEAL, WHITE, BLACK
94
- NO variants (_A, _B, _C, _D, _E)
95
 
96
- 2. TEXT OVERLAP PREVENTION (MOST IMPORTANT):
97
- - ALWAYS FadeOut text before showing new text
98
- - NEVER reuse the same position without FadeOut first
99
- - Pattern for EVERY text:
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  ```python
101
- title = Text("Title", font_size=36).to_edge(UP, buff=1)
102
- self.play(Write(title))
103
- self.wait(1.5)
104
- self.play(FadeOut(title)) # ← MANDATORY!
105
 
106
- # Now safe to reuse UP position
107
- subtitle = Text("Next", font_size=32).to_edge(UP, buff=1)
108
- self.play(Write(subtitle))
109
- self.wait(1.5)
110
- self.play(FadeOut(subtitle)) # ← MANDATORY!
111
  ```
112
 
113
- 3. SAFE BOUNDARIES (CRITICAL):
114
- - Font size: MAX 36 (never larger!)
115
- - Shifts: UP*1.5, DOWN*1.5, LEFT*3, RIGHT*3 (MAX!)
116
- - Always use buff=1 with to_edge()
117
- - Safe zone: X[-4, 4], Y[-2, 2]
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- 4. NEVER use:
120
  - get_x_axis_label(), get_y_axis_label()
121
- - Checkmark, SVGMobject, ImageMobject
 
122
  - .add_prefix(), .add_suffix()
123
 
124
- 5. For axis labels:
125
- x_label = Text("Time", font_size=24).next_to(axes.x_axis, DOWN, buff=0.5)
126
- y_label = Text("Value", font_size=24).next_to(axes.y_axis, LEFT, buff=0.5)
 
 
127
 
128
- 6. STRUCTURE - Follow this pattern:
129
- ```python
130
- from manim import *
131
-
132
- class MyScene(Scene):
133
- def construct(self):
134
- self.camera.background_color = WHITE
135
-
136
- # Section 1
137
- text1 = Text("First", font_size=36).to_edge(UP, buff=1)
138
- self.play(Write(text1))
139
- self.wait(1.5)
140
- self.play(FadeOut(text1)) # ← Clean up!
141
-
142
- # Section 2
143
- text2 = Text("Second", font_size=32).to_edge(UP, buff=1)
144
- self.play(Write(text2))
145
- self.wait(1.5)
146
- self.play(FadeOut(text2)) # ← Clean up!
147
- ```
148
 
149
- User wants: {prompt}
150
-
151
- Generate complete code following ALL rules above. EVERY text MUST have FadeOut before next text!"""
152
 
153
  response = model.generate_content(full_prompt)
154
  code = response.text
@@ -223,11 +251,18 @@ def render_video(prompt, quality="low"):
223
  )
224
 
225
  output_lines = []
 
226
  for line in process.stdout:
227
  output_lines.append(line)
 
 
 
228
 
229
  process.wait()
230
 
 
 
 
231
  if process.returncode == 0:
232
  # Find the generated video
233
  media_path = temp_dir / "media"
@@ -235,11 +270,19 @@ def render_video(prompt, quality="low"):
235
 
236
  if video_files:
237
  video_path = str(video_files[0])
238
- yield f"✅ Video rendered successfully! 🎉", code, video_path
 
 
 
 
 
 
 
 
239
  else:
240
  yield "❌ Video file not found after rendering", code, None
241
  else:
242
- error_msg = ''.join(output_lines[-30:]) # Last 30 lines
243
  yield f"❌ Rendering failed:\n\n{error_msg}", code, None
244
 
245
  # Cleanup
@@ -259,7 +302,11 @@ def create_interface():
259
  gr.Markdown("""
260
  # 🎬 Manim Video Generator
261
  Create mathematical animations using AI! Describe what you want to see animated.
262
-
 
 
 
 
263
  **Examples:**
264
  - "Explain Pythagorean theorem with animation"
265
  - "Show a sine wave transforming into a cosine wave"
@@ -295,6 +342,11 @@ def create_interface():
295
  - Medium/High quality may take 2-3 minutes
296
  - Complex animations may timeout on free tier
297
 
 
 
 
 
 
298
  """)
299
 
300
  generate_btn.click(
@@ -319,4 +371,4 @@ def create_interface():
319
 
320
  if __name__ == "__main__":
321
  demo = create_interface()
322
- demo.launch()
 
12
  GENAI_AVAILABLE = True
13
  except ImportError:
14
  GENAI_AVAILABLE = False
15
+ print("⚠️ google-generativeai not installed")
16
 
17
  # Get API key from environment
18
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
 
70
  # 8. Replace Tex with MathTex
71
  code = re.sub(r'\bTex\(', 'MathTex(', code)
72
 
73
+ # 9. CRITICAL FIX: Add color=BLACK to Text objects that don't have color specified
74
+ # This prevents invisible white text on white background
75
+ # Match Text(...) that doesn't have color= parameter
76
+ def add_black_color(match):
77
+ text_content = match.group(0)
78
+ # Check if color parameter already exists
79
+ if 'color=' not in text_content:
80
+ # Find the closing parenthesis of Text()
81
+ # Add color=BLACK before the last closing paren
82
+ if ', font_size=' in text_content:
83
+ # Insert after font_size
84
+ text_content = text_content.replace(')', ', color=BLACK)', 1)
85
+ else:
86
+ # Insert before closing paren
87
+ text_content = text_content[:-1] + ', color=BLACK)'
88
+ return text_content
89
+
90
+ # Apply to all Text() objects
91
+ code = re.sub(r'Text\([^)]+\)', add_black_color, code)
92
+
93
  return code
94
 
95
  def generate_code_with_gemini(prompt):
 
108
 
109
  model = genai.GenerativeModel(model_name)
110
 
111
+ full_prompt = f"""You are a Manim code generator. Generate WORKING Manim animation code.
112
+
113
+ USER REQUEST: {prompt}
114
+
115
+ CRITICAL RULES YOU MUST FOLLOW:
116
 
117
+ 1. ALWAYS start with: from manim import *
 
118
 
119
+ 2. Class structure MUST be:
120
+ ```python
121
+ from manim import *
122
+
123
+ class MyScene(Scene):
124
+ def construct(self):
125
+ # Your animation code here
126
+ # MUST have at least one self.play() or self.add()
127
+ ```
128
+
129
+ 3. COLORS - ONLY use these 10: BLUE, RED, GREEN, YELLOW, ORANGE, PURPLE, PINK, TEAL, WHITE, BLACK
130
+ - NO color variants like BLUE_A, RED_B, etc.
131
+
132
+ 4. TEXT RULES:
133
+ - Use: Text("message", font_size=36, color=BLACK)
134
+ - ALWAYS FadeOut text before creating new text in same position
135
+ - Example:
136
  ```python
137
+ text1 = Text("First", font_size=36, color=BLACK)
138
+ self.play(Write(text1))
139
+ self.wait(1)
140
+ self.play(FadeOut(text1)) # Must FadeOut!
141
 
142
+ text2 = Text("Second", font_size=36, color=BLACK)
143
+ self.play(Write(text2))
144
+ self.wait(1)
145
+ self.play(FadeOut(text2))
 
146
  ```
147
 
148
+ 5. SHAPES:
149
+ - Circle: Circle(radius=1, color=BLUE)
150
+ - Square: Square(side_length=2, color=RED)
151
+ - Rectangle: Rectangle(width=3, height=2, color=GREEN)
152
+ - Line: Line(start=LEFT, end=RIGHT, color=YELLOW)
153
+
154
+ 6. POSITIONING:
155
+ - Use .shift(UP), .shift(DOWN), .shift(LEFT), .shift(RIGHT)
156
+ - Use .to_edge(UP), .to_edge(DOWN), .to_edge(LEFT), .to_edge(RIGHT)
157
+ - Use .move_to(ORIGIN)
158
+
159
+ 7. ANIMATIONS:
160
+ - Show objects: Create(), Write(), FadeIn()
161
+ - Hide objects: FadeOut(), Uncreate()
162
+ - Transform: Transform(obj1, obj2)
163
+ - Move: obj.animate.shift(UP)
164
 
165
+ 8. NEVER USE:
166
  - get_x_axis_label(), get_y_axis_label()
167
+ - SVGMobject, ImageMobject
168
+ - Checkmark, XMark
169
  - .add_prefix(), .add_suffix()
170
 
171
+ 9. SIMPLE AND WORKING:
172
+ - Keep it simple
173
+ - Test each animation
174
+ - Make sure there's visible content
175
+ - Animation should be 5-10 seconds long
176
 
177
+ Generate COMPLETE, WORKING code that creates a visible animation for: {prompt}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
+ The code must actually show something on screen!"""
 
 
180
 
181
  response = model.generate_content(full_prompt)
182
  code = response.text
 
251
  )
252
 
253
  output_lines = []
254
+ has_error = False
255
  for line in process.stdout:
256
  output_lines.append(line)
257
+ # Check for common errors in output
258
+ if any(err in line.lower() for err in ['error', 'exception', 'traceback', 'failed']):
259
+ has_error = True
260
 
261
  process.wait()
262
 
263
+ # Get full output for debugging
264
+ full_output = ''.join(output_lines)
265
+
266
  if process.returncode == 0:
267
  # Find the generated video
268
  media_path = temp_dir / "media"
 
270
 
271
  if video_files:
272
  video_path = str(video_files[0])
273
+ # Check if video file is too small (blank video indicator)
274
+ video_size = os.path.getsize(video_path)
275
+
276
+ if video_size < 5000: # Less than 5KB means blank/error
277
+ yield f"⚠️ Video rendered but seems blank (only {video_size} bytes)!\n\nMaybe there's an error in the code. Check the generated code below.\n\nRender output (last 40 lines):\n{chr(10).join(output_lines[-40:])}", code, None
278
+ elif has_error:
279
+ yield f"⚠️ Video rendered but errors detected!\n\nRender output (last 40 lines):\n{chr(10).join(output_lines[-40:])}", code, video_path
280
+ else:
281
+ yield f"✅ Video rendered successfully! 🎉", code, video_path
282
  else:
283
  yield "❌ Video file not found after rendering", code, None
284
  else:
285
+ error_msg = ''.join(output_lines[-40:]) # Last 40 lines
286
  yield f"❌ Rendering failed:\n\n{error_msg}", code, None
287
 
288
  # Cleanup
 
302
  gr.Markdown("""
303
  # 🎬 Manim Video Generator
304
  Create mathematical animations using AI! Describe what you want to see animated.
305
+
306
+ **⚠️ IMPORTANT: You need to set GEMINI_API_KEY in Space Settings → Variables and secrets**
307
+
308
+ Get your free Gemini API key from: https://aistudio.google.com/app/apikey
309
+
310
  **Examples:**
311
  - "Explain Pythagorean theorem with animation"
312
  - "Show a sine wave transforming into a cosine wave"
 
342
  - Medium/High quality may take 2-3 minutes
343
  - Complex animations may timeout on free tier
344
 
345
+ ### 🔧 Setup Required:
346
+ 1. Get a free Gemini API key from: https://aistudio.google.com/app/apikey
347
+ 2. In your Space, go to Settings → Variables and secrets
348
+ 3. Add: Name: `GEMINI_API_KEY`, Value: `your-api-key-here`
349
+ 4. Restart the Space
350
  """)
351
 
352
  generate_btn.click(
 
371
 
372
  if __name__ == "__main__":
373
  demo = create_interface()
374
+ demo.launch()