devendergarg14 commited on
Commit
4b9f75c
·
verified ·
1 Parent(s): 9563797

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -12
app.py CHANGED
@@ -5,11 +5,57 @@ import re
5
  import time
6
  import glob
7
  import shutil
 
 
 
 
 
8
 
9
  # ---------------------------------------------------------
10
  # 1. Helper Functions (Dependencies for Rendering)
11
  # ---------------------------------------------------------
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def cleanup_media_directory():
14
  """Wipes the media directory to prevent caching issues."""
15
  media_dir = 'media'
@@ -115,15 +161,17 @@ def run_manim(code_str, orientation, quality, timeout):
115
 
116
  # Strategy B: Look for a Static Image (.png) and convert to Video
117
  media_image_base = os.path.join("media", "images", "scene")
118
- expected_image_name = output_filename + ".png"
119
  found_image_path = None
120
 
121
  if os.path.exists(media_image_base):
122
  for root, _, files in os.walk(media_image_base):
123
- if expected_image_name in files:
124
- found_image_path = os.path.join(root, expected_image_name)
125
- break
126
-
 
 
127
  if found_image_path:
128
  print(f"🖼️ Static scene detected (0 animations). converting image to video: {found_image_path}", flush=True)
129
  converted_video_path = os.path.join(os.path.dirname(found_image_path), output_filename)
@@ -151,6 +199,16 @@ def run_manim(code_str, orientation, quality, timeout):
151
  def render_video_from_code(code, orientation, quality, timeout, preview_factor):
152
  """Renders a video from a given Manim code string."""
153
  try:
 
 
 
 
 
 
 
 
 
 
154
  cleanup_media_directory()
155
 
156
  if not code or "from manim import" not in code:
