devendergarg14 commited on
Commit
2533600
·
verified ·
1 Parent(s): 9b3ed18

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -49
app.py CHANGED
@@ -5,55 +5,60 @@ import re
5
  import time
6
  import glob
7
  import shutil
8
- # --- START: Corrected Ruff Integration ---
9
- # Note: You must run 'pip install ruff'
10
- import ruff
11
- # --- END: Corrected Ruff Integration ---
12
-
13
 
14
  # ---------------------------------------------------------
15
  # 1. Helper Functions (Dependencies for Rendering)
16
  # ---------------------------------------------------------
17
 
18
- def check_code_with_ruff(code_str: str) -> str:
19
  """
20
- Analyzes code using the high-performance Ruff linter.
21
- This is configured to ignore warnings about star imports (`from manim import *`)
22
- but will reliably catch definite NameErrors (e.g., 'Cirle', 'CENTER', 'BLE').
 
23
  """
24
- print("🕵️ Running fast pre-check with Ruff...", flush=True)
25
 
26
- # Configure Ruff to ignore star-import warnings (F403, F405)
27
- # but to catch everything else, including undefined names (F821).
28
- settings = {
29
- "ignore": ["F403", "F405"]
30
- }
 
 
 
 
 
 
 
 
 
31
 
32
  try:
33
- # Use the official 'ruff.check' API, passing the code as 'contents'
34
- diagnostics = ruff.check(contents=code_str, settings=settings, filename="scene.py")
35
-
36
- if not diagnostics:
37
- return "" # No errors found
38
-
39
- error_report = "Static analysis found potential errors:\n"
40
- for diag in diagnostics:
41
- # The diagnostic object has a slightly different structure
42
- error_report += f"- Line {diag.location.row}: {diag.body} ({diag.code})\n"
43
 
44
- return error_report
45
-
46
- except Exception as e:
47
- # Fallback in case Ruff itself has an issue
48
- print(f"⚠️ Ruff pre-check encountered an internal error: {e}", flush=True)
49
- return "" # Allow render to proceed, don't block on linter failure
 
 
 
 
 
 
 
 
50
 
51
  def cleanup_media_directory():
52
  """Wipes the media directory to prevent caching issues."""
53
  media_dir = 'media'
54
  if os.path.exists(media_dir):
55
  try: shutil.rmtree(media_dir)
56
- except OSError as e: print(f"⚠️ Warning during cleanup: {e}", flush=True)
57
 
58
  def make_even(n):
59
  n = int(n)
@@ -70,7 +75,7 @@ def get_resolution_flags(orientation, quality):
70
 
71
  def scale_animation_times(code, factor):
72
  """Scales run_time and wait() calls."""
73
- print(f" Scaling animation times by a factor of {factor} for preview.", flush=True)
74
  MIN_RUN_TIME = 0.1
75
  def scale(m, is_wait):
76
  val = float(m.group(2)) * factor
@@ -81,7 +86,7 @@ def scale_animation_times(code, factor):
81
 
82
  def run_manim(code_str, orientation, quality, timeout):
83
  timeout_sec = float(timeout) if timeout and float(timeout) > 0 else None
84
- print(f"🎬 Starting Full Render: {orientation} @ {quality} (Timeout: {timeout_sec}s)...", flush=True)
85
 
86
  with open("scene.py", "w", encoding="utf-8") as f: f.write(code_str)
87
 
@@ -92,7 +97,7 @@ def run_manim(code_str, orientation, quality, timeout):
92
  frame_rate_flags = ["--frame_rate", "15"] if quality == "Preview (360p)" else []
93
  cmd = ["manim", "--resolution", res_str, *frame_rate_flags, "--disable_caching",
94
  "--progress_bar", "none", "scene.py", "GenScene", "-o", output_filename]
95
- print(f"⚙️ Running command: {' '.join(cmd)}", flush=True)
96
 
97
  try:
98
  process = subprocess.run(cmd, capture_output=True, timeout=timeout_sec, check=False)
@@ -100,22 +105,22 @@ def run_manim(code_str, orientation, quality, timeout):
100
  full_logs = f"--- MANIM STDOUT ---\n{stdout_log}\n\n--- MANIM STDERR ---\n{stderr_log}"
