Adityahulk commited on
Commit
12fe8d7
·
1 Parent(s): 3768c4a

adding integration for video dfriectly in streamlit app

Browse files
manimator/agents/reflexion_agent.py CHANGED
@@ -243,12 +243,45 @@ YOU MUST APPLY THESE LESSONS IN YOUR CODE! Do not repeat these mistakes.
243
 
244
  {goal}
245
 
246
- CRITICAL REMINDERS:
247
- 1. NO BLANK SCREENS: Keep the screen populated. If a voiceover is playing, show something.
248
- 2. NO OVERLAPS: Ensure text and objects do not overlap. Use `next_to` and `arrange` with proper `buff`.
249
- 3. CLEAN TRANSITIONS: Fade out old content before showing new content.
250
- 4. VARIED ANIMATIONS: Use a mix of Write, FadeIn, GrowFromCenter, etc.
251
- 5. STAY ON SCREEN: Ensure all text and objects are within screen boundaries.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  """
253
 
254
  messages = [
@@ -282,37 +315,81 @@ CODE TO REVIEW:
282
  {code}
283
  ```
284
 
285
- Review specifically for:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
- 1. **Visual Overlaps** (CRITICAL):
288
- - VGroup misuse (arranging mixed types together)
289
- - Objects placed at same position without offset
290
- - Text stacking on top of other text
291
- - Elements not using next_to() or arrange() properly
 
292
 
293
- 2. **Manim API Misuse**:
294
- - Invalid parameters (corner_radius on Rectangle, etc.)
295
- - Deprecated methods
296
- - Incorrect animation calls
297
 
298
- 3. **Logic Errors**:
299
- - Objects used before definition
300
- - Animations on removed objects
301
- - Incorrect loop logic
302
 
303
- 4. **Best Practices**:
304
- - Blank screens during voiceover
305
- - Missing cleanup (FadeOut before new content)
306
- - Objects going off-screen
307
- - Poor animation variety
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
  For EACH issue found, provide:
310
  - severity: "low" | "medium" | "high"
311
- - category: "OVERLAP" | "API_MISUSE" | "LOGIC_ERROR" | "BEST_PRACTICE"
312
  - line_range: [start_line, end_line] if identifiable
313
  - description: What's wrong
314
  - suggestion: How to fix it
315
 
 
 
 
 
 
316
  If the code is well-written with no significant issues, respond with:
317
  {{"has_issues": false, "overall_severity": "none", "issues": [], "summary": "Code is well-structured"}}
318
 
@@ -324,13 +401,20 @@ Respond ONLY with valid JSON in this exact format:
324
  "issues": [
325
  {{
326
  "severity": "high",
327
- "category": "OVERLAP",
328
- "line_range": [65, 68],
329
- "description": "VGroup(boxes, labels).arrange() treats these as 2 items, causing all boxes to overlap",
330
- "suggestion": "Create individual VGroup pairs: [VGroup(box, label) for box, label in zip(boxes, labels)], then arrange pairs"
 
 
 
 
 
 
 
331
  }}
332
  ],
333
- "summary": "Found 1 critical overlap issue"
334
  }}
335
  ```
336
  """
 
243
 
244
  {goal}
245
 