@@ -184,16 +242,16 @@ class GenScene(Scene):
184
  """
185
 
186
  with gr.Blocks(title="Manim Render API") as demo:
187
- # Hidden components to define the API signature
188
- code_input = gr.Code(label="Python Code", language="python", value=DEFAULT_CODE,visible=False)
189
- orientation_opt = gr.Radio(choices=["Landscape (16:9)", "Portrait (9:16)"], value="Portrait (9:16)", label="Orientation",visible=False)
190
- quality_opt = gr.Dropdown(choices=["Preview (360p)", "480p", "720p", "1080p", "4k"], value="Preview (360p)", label="Quality", visible=False)
191
- timeout_input = gr.Number(label="Render Timeout (seconds)", value=60, visible=False)
192
- preview_speed_factor_input = gr.Number(label="Preview Speed Factor", value=0.5,visible=False)
193
 
194
  video_output = gr.Video(label="Result")
195
  status_output = gr.Textbox(label="Status/Logs")
196
- fix_btn_output = gr.Button("Fix Error & Re-render", variant="stop",visible=False)
197
 
198
  render_btn = gr.Button("Render")
199
 
 
5
  import time
6
  import glob
7
  import shutil
8
+ # --- START: New Imports for Pyflakes Integration ---
9
+ from pyflakes.api import check
10
+ from pyflakes.reporter import Reporter
11
+ import io
12
+ # --- END: New Imports ---
13
 
14
  # ---------------------------------------------------------
15
  # 1. Helper Functions (Dependencies for Rendering)
16
  # ---------------------------------------------------------
17
 
18
+ class ErrorReporter(Reporter):
19
+ """Custom reporter to capture pyflakes errors into a list."""
20
+ def __init__(self):
21
+ self.errors = []
22
+ # Suppress the default print-to-stdout behavior
23
+ super().__init__(io.StringIO(), io.StringIO())
24
+
25
+ def unexpectedError(self, filename, msg):
26
+ self.errors.append(f"Unexpected Error in {filename}: {msg}")
27
+
28
+ def syntaxError(self, filename, msg, lineno, offset, text):
29
+ self.errors.append(f"Syntax Error in {filename} (Line {lineno}): {msg}")
30
+
31
+ def flake(self, message):
32
+ self.errors.append(str(message))
33
+
34
+ def check_code_with_pyflakes(code_str: str) -> str:
35
+ """
36
+ Analyzes a string of Python code using pyflakes and returns a formatted error report.
37
+ Returns an empty string if no errors are found.
38
+ """
39
+ reporter = ErrorReporter()
40
+ check(code_str, "scene.py", reporter=reporter)
41
+
42
+ if not reporter.errors:
43
+ return "" # No errors found
44
+
45
+ # Format the error list into a user-friendly string
46
+ error_report = "Static analysis found potential errors:\n"
47
+ for err in reporter.errors:
48
+ # Example raw error: 'scene.py:5:21: undefined name 'Cirle''
49
+ match = re.search(r'scene\.py:(\d+):.*(undefined name.*)', str(err))
50
+ if match:
51
+ line_num = match.group(1)
52
+ error_msg = match.group(2)
53
+ error_report += f"- Line {line_num}: {error_msg}\n"
54
+ else:
55
+ error_report += f"- {err}\n"
56
+
57
+ return error_report
58
+
59
  def cleanup_media_directory():
60
  """Wipes the media directory to prevent caching issues."""
61
  media_dir = 'media'
 
161
 
162
  # Strategy B: Look for a Static Image (.png) and convert to Video
163
  media_image_base = os.path.join("media", "images", "scene")
164
+ expected_image_name = output_filename.replace('.mp4', '.png')
165
  found_image_path = None
166
 
167
  if os.path.exists(media_image_base):
168
  for root, _, files in os.walk(media_image_base):
169
+ # Manim Community v0.18.0 changed naming for -o. Let's find the single png.
170
+ png_files = [f for f in files if f.endswith(".png")]
171
+ if len(png_files) == 1:
172
+ found_image_path = os.path.join(root, png_files[0])
173
+ break
174
+
175
  if found_image_path:
176
  print(f"🖼️ Static scene detected (0 animations). converting image to video: {found_image_path}", flush=True)
177
  converted_video_path = os.path.join(os.path.dirname(found_image_path), output_filename)
 
199
  def render_video_from_code(code, orientation, quality, timeout, preview_factor):
200
  """Renders a video from a given Manim code string."""
201
  try:
202
+ # --- START: Integrated Pyflakes Pre-Check ---
203
+ print("🕵️ Running static analysis with pyflakes...", flush=True)
204
+ static_errors = check_code_with_pyflakes(code)
205
+ if static_errors:
206
+ print(f"❌ Static analysis failed:\n{static_errors}", flush=True)
207
+ # Return the error report immediately without trying to render
208
+ return None, static_errors, gr.Button(visible=True)
209
+ print("✅ Static analysis passed.", flush=True)
210
+ # --- END: Integrated Pyflakes Pre-Check ---
211
+
212
  cleanup_media_directory()
213
 
214
  if not code or "from manim import" not in code:
 
242
  """
243
 
244
  with gr.Blocks(title="Manim Render API") as demo:
245
+ # Components are now visible for direct interaction
246
+ code_input = gr.Code(label="Python Code", language="python", value=DEFAULT_CODE, visible=True)
247
+ orientation_opt = gr.Radio(choices=["Landscape (16:9)", "Portrait (9:16)"], value="Portrait (9:16)", label="Orientation", visible=True)
248
+ quality_opt = gr.Dropdown(choices=["Preview (360p)", "480p", "720p", "1080p", "4k"], value="Preview (360p)", label="Quality", visible=True)
249
+ timeout_input = gr.Number(label="Render Timeout (seconds)", value=60, visible=True)
250
+ preview_speed_factor_input = gr.Number(label="Preview Speed Factor", value=0.5, visible=True)
251
 
252
  video_output = gr.Video(label="Result")
253
  status_output = gr.Textbox(label="Status/Logs")
254
+ fix_btn_output = gr.Button("Fix Error & Re-render", variant="stop", visible=True)
255
 
256
  render_btn = gr.Button("Render")
257