101
 
102
  if process.returncode != 0:
103
- print(f" Render Failed.\n{stderr_log}", flush=True)
104
- return None, f"⚠️ ERROR: Manim failed to render.\n{full_logs}", False
105
  except subprocess.TimeoutExpired as e:
106
- print(f" Render timed out after {timeout_sec} seconds.", flush=True)
107
  stdout_log, stderr_log = (e.stdout.decode('utf-8', 'ignore') if e.stdout else ""), (e.stderr.decode('utf-8', 'ignore') if e.stderr else "")
108
- return None, f" ERROR: Timed out.\n--- MANIM STDOUT ---\n{stdout_log}\n\n--- MANIM STDERR ---\n{stderr_log}", False
109
 
110
  media_video_base = os.path.join("media", "videos", "scene")
111
  if os.path.exists(media_video_base):
112
  for root, _, files in os.walk(media_video_base):
113
  if output_filename in files:
114
  found_video_path = os.path.join(root, output_filename)
115
- print(f" Video Render Success: {found_video_path}", flush=True)
116
- return found_video_path, f" Rendering Successful\n\n{full_logs}", True
117
 
118
- print(f" Final output file '{output_filename}' not found.", flush=True)
119
  return None, f"Video file not created despite success code. Check logs:\n{full_logs}", False
120
 
121
  # ---------------------------------------------------------
@@ -125,13 +130,11 @@ def run_manim(code_str, orientation, quality, timeout):
125
  def render_video_from_code(code, orientation, quality, timeout, preview_factor):
126
  """Renders a video from a given Manim code string."""
127
  try:
128
- # --- START: New Ruff Pre-Check ---
129
- ruff_errors = check_code_with_ruff(code)
130
- if ruff_errors:
131
- print(f"❌ Ruff pre-check failed:\n{ruff_errors}", flush=True)
132
- return None, ruff_errors, gr.Button(visible=True)
133
- print("✅ Ruff pre-check passed. Code is valid.", flush=True)
134
- # --- END: New Ruff Pre-Check ---
135
 
136
  cleanup_media_directory()
137
  if not code or "from manim import" not in code:
 
5
  import time
6
  import glob
7
  import shutil
 
 
 
 
 
8
 
9
  # ---------------------------------------------------------
10
  # 1. Helper Functions (Dependencies for Rendering)
11
  # ---------------------------------------------------------
12
 
13
+ def run_manim_pre_check(code_str: str) -> (bool, str):
14
  """
15
+ Runs Manim with the '-s' flag to perform a fast, reliable pre-check.
16
+ This executes the Python code without rendering the full video.
17
+ Returns (True, "Success") if the code is valid.
18
+ Returns (False, "Error Log") if any Python error (like NameError) occurs.
19
  """
20
+ print("🕵️ Running fast pre-check with 'manim -s'...", flush=True)
21
 
22
+ # Write the code to a temporary file for the pre-check
23
+ with open("scene_pre_check.py", "w", encoding="utf-8") as f:
24
+ f.write(code_str)
25
+
26
+ # Use low quality and '-s' flag for maximum speed. Output is discarded.
27
+ cmd = [
28
+ "manim",
29
+ "-ql",
30
+ "--progress_bar", "none",
31
+ "--disable_caching",
32
+ "scene_pre_check.py", "GenScene",
33
+ "-s", # This is the key: save last frame only.
34
+ "-o", "pre_check_output" # Output is temporary and will be overwritten
35
+ ]
36
 
37
  try:
38
+ # We don't need a long timeout for a pre-check
39
+ process = subprocess.run(cmd, capture_output=True, timeout=30, check=False)
 
 
 
 
 
 
 
 
40
 