246
+ # ============================================================================
247
+ # 🚨 CRITICAL REQUIREMENTS - YOU MUST FOLLOW THESE
248
+ # ============================================================================
249
+
250
+ ## SCREEN BOUNDARIES (CRITICAL!)
251
+ - **ALL content MUST stay on screen** - nothing should be cut off
252
+ - For any VGroup with 4+ items: USE `group.scale_to_fit_height(config.frame_height - 2.5)`
253
+ - Maximum 4-5 items visible at once, use smaller fonts (28-32pt) for lists
254
+ - Always leave margins: top 1.0, bottom 0.8, sides 0.5
255
+
256
+ ## DYNAMIC ANIMATIONS (CRITICAL!)
257
+ - **NEVER use only Write()** - mix at least 4 different animation types
258
+ - **MUST use LaggedStart** for any list of items: `LaggedStart(*[FadeIn(x, shift=RIGHT) for x in items], lag_ratio=0.2)`
259
+ - **MUST include emphasis animations**: `Indicate()`, `Circumscribe()`, `Flash()` on key elements
260
+ - **Use motion during voiceover**: `obj.animate.scale(1.05)` while explaining
261
+ - **Creative transitions**: `FadeOut(old, shift=LEFT), FadeIn(new, shift=RIGHT)`
262
+
263
+ ## NO STATIC/BORING MOMENTS
264
+ - NEVER have blank screens - always show something
265
+ - NEVER use `self.wait()` longer than 0.5s without animation
266
+ - Every section should have at least one emphasis animation
267
+ - Objects should move and transform, not just appear
268
+
269
+ ## GOOD EXAMPLE PATTERN:
270
+ ```python
271
+ # Create items and SCALE TO FIT
272
+ items = VGroup(*[Text(f"Item {{i}}", font_size=28) for i in range(5)])
273
+ items.arrange(DOWN, buff=0.3)
274
+ items.scale_to_fit_height(config.frame_height - 3.0) # CRITICAL!
275
+ items.next_to(title, DOWN, buff=0.6)
276
+
277
+ # Animate with VARIETY
278
+ self.play(LaggedStart(*[FadeIn(i, shift=RIGHT) for i in items], lag_ratio=0.15))
279
+
280
+ # Add EMPHASIS
281
+ self.play(Indicate(items[0], color=YELLOW, scale_factor=1.1))
282
+ self.play(Circumscribe(items[1]))
283
+ self.play(items[2].animate.scale(1.1).set_color(GREEN))
284
+ ```
285
  """
286
 
287
  messages = [
 
315
  {code}
316
  ```
317
 
318
+ # ============================================================================
319
+ # CRITICAL REVIEW CATEGORIES - CHECK ALL CAREFULLY
320
+ # ============================================================================
321
+
322
+ ## 1. 🚨 SCREEN BOUNDARY ISSUES (HIGH PRIORITY)
323
+
324
+ Check if content will GO OFF SCREEN:
325
+ - Count items in VGroups - if 5+ items are arranged vertically, is there `scale_to_fit_height()`?
326
+ - Are there multiple items stacked without proper scaling?
327
+ - Is `config.frame_height` or `config.frame_width` used for boundary checks?
328
+ - **RED FLAG**: VGroup with 4+ items arranged(DOWN) WITHOUT scale_to_fit_height = CRITICAL ERROR
329
+ - **RED FLAG**: Large groups not using safe margins (buff < 0.5)
330
+
331
+ **Expected pattern for 4+ items:**
332
+ ```python
333
+ group.scale_to_fit_height(config.frame_height - 2.5)
334
+ ```
335
+
336
+ ## 2. 🎬 ANIMATION VARIETY & ENGAGEMENT (HIGH PRIORITY)
337
+
338
+ Check if video will be STATIC/BORING:
339
+ - Count animation types used - are there at least 3-4 different types?
340
+ - **RED FLAG**: Only using `Write()` for all animations
341
+ - **RED FLAG**: No emphasis animations (Indicate, Circumscribe, Flash, etc.)
342
+ - **RED FLAG**: No LaggedStart for list animations
343
+ - **RED FLAG**: Long `self.wait()` calls (> 1 second) without visual activity
344
+ - **RED FLAG**: Simple FadeIn/FadeOut without shift parameters
345
 
346
+ **Good animations to look for:**
347
+ - `FadeIn(obj, shift=UP/DOWN/LEFT/RIGHT)`
348
+ - `LaggedStart(*[...], lag_ratio=0.2)`
349
+ - `Indicate()`, `Circumscribe()`, `Flash()`
350
+ - `obj.animate.scale(1.1).set_color(YELLOW)`
351
+ - `GrowFromCenter()`, `DrawBorderThenFill()` ✓
352
 
353
+ ## 3. 📐 VISUAL OVERLAPS
 
 
 
354
 
355
+ - VGroup misuse (arranging mixed types together)
356
+ - Objects placed at same position without offset
357
+ - Text stacking on top of other text
358
+ - Elements not using next_to() or arrange() properly
359
 
360
+ ## 4. 🔧 MANIM API MISUSE
361
+
362
+ - Invalid parameters (corner_radius on Rectangle, etc.)
363
+ - Deprecated methods
364
+ - Incorrect animation calls
365
+
366
+ ## 5. 💡 LOGIC ERRORS
367
+
368
+ - Objects used before definition
369
+ - Animations on removed objects
370
+ - Incorrect loop logic
371
+
372
+ ## 6. ✨ BEST PRACTICES
373
+
374
+ - Blank screens during voiceover (no visuals while talking)
375
+ - Missing cleanup (FadeOut before new content)
376
+ - Poor visual hierarchy
377
+ - No transitions between sections (just FadeOut/FadeIn without motion)
378
+
379
+ # ============================================================================
380
 
381
  For EACH issue found, provide:
382
  - severity: "low" | "medium" | "high"
383
+ - category: "OFF_SCREEN" | "STATIC_VIDEO" | "OVERLAP" | "API_MISUSE" | "LOGIC_ERROR" | "BEST_PRACTICE"
384
  - line_range: [start_line, end_line] if identifiable
385
  - description: What's wrong
386
  - suggestion: How to fix it
387
 
388
+ **SEVERITY GUIDE:**
389
+ - HIGH: Content goes off-screen, only Write() animations used, major overlaps
390
+ - MEDIUM: Missing emphasis animations, no LaggedStart for lists, long waits
391
+ - LOW: Minor styling issues, could be slightly more dynamic
392
+
393
  If the code is well-written with no significant issues, respond with:
394
  {{"has_issues": false, "overall_severity": "none", "issues": [], "summary": "Code is well-structured"}}
395
 
 
401
  "issues": [
402
  {{
403
  "severity": "high",
404
+ "category": "OFF_SCREEN",
405
+ "line_range": [45, 52],
406
+ "description": "VGroup with 6 items arranged vertically without scale_to_fit_height - content will go off bottom of screen",
407
+ "suggestion": "Add: group.scale_to_fit_height(config.frame_height - 2.5) after arrange()"
408
+ }},
409
+ {{
410
+ "severity": "high",
411
+ "category": "STATIC_VIDEO",
412
+ "line_range": [1, 100],
413
+ "description": "Only Write() and FadeIn() animations used - video will feel static and boring",
414
+ "suggestion": "Add emphasis animations: Indicate(), Circumscribe(). Use LaggedStart for lists. Add .animate chains for motion."
415
  }}
416
  ],
417
+ "summary": "Found 2 critical issues: content goes off-screen and animations lack variety"
418
  }}
419
  ```
420
  """
manimator/inputs/pdf_parser.py CHANGED
@@ -1,6 +1,6 @@
1
  import logging
2
  from pathlib import Path
3
- from typing import Optional
4
  import PyPDF2
5
 
6
  logger = logging.getLogger(__name__)
@@ -11,7 +11,7 @@ class PDFParser:
11
  """
12
 
13
  @staticmethod
14
- def parse(file_path: str | Path) -> str:
15
  """
16
  Extract text from a PDF file.
17
  """
 
1
  import logging
2
  from pathlib import Path
3
+ from typing import Optional, Union
4
  import PyPDF2
5
 
6
  logger = logging.getLogger(__name__)
 
11
  """
12
 
13
  @staticmethod
14
+ def parse(file_path: Union[str, Path]) -> str:
15
  """
16
  Extract text from a PDF file.
17
  """
manimator/utils/system_prompts.py CHANGED
@@ -65,34 +65,103 @@ MANIM API CONSTRAINTS (CRITICAL - DO NOT HALLUCINATE):
65
  - WHITE, BLACK, RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, PINK, TEAL, GRAY
66
  - For custom colors, use hex strings: "#FF5733"
67
 
68
- **Positioning & Layout (STRICT NO OVERLAPS!)**:
69
- - **CRITICAL**: Objects MUST NOT overlap unless intended (like a background).
70
- - **NEVER** place multiple text objects at the default center without moving them.
71
- - **MANDATORY**: Use `VGroup(obj1, obj2).arrange(DOWN, buff=0.5)` for lists/stacks.
72
- - **MANDATORY**: Use `obj.next_to(other, direction, buff=0.5)` for relative positioning.
73
- - Use `obj.to_edge(UP, buff=1.0)` for titles.
74
- - **AVOID** absolute coordinates like `move_to([3, 2, 0])` for text. It causes overlaps.
75
- - If the screen is full, **FADE OUT** old content before adding new items.
76
-
77
- **Advanced Animations** (Make it look PREMIUM):
78
- - **Transitions**: `TransformMatchingShapes`, `TransformMatchingTex`
79
- - **Creation**: `Write(obj)`, `Create(obj)`, `DrawBorderThenFill(obj)`, `FadeIn(obj, shift=UP)`, `GrowFromCenter(obj)`, `SpinInFromNothing(obj)`
80
- - **Emphasis**: `Indicate(obj)`, `Circumscribe(obj)`, `Wiggle(obj)`, `FocusOn(obj)`
81
- - **Grouping**: `self.play(LaggedStart(*[Write(o) for o in group], lag_ratio=0.1))`
82
- - **Motion**: `self.play(obj.animate.scale(1.2).set_color(RED))`
83
-
84
- **VISUAL ENGAGEMENT RULES (CRITICAL):**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  1. **NO BLANK SCREENS**: NEVER leave the screen empty for more than 0.5 seconds.
86
  - If a voiceover is long, break it up and show corresponding visuals for each part.
87
  - Always have a background or title visible if main content is clearing.
88
  - Use `wait()` only when static visuals are fully present and readable.
 
89
  2. **STRICT NO OVERLAP**:
90
  - Text must NEVER overlap with other text or figures.
91
  - Use `next_to(target, direction, buff=0.5)` to ensure spacing.
92
  - If screen is full, `FadeOut` old content before adding new.
93
- 3. **DYNAMIC FLOW**:
94
- - Avoid static slides. Keep things moving gently if possible.
95
- - Use a variety of animations (not just `Write`). Mix `FadeIn`, `GrowFromCenter`, `DrawBorderThenFill`.
 
 
96
 
97
  {theme_instructions}
98
 
@@ -109,44 +178,64 @@ class GeneratedScene(VoiceoverScene):
109
  # Initialize voiceover
110
  self.set_speech_service(SimpleElevenLabsService(voice_id="Rachel"))
111
 
112
- # --- Section 1: Intro ---
113
- with self.voiceover(text="Let's explore this concept.") as tracker:
114
- title = Text("The Concept", font_size=64, weight=BOLD).to_edge(UP)
115
- self.play(Write(title), run_time=1)
 
 
 
 
 
 
 
 
 
116
 
117
- # --- Section 2: Main Content ---
118
- with self.voiceover(text="Here are the key components.") as tracker:
119
- # Use VGroup for layout safety
120
- item1 = Text("1. First Item", font_size=36)
121
- item2 = Text("2. Second Item", font_size=36)
122
- item3 = Text("3. Third Item", font_size=36)
123
 
124
- group = VGroup(item1, item2, item3).arrange(DOWN, buff=0.5, aligned_edge=LEFT)
125
- group.next_to(title, DOWN, buff=1.0)
 
 
126
 
127
- # Animate with LaggedStart for premium feel
128
- self.play(LaggedStart(*[FadeIn(i, shift=RIGHT) for i in group], lag_ratio=0.3))
 
129
 
130
- # --- Section 3: Detail ---
131
- with self.voiceover(text="Notice how they interact.") as tracker:
132
- self.play(Indicate(item1, color=YELLOW))
133
- self.play(item2.animate.scale(1.1))
 
 
 
 
 
134
 
135
- # Cleanup
136
- self.play(FadeOut(Group(title, group)))
 
 
 
 
137
  ```
138
 
139
  GENERAL BEST PRACTICES:
140
- 1. **Typography**: Use `Text` for labels/headings, `MathTex` ONLY for math. Align text properly (`aligned_edge=LEFT`).
141
- 2. **Visual Hierarchy**: Title (64pt) > Heading (48pt) > Body (36pt) > Label (24pt).
142
  3. **No Overlap**: ALWAYS use `arrange` or `next_to` with `buff`. Check your spacing!
143
  4. **Motion**: Use `shift=UP/DOWN` in `FadeIn` for dynamic entrances. Use `LaggedStart` for lists.
144
- 5. **Cleanliness**: Don't clutter the screen. Fade out old objects before showing new ones.
145
- 6. **NEVER hallucinate parameters**: Only use parameters listed above.
 
146
 
147
  Generate the COMPLETE Python code for the requested topic.
148
  """
149
 
 
150
  SCENE_SYSTEM_PROMPT = """# Content Structure System
151
 
152
  When presented with any research paper, topic, question, or material, transform it into the following structured format:
 
65
  - WHITE, BLACK, RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, PINK, TEAL, GRAY
66
  - For custom colors, use hex strings: "#FF5733"
67
 
68
+ # ============================================================================
69
+ # 🚨 CRITICAL: SCREEN BOUNDARY RULES (CONTENT MUST STAY ON SCREEN!)
70
+ # ============================================================================
71
+
72
+ **The screen has STRICT boundaries. Content going off-screen is a CRITICAL ERROR.**
73
+
74
+ 1. **MANDATORY SCALING**: After creating any VGroup with multiple items, ALWAYS scale to fit:
75
+ ```python
76
+ # ALWAYS do this for groups with 3+ items:
77
+ group = VGroup(item1, item2, item3, item4).arrange(DOWN, buff=0.3)
78
+ group.scale_to_fit_height(config.frame_height - 2.5) # Leave 1.25 margin top/bottom
79
+ group.scale_to_fit_width(config.frame_width - 2) # Leave 1 margin left/right
80
+ ```
81
+
82
+ 2. **LIMIT ITEMS PER SCREEN**:
83
+ - Maximum 4-5 items visible at once with title
84
+ - Maximum 6 items if no title
85
+ - If more items needed: use PAGINATION (show items in batches, FadeOut old, FadeIn new)
86
+
87
+ 3. **SAFE ZONES**: Always leave margins:
88
+ - Top: 1.0 unit buffer (for title)
89
+ - Bottom: 0.8 unit buffer
90
+ - Left/Right: 0.5 unit buffer each
91
+ - Use: `group.move_to(ORIGIN).shift(DOWN * 0.5)` to center in safe zone
92
+
93
+ 4. **CHECK BOUNDS AFTER POSITIONING**:
94
+ ```python
95
+ # After arranging, if content is tall, scale it:
96
+ if group.height > config.frame_height - 2:
97
+ group.scale_to_fit_height(config.frame_height - 2.5)
98
+ ```
99
+
100
+ 5. **SMALLER FONT FOR LISTS**: When showing 4+ items, use smaller fonts:
101
+ - Title: 48pt (not 64)
102
+ - Items: 28-32pt (not 36-48)
103
+
104
+ # ============================================================================
105
+ # 🎬 CRITICAL: DYNAMIC ANIMATION RULES (NO STATIC/BORING VIDEOS!)
106
+ # ============================================================================
107
+
108
+ **Videos MUST be dynamic and engaging. Static slides are UNACCEPTABLE.**
109
+
110
+ 1. **ANIMATION VARIETY (MANDATORY)**:
111
+ - NEVER use only `Write()` - mix at least 3-4 different animation types
112
+ - Use: `FadeIn(shift=UP/DOWN/LEFT/RIGHT)`, `GrowFromCenter`, `DrawBorderThenFill`, `SpinInFromNothing`
113
+ - For lists: ALWAYS use `LaggedStart` with `lag_ratio=0.15-0.3`
114
+
115
+ 2. **CONTINUOUS MOTION**:
116
+ - Objects should move/transform, not just appear
117
+ - Use `.animate` chains: `obj.animate.scale(1.1).shift(UP*0.2).set_color(YELLOW)`
118
+ - Add subtle motion during voiceover: `self.play(obj.animate.scale(1.05), run_time=2)`
119
+
120
+ 3. **EMPHASIS ANIMATIONS (USE FREQUENTLY)**:
121
+ - `Indicate(obj, color=YELLOW, scale_factor=1.2)` - highlight important items
122
+ - `Circumscribe(obj, color=YELLOW)` - draw attention
123
+ - `Flash(obj, color=WHITE)` - quick flash effect
124
+ - `Wiggle(obj)` - playful emphasis
125
+ - `FocusOn(point)` - zoom focus effect
126
+
127
+ 4. **TRANSITIONS BETWEEN SECTIONS**:
128
+ - NEVER just `FadeOut` and `FadeIn` - use creative transitions
129
+ - `TransformMatchingShapes(old_group, new_group)` - morph between similar objects
130
+ - `ReplacementTransform(old, new)` - smooth replacement
131
+ - Slide transitions: `FadeOut(old, shift=LEFT), FadeIn(new, shift=RIGHT)`
132
+
133
+ 5. **PARALLEL ANIMATIONS**:
134
+ - Combine multiple animations: `self.play(Write(text), Create(circle), run_time=1.5)`
135
+ - Use `AnimationGroup` for complex choreography
136
+
137
+ 6. **BACKGROUND ANIMATIONS** (optional but recommended):
138
+ - Subtle floating particles, pulsing backgrounds, moving grid lines
139
+ - Keep the screen alive even when explaining
140
+
141
+ 7. **TIMING**:
142
+ - Short animations: 0.5-1.0 seconds
143
+ - Standard: 1.0-1.5 seconds
144
+ - Complex: 2.0-3.0 seconds
145
+ - AVOID `self.wait()` longer than 0.5 seconds - always show something moving
146
+
147
+ # ============================================================================
148
+ # VISUAL ENGAGEMENT RULES
149
+ # ============================================================================
150
+
151
  1. **NO BLANK SCREENS**: NEVER leave the screen empty for more than 0.5 seconds.
152
  - If a voiceover is long, break it up and show corresponding visuals for each part.
153
  - Always have a background or title visible if main content is clearing.
154
  - Use `wait()` only when static visuals are fully present and readable.
155
+
156
  2. **STRICT NO OVERLAP**:
157
  - Text must NEVER overlap with other text or figures.
158
  - Use `next_to(target, direction, buff=0.5)` to ensure spacing.
159
  - If screen is full, `FadeOut` old content before adding new.
160
+
161
+ 3. **PACING**:
162
+ - Show 2-3 items, then emphasize/animate them
163
+ - Clear screen and move to next batch
164
+ - Each screen should have a "moment" - an emphasis animation
165
 
166
  {theme_instructions}
167
 
 
178
  # Initialize voiceover
179
  self.set_speech_service(SimpleElevenLabsService(voice_id="Rachel"))
180
 
181
+ # --- Section 1: Intro with Dynamic Animation ---
182
+ with self.voiceover(text="Let's explore this fascinating concept.") as tracker:
183
+ title = Text("The Concept", font_size=48, weight=BOLD).to_edge(UP, buff=0.8)
184
+ self.play(FadeIn(title, shift=DOWN), run_time=1)
185
+ self.play(Indicate(title, color=YELLOW, scale_factor=1.1))
186
+
187
+ # --- Section 2: Main Content with Safe Boundaries ---
188
+ with self.voiceover(text="Here are the key components of this system.") as tracker:
189
+ # Create items with smaller font for multiple items
190
+ items = VGroup(*[
191
+ Text(f"{{i+1}}. Item {{i+1}} Description", font_size=28)
192
+ for i in range(4)
193
+ ]).arrange(DOWN, buff=0.4, aligned_edge=LEFT)
194
 
195
+ # 🚨 CRITICAL: Scale to fit screen with margins
196
+ items.scale_to_fit_height(config.frame_height - 3.5)
197
+ items.next_to(title, DOWN, buff=0.8)
 
 
 
198
 
199
+ # Animate with variety using LaggedStart
200
+ self.play(LaggedStart(*[
201
+ FadeIn(item, shift=RIGHT*0.5) for item in items
202
+ ], lag_ratio=0.2))
203
 
204
+ # Add emphasis animations
205
+ for item in items:
206
+ self.play(Indicate(item, scale_factor=1.05), run_time=0.3)
207
 
208
+ # --- Section 3: Transform/Transition ---
209
+ with self.voiceover(text="Watch how these elements interact.") as tracker:
210
+ # Creative transition
211
+ self.play(
212
+ items[0].animate.scale(1.2).set_color(YELLOW),
213
+ items[1:].animate.set_opacity(0.5),
214
+ run_time=1
215
+ )
216
+ self.play(Circumscribe(items[0], color=YELLOW))
217
 
218
+ # Cleanup with slide transition
219
+ self.play(
220
+ FadeOut(title, shift=UP),
221
+ FadeOut(items, shift=DOWN),
222
+ run_time=0.8
223
+ )
224
  ```
225
 
226
  GENERAL BEST PRACTICES:
227
+ 1. **Typography**: Use smaller fonts (28-36pt) for lists. Title max 48-56pt.
228
+ 2. **Visual Hierarchy**: Title > Heading > Body > Label. But keep all readable.
229
  3. **No Overlap**: ALWAYS use `arrange` or `next_to` with `buff`. Check your spacing!
230
  4. **Motion**: Use `shift=UP/DOWN` in `FadeIn` for dynamic entrances. Use `LaggedStart` for lists.
231
+ 5. **Screen Bounds**: ALWAYS `scale_to_fit_height/width` for groups with 4+ items.
232
+ 6. **Animation Variety**: Mix at least 4 different animation types per video.
233
+ 7. **NEVER hallucinate parameters**: Only use parameters listed above.
234
 
235
  Generate the COMPLETE Python code for the requested topic.
236
  """
237
 
238
+
239
  SCENE_SYSTEM_PROMPT = """# Content Structure System
240
 
241
  When presented with any research paper, topic, question, or material, transform it into the following structured format:
requirements.txt CHANGED
@@ -8,4 +8,7 @@ manim==0.18.1
8
  pypdf2==3.0.1
9
  gradio
10
  streamlit
11
- requests
 
 
 
 
8
  pypdf2==3.0.1
9
  gradio
10
  streamlit
11
+ requests
12
+ beautifulsoup4>=4.12.0
13
+ lxml>=4.9.0
14
+ readability-lxml>=0.8.1
streamlit_app.py CHANGED
@@ -18,6 +18,10 @@ import asyncio
18
  from pathlib import Path
19
  from datetime import datetime
20
 
 
 
 
 
21
  # Check if we're in direct mode (for Hugging Face deployment)
22
  DIRECT_MODE = os.getenv("DIRECT_MODE", "true").lower() == "true"
23
 
@@ -29,55 +33,343 @@ st.set_page_config(
29
  initial_sidebar_state="expanded"
30
  )
31
 
32
- # Custom CSS for better aesthetics
33
  st.markdown("""
34
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  .stApp {
36
- background-color: #0e1117;
37
- color: #fafafa;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  .stButton>button {
40
- background-color: #ff4b4b;
41
- color: white;
42
- border-radius: 20px;
43
- padding: 10px 24px;
44
- font-weight: bold;
 
45
  border: none;
46
- transition: all 0.3s ease;
 
 
 
47
  }
 
48
  .stButton>button:hover {
49
- background-color: #ff3333;
50
- transform: scale(1.05);
51
  }
52
- .stTextInput>div>div>input {
53
- border-radius: 10px;
 
54
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  .stTextArea>div>div>textarea {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  border-radius: 10px;
57
  }
58
- .css-1d391kg {
59
- padding-top: 3rem;
 
 
60
  }
61
- .status-box {
62
- padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
63
  border-radius: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  margin: 1rem 0;
 
 
 
65
  }
 
66
  .status-generating {
67
- background-color: #1e3a5f;
68
- border-left: 4px solid #3b82f6;
 
69
  }
 
70
  .status-rendering {
71
- background-color: #1e3a5f;
72
- border-left: 4px solid #f59e0b;
 
73
  }
 
74
  .status-complete {
75
- background-color: #1a3d2e;
76
- border-left: 4px solid #10b981;
 
77
  }
 
78
  .status-error {
79
- background-color: #3d1a1a;
80
- border-left: 4px solid #ef4444;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  }
82
  </style>
83
  """, unsafe_allow_html=True)
 
18
  from pathlib import Path
19
  from datetime import datetime
20
 
21
+ # Load environment variables from .env file
22
+ from dotenv import load_dotenv
23
+ load_dotenv()
24
+
25
  # Check if we're in direct mode (for Hugging Face deployment)
26
  DIRECT_MODE = os.getenv("DIRECT_MODE", "true").lower() == "true"
27
 
 
33
  initial_sidebar_state="expanded"
34
  )
35
 
36
+ # Custom CSS - Premium Techy Design
37
  st.markdown("""
38
  <style>
39
+ /* ========================================
40
+ HIDE STREAMLIT DEFAULT ELEMENTS
41
+ ======================================== */
42
+ #MainMenu {visibility: hidden;}
43
+ footer {visibility: hidden;}
44
+ header {visibility: hidden;}
45
+
46
+ /* Hide the deploy button and hamburger menu */
47
+ .stDeployButton {display: none;}
48
+ [data-testid="stToolbar"] {display: none;}
49
+ [data-testid="stDecoration"] {display: none;}
50
+ [data-testid="stStatusWidget"] {display: none;}
51
+
52
+ /* Remove top padding */
53
+ .block-container {
54
+ padding-top: 1rem !important;
55
+ }
56
+
57
+ /* ========================================
58
+ MAIN APP - CYBER DARK THEME
59
+ ======================================== */
60
  .stApp {
61
+ background: linear-gradient(135deg, #0a0a1a 0%, #0f0f2d 50%, #0a0a1a 100%);
62
+ color: #e0e0ff;
63
+ }
64
+
65
+ /* Subtle animated background grid */
66
+ .stApp::before {
67
+ content: "";
68
+ position: fixed;
69
+ top: 0;
70
+ left: 0;
71
+ width: 100%;
72
+ height: 100%;
73
+ background-image:
74
+ linear-gradient(rgba(99, 102, 241, 0.03) 1px, transparent 1px),
75
+ linear-gradient(90deg, rgba(99, 102, 241, 0.03) 1px, transparent 1px);
76
+ background-size: 50px 50px;
77
+ pointer-events: none;
78
+ z-index: -1;
79
+ }
80
+
81
+ /* All text should be light */
82
+ .stApp p, .stApp span, .stApp label, .stApp div {
83
+ color: #e0e0ff !important;
84
+ }
85
+
86
+ /* ========================================
87
+ SIDEBAR - GLASSMORPHISM STYLE
88
+ ======================================== */
89
+ [data-testid="stSidebar"] {
90
+ background: linear-gradient(180deg, rgba(20, 20, 45, 0.95) 0%, rgba(15, 15, 35, 0.98) 100%) !important;
91
+ backdrop-filter: blur(20px);
92
+ border-right: 1px solid rgba(99, 102, 241, 0.2);
93
  }
94
+
95
+ [data-testid="stSidebar"] * {
96
+ color: #e0e0ff !important;
97
+ }
98
+
99
+ /* Sidebar title styling */
100
+ [data-testid="stSidebar"] h1 {
101
+ background: linear-gradient(90deg, #818cf8 0%, #c084fc 50%, #f472b6 100%);
102
+ -webkit-background-clip: text;
103
+ -webkit-text-fill-color: transparent;
104
+ background-clip: text;
105
+ font-weight: 700 !important;
106
+ }
107
+
108
+ /* Mode indicator - glowing badge */
109
+ [data-testid="stSidebar"] .stSuccess {
110
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(52, 211, 153, 0.1) 100%) !important;
111
+ border: 1px solid rgba(16, 185, 129, 0.4) !important;
112
+ border-radius: 12px !important;
113
+ box-shadow: 0 0 20px rgba(16, 185, 129, 0.15);
114
+ }
115
+
116
+ [data-testid="stSidebar"] .stInfo {
117
+ background: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(139, 92, 246, 0.1) 100%) !important;
118
+ border: 1px solid rgba(99, 102, 241, 0.4) !important;
119
+ border-radius: 12px !important;
120
+ box-shadow: 0 0 20px rgba(99, 102, 241, 0.15);
121
+ }
122
+
123
+ /* Section headers in sidebar */
124
+ [data-testid="stSidebar"] .stMarkdown h3 {
125
+ color: #a5b4fc !important;
126
+ font-size: 0.85rem !important;
127
+ text-transform: uppercase;
128
+ letter-spacing: 1.5px;
129
+ margin-top: 1.5rem !important;
130
+ }
131
+
132
+ /* ========================================
133
+ BUTTONS - NEON GLOW STYLE
134
+ ======================================== */
135
  .stButton>button {
136
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
137
+ color: white !important;
138
+ border-radius: 12px;
139
+ padding: 14px 32px;
140
+ font-weight: 600;
141
+ font-size: 16px;
142
  border: none;
143
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
144
+ box-shadow: 0 4px 20px rgba(99, 102, 241, 0.4);
145
+ position: relative;
146
+ overflow: hidden;
147
  }
148
+
149
  .stButton>button:hover {
150
+ transform: translateY(-3px);
151
+ box-shadow: 0 8px 30px rgba(139, 92, 246, 0.5);
152
  }
153
+
154
+ .stButton>button:active {
155
+ transform: translateY(-1px);
156
  }
157
+
158
+ /* Download button - cyan neon */
159
+ .stDownloadButton>button {
160
+ background: linear-gradient(135deg, #06b6d4 0%, #22d3ee 50%, #67e8f9 100%) !important;
161
+ color: #0a0a1a !important;
162
+ font-weight: 700 !important;
163
+ border-radius: 12px;
164
+ padding: 14px 32px;
165
+ border: none;
166
+ box-shadow: 0 4px 20px rgba(6, 182, 212, 0.4);
167
+ }
168
+
169
+ .stDownloadButton>button:hover {
170
+ transform: translateY(-3px);
171
+ box-shadow: 0 8px 30px rgba(34, 211, 238, 0.5);
172
+ }
173
+
174
+ /* ========================================
175
+ INPUT FIELDS - GLASS CARDS
176
+ ======================================== */
177
+ .stTextInput>div>div>input,
178
  .stTextArea>div>div>textarea {
179
+ background: rgba(20, 20, 50, 0.6) !important;
180
+ color: #ffffff !important;
181
+ border: 1px solid rgba(99, 102, 241, 0.3) !important;
182
+ border-radius: 12px;
183
+ backdrop-filter: blur(10px);
184
+ transition: all 0.3s ease;
185
+ }
186
+
187
+ .stTextInput>div>div>input:focus,
188
+ .stTextArea>div>div>textarea:focus {
189
+ border-color: #8b5cf6 !important;
190
+ box-shadow: 0 0 20px rgba(139, 92, 246, 0.3) !important;
191
+ }
192
+
193
+ .stTextInput>div>div>input::placeholder,
194
+ .stTextArea>div>div>textarea::placeholder {
195
+ color: #6b7280 !important;
196
+ }
197
+
198
+ /* ========================================
199
+ SELECTBOX / DROPDOWN
200
+ ======================================== */
201
+ .stSelectbox>div>div {
202
+ background: rgba(20, 20, 50, 0.6) !important;
203
+ border: 1px solid rgba(99, 102, 241, 0.3) !important;
204
  border-radius: 10px;
205
  }
206
+
207
+ .stSelectbox label {
208
+ color: #a5b4fc !important;
209
+ font-weight: 500;
210
  }
211
+
212
+ /* ========================================
213
+ TABS - PILL STYLE
214
+ ======================================== */
215
+ .stTabs [data-baseweb="tab-list"] {
216
+ gap: 8px;
217
+ background: transparent;
218
+ padding: 4px;
219
+ }
220
+
221
+ .stTabs [data-baseweb="tab"] {
222
+ background: rgba(20, 20, 50, 0.6);
223
+ border: 1px solid rgba(99, 102, 241, 0.2);
224
  border-radius: 10px;
225
+ color: #a5b4fc !important;
226
+ padding: 12px 24px;
227
+ transition: all 0.3s ease;
228
+ }
229
+
230
+ .stTabs [data-baseweb="tab"]:hover {
231
+ background: rgba(99, 102, 241, 0.1);
232
+ border-color: rgba(99, 102, 241, 0.4);
233
+ }
234
+
235
+ .stTabs [aria-selected="true"] {
236
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
237
+ border-color: transparent !important;
238
+ color: white !important;
239
+ box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
240
+ }
241
+
242
+ /* ========================================
243
+ HEADERS - GRADIENT TEXT
244
+ ======================================== */
245
+ h1 {
246
+ background: linear-gradient(90deg, #818cf8 0%, #c084fc 50%, #f472b6 100%);
247
+ -webkit-background-clip: text;
248
+ -webkit-text-fill-color: transparent;
249
+ background-clip: text;
250
+ font-weight: 800 !important;
251
+ font-size: 2.5rem !important;
252
+ }
253
+
254
+ h2, h3, h4, h5, h6 {
255
+ color: #e0e0ff !important;
256
+ }
257
+
258
+ /* ========================================
259
+ STATUS BOXES - GLOWING CARDS
260
+ ======================================== */
261
+ .status-box {
262
+ padding: 1.25rem;
263
+ border-radius: 16px;
264
  margin: 1rem 0;
265
+ color: #ffffff !important;
266
+ backdrop-filter: blur(10px);
267
+ border: 1px solid;
268
  }
269
+
270
  .status-generating {
271
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
272
+ border-color: rgba(59, 130, 246, 0.4);
273
+ box-shadow: 0 0 25px rgba(59, 130, 246, 0.15);
274
  }
275
+
276
  .status-rendering {
277
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.15) 0%, rgba(251, 191, 36, 0.1) 100%);
278
+ border-color: rgba(245, 158, 11, 0.4);
279
+ box-shadow: 0 0 25px rgba(245, 158, 11, 0.15);
280
  }
281
+
282
  .status-complete {
283
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(52, 211, 153, 0.1) 100%);
284
+ border-color: rgba(16, 185, 129, 0.4);
285
+ box-shadow: 0 0 25px rgba(16, 185, 129, 0.15);
286
  }
287
+
288
  .status-error {
289
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.15) 0%, rgba(248, 113, 113, 0.1) 100%);
290
+ border-color: rgba(239, 68, 68, 0.4);
291
+ box-shadow: 0 0 25px rgba(239, 68, 68, 0.15);
292
+ }
293
+
294
+ /* ========================================
295
+ PROGRESS BAR - ANIMATED GRADIENT
296
+ ======================================== */
297
+ .stProgress > div > div > div > div {
298
+ background: linear-gradient(90deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
299
+ border-radius: 10px;
300
+ }
301
+
302
+ .stProgress > div > div > div {
303
+ background: rgba(99, 102, 241, 0.1);
304
+ border-radius: 10px;
305
+ }
306
+
307
+ /* ========================================
308
+ FILE UPLOADER
309
+ ======================================== */
310
+ [data-testid="stFileUploader"] {
311
+ background: rgba(20, 20, 50, 0.6);
312
+ border: 1px dashed rgba(99, 102, 241, 0.4);
313
+ border-radius: 16px;
314
+ padding: 1.5rem;
315
+ transition: all 0.3s ease;
316
+ }
317
+
318
+ [data-testid="stFileUploader"]:hover {
319
+ border-color: #8b5cf6;
320
+ box-shadow: 0 0 20px rgba(139, 92, 246, 0.2);
321
+ }
322
+
323
+ [data-testid="stFileUploader"] label {
324
+ color: #a5b4fc !important;
325
+ }
326
+
327
+ /* ========================================
328
+ VIDEO PLAYER - PREMIUM FRAME
329
+ ======================================== */
330
+ video {
331
+ border-radius: 16px;
332
+ box-shadow:
333
+ 0 20px 50px rgba(0, 0, 0, 0.5),
334
+ 0 0 0 1px rgba(99, 102, 241, 0.2);
335
+ }
336
+
337
+ /* ========================================
338
+ ALERTS - GLASS STYLE
339
+ ======================================== */
340
+ .stAlert {
341
+ background: rgba(20, 20, 50, 0.8) !important;
342
+ border: 1px solid rgba(99, 102, 241, 0.3) !important;
343
+ border-radius: 12px;
344
+ backdrop-filter: blur(10px);
345
+ }
346
+
347
+ /* ========================================
348
+ DIVIDERS
349
+ ======================================== */
350
+ hr {
351
+ border-color: rgba(99, 102, 241, 0.2) !important;
352
+ }
353
+
354
+ /* ========================================
355
+ SCROLLBAR - MINIMAL STYLE
356
+ ======================================== */
357
+ ::-webkit-scrollbar {
358
+ width: 8px;
359
+ height: 8px;
360
+ }
361
+
362
+ ::-webkit-scrollbar-track {
363
+ background: rgba(20, 20, 50, 0.3);
364
+ }
365
+
366
+ ::-webkit-scrollbar-thumb {
367
+ background: linear-gradient(180deg, #6366f1 0%, #8b5cf6 100%);
368
+ border-radius: 4px;
369
+ }
370
+
371
+ ::-webkit-scrollbar-thumb:hover {
372
+ background: linear-gradient(180deg, #818cf8 0%, #a855f7 100%);
373
  }
374
  </style>
375
  """, unsafe_allow_html=True)