41
+ if process.returncode == 0:
42
+ print("✅ Pre-check passed. Code is valid.", flush=True)
43
+ return True, "Pre-check successful."
44
+ else:
45
+ # An error occurred, capture the logs
46
+ stderr_log = process.stderr.decode('utf-8', 'ignore')
47
+ print(f"❌ Pre-check failed.\n{stderr_log}", flush=True)
48
+ # Format a clean error message for the user
49
+ error_message = f"⚠️ ERROR: Your code failed the pre-check.\n\n--- ERROR LOG ---\n{stderr_log}"
50
+ return False, error_message
51
+
52
+ except subprocess.TimeoutExpired:
53
+ print("⌛ Pre-check timed out.", flush=True)
54
+ return False, "❌ ERROR: The pre-check timed out. The code may contain an infinite loop."
55
 
56
  def cleanup_media_directory():
57
  """Wipes the media directory to prevent caching issues."""
58
  media_dir = 'media'
59
  if os.path.exists(media_dir):
60
  try: shutil.rmtree(media_dir)
61
+ except OSError as e: print(f"⚠️ Warning during cleanup: {e}", flush=True)
62
 
63
  def make_even(n):
64
  n = int(n)
 
75
 
76
  def scale_animation_times(code, factor):
77
  """Scales run_time and wait() calls."""
78
+ print(f"âš¡ Scaling animation times by a factor of {factor} for preview.", flush=True)
79
  MIN_RUN_TIME = 0.1
80
  def scale(m, is_wait):
81
  val = float(m.group(2)) * factor
 
86
 
87
  def run_manim(code_str, orientation, quality, timeout):
88
  timeout_sec = float(timeout) if timeout and float(timeout) > 0 else None
89
+ print(f"🎬 Starting Full Render: {orientation} @ {quality} (Timeout: {timeout_sec}s)...", flush=True)
90
 
91
  with open("scene.py", "w", encoding="utf-8") as f: f.write(code_str)
92
 
 
97
  frame_rate_flags = ["--frame_rate", "15"] if quality == "Preview (360p)" else []
98
  cmd = ["manim", "--resolution", res_str, *frame_rate_flags, "--disable_caching",
99
  "--progress_bar", "none", "scene.py", "GenScene", "-o", output_filename]
100
+ print(f"⚙️ Running command: {' '.join(cmd)}", flush=True)
101
 
102
  try:
103
  process = subprocess.run(cmd, capture_output=True, timeout=timeout_sec, check=False)
 
105
  full_logs = f"--- MANIM STDOUT ---\n{stdout_log}\n\n--- MANIM STDERR ---\n{stderr_log}"
106
 
107
  if process.returncode != 0:
108
+ print(f"❌ Render Failed.\n{stderr_log}", flush=True)
109
+ return None, f"⚠️ ERROR: Manim failed to render.\n{full_logs}", False
110
  except subprocess.TimeoutExpired as e:
111
+ print(f"⌛ Render timed out after {timeout_sec} seconds.", flush=True)
112
  stdout_log, stderr_log = (e.stdout.decode('utf-8', 'ignore') if e.stdout else ""), (e.stderr.decode('utf-8', 'ignore') if e.stderr else "")
113
+ return None, f"❌ ERROR: Timed out.\n--- MANIM STDOUT ---\n{stdout_log}\n\n--- MANIM STDERR ---\n{stderr_log}", False
114
 
115
  media_video_base = os.path.join("media", "videos", "scene")
116
  if os.path.exists(media_video_base):
117
  for root, _, files in os.walk(media_video_base):
118
  if output_filename in files:
119
  found_video_path = os.path.join(root, output_filename)
120
+ print(f"✅ Video Render Success: {found_video_path}", flush=True)
121
+ return found_video_path, f"✅ Rendering Successful\n\n{full_logs}", True
122
 
123
+ print(f"❌ Final output file '{output_filename}' not found.", flush=True)
124
  return None, f"Video file not created despite success code. Check logs:\n{full_logs}", False
125
 
126
  # ---------------------------------------------------------
 
130
  def render_video_from_code(code, orientation, quality, timeout, preview_factor):
131
  """Renders a video from a given Manim code string."""
132
  try:
133
+ # --- START: New '-s' Pre-Check ---
134
+ is_valid, logs = run_manim_pre_check(code)
135
+ if not is_valid:
136
+ return None, logs, gr.Button(visible=True)
137
+ # --- END: New '-s' Pre-Check ---
 
 
138
 
139
  cleanup_media_directory()
140
  if not code or "from manim import" not in code: