Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,9 +14,9 @@ def modify_animation_times(code: str, factor: float = 1.0, for_precheck: bool =
|
|
| 14 |
Modifies wait() and run_time in the code.
|
| 15 |
|
| 16 |
1. If for_precheck=True:
|
| 17 |
-
- Sets
|
| 18 |
-
- Sets
|
| 19 |
-
- This
|
| 20 |
|
| 21 |
2. If for_precheck=False (Preview Mode):
|
| 22 |
- Scales animation speed by 'factor'.
|
|
@@ -27,10 +27,9 @@ def modify_animation_times(code: str, factor: float = 1.0, for_precheck: bool =
|
|
| 27 |
if for_precheck:
|
| 28 |
print("⚡ Optimizing code for Pre-check (Zero Latency)...", flush=True)
|
| 29 |
# Regex: Find self.wait(ANYTHING) and replace with self.wait(0)
|
| 30 |
-
# We use [^)]* to match any content inside the parenthesis (numbers, math, variables)
|
| 31 |
code = re.sub(r"self\.wait\s*\([^)]*\)", "self.wait(0)", code)
|
| 32 |
|
| 33 |
-
# Regex: Find run_time=ANYTHING
|
| 34 |
code = re.sub(r"run_time\s*=\s*[^,)]+", "run_time=0.01", code)
|
| 35 |
return code
|
| 36 |
|
|
@@ -59,16 +58,20 @@ def modify_animation_times(code: str, factor: float = 1.0, for_precheck: bool =
|
|
| 59 |
|
| 60 |
def run_manim_pre_check(code_str: str) -> (bool, str):
|
| 61 |
"""
|
| 62 |
-
Runs Manim with the '-s' flag to perform a fast
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
"""
|
| 66 |
print("🕵️ Running fast pre-check with 'manim -s'...", flush=True)
|
| 67 |
|
| 68 |
-
# Apply the speed hack
|
| 69 |
fast_code = modify_animation_times(code_str, for_precheck=True)
|
| 70 |
|
| 71 |
-
# Write
|
| 72 |
with open("scene_pre_check.py", "w", encoding="utf-8") as f:
|
| 73 |
f.write(fast_code)
|
| 74 |
|
|
@@ -78,26 +81,27 @@ def run_manim_pre_check(code_str: str) -> (bool, str):
|
|
| 78 |
"--progress_bar", "none",
|
| 79 |
"--disable_caching",
|
| 80 |
"scene_pre_check.py", "GenScene",
|
| 81 |
-
"-s", # Save last frame only
|
| 82 |
"-o", "pre_check_output"
|
| 83 |
]
|
| 84 |
|
| 85 |
try:
|
| 86 |
-
#
|
| 87 |
process = subprocess.run(cmd, capture_output=True, timeout=30, check=False)
|
| 88 |
|
| 89 |
if process.returncode == 0:
|
| 90 |
print("✅ Pre-check passed. Code is valid.", flush=True)
|
| 91 |
return True, "Pre-check successful."
|
| 92 |
else:
|
|
|
|
| 93 |
stderr_log = process.stderr.decode('utf-8', 'ignore')
|
| 94 |
print(f"❌ Pre-check failed.\n{stderr_log}", flush=True)
|
| 95 |
return False, f"⚠️ ERROR: Your code failed the pre-check.\n\n--- ERROR LOG ---\n{stderr_log}"
|
| 96 |
|
| 97 |
except subprocess.TimeoutExpired:
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
return
|
| 101 |
|
| 102 |
def cleanup_media_directory():
|
| 103 |
"""Wipes the media directory to prevent caching issues."""
|
|
@@ -164,17 +168,20 @@ def run_manim(code_str, orientation, quality, timeout):
|
|
| 164 |
def render_video_from_code(code, orientation, quality, timeout, preview_factor):
|
| 165 |
"""Renders a video from a given Manim code string."""
|
| 166 |
try:
|
| 167 |
-
# --- 1. Pre-Check (With Speed Hack) ---
|
| 168 |
is_valid, logs = run_manim_pre_check(code)
|
|
|
|
|
|
|
| 169 |
if not is_valid:
|
| 170 |
return None, logs, gr.Button(visible=True)
|
| 171 |
|
|
|
|
|
|
|
| 172 |
cleanup_media_directory()
|
| 173 |
if not code or "from manim import" not in code:
|
| 174 |
return None, "Error: No valid code to render.", gr.Button(visible=False)
|
| 175 |
|
| 176 |
-
# --- 2. Prepare Code for Render ---
|
| 177 |
-
# If quality is Preview, we scale time. If not, we use original code.
|
| 178 |
if quality == "Preview (360p)":
|
| 179 |
code_to_render = modify_animation_times(code, factor=float(preview_factor) or 0.5, for_precheck=False)
|
| 180 |
else:
|
|
|
|
| 14 |
Modifies wait() and run_time in the code.
|
| 15 |
|
| 16 |
1. If for_precheck=True:
|
| 17 |
+
- Sets self.wait(...) to self.wait(0).
|
| 18 |
+
- Sets run_time=... to run_time=0.01.
|
| 19 |
+
- This attempts to make the validation run instantly.
|
| 20 |
|
| 21 |
2. If for_precheck=False (Preview Mode):
|
| 22 |
- Scales animation speed by 'factor'.
|
|
|
|
| 27 |
if for_precheck:
|
| 28 |
print("⚡ Optimizing code for Pre-check (Zero Latency)...", flush=True)
|
| 29 |
# Regex: Find self.wait(ANYTHING) and replace with self.wait(0)
|
|
|
|
| 30 |
code = re.sub(r"self\.wait\s*\([^)]*\)", "self.wait(0)", code)
|
| 31 |
|
| 32 |
+
# Regex: Find run_time=ANYTHING and set to 0.01 to avoid "run_time <= 0" error
|
| 33 |
code = re.sub(r"run_time\s*=\s*[^,)]+", "run_time=0.01", code)
|
| 34 |
return code
|
| 35 |
|
|
|
|
| 58 |
|
| 59 |
def run_manim_pre_check(code_str: str) -> (bool, str):
|
| 60 |
"""
|
| 61 |
+
Runs Manim with the '-s' flag to perform a fast pre-check.
|
| 62 |
+
|
| 63 |
+
CRITICAL BEHAVIOR:
|
| 64 |
+
1. Tries to run quickly using 'modify_animation_times'.
|
| 65 |
+
2. If it catches a SyntaxError or NameError, it FAILS (Returns False).
|
| 66 |
+
3. If it runs for >30 seconds (Timeout), it PASSES (Returns True), assuming
|
| 67 |
+
the code is valid but just computationally heavy.
|
| 68 |
"""
|
| 69 |
print("🕵️ Running fast pre-check with 'manim -s'...", flush=True)
|
| 70 |
|
| 71 |
+
# Apply the speed hack
|
| 72 |
fast_code = modify_animation_times(code_str, for_precheck=True)
|
| 73 |
|
| 74 |
+
# Write to temp file
|
| 75 |
with open("scene_pre_check.py", "w", encoding="utf-8") as f:
|
| 76 |
f.write(fast_code)
|
| 77 |
|
|
|
|
| 81 |
"--progress_bar", "none",
|
| 82 |
"--disable_caching",
|
| 83 |
"scene_pre_check.py", "GenScene",
|
| 84 |
+
"-s", # Save last frame only
|
| 85 |
"-o", "pre_check_output"
|
| 86 |
]
|
| 87 |
|
| 88 |
try:
|
| 89 |
+
# Run for max 30 seconds
|
| 90 |
process = subprocess.run(cmd, capture_output=True, timeout=30, check=False)
|
| 91 |
|
| 92 |
if process.returncode == 0:
|
| 93 |
print("✅ Pre-check passed. Code is valid.", flush=True)
|
| 94 |
return True, "Pre-check successful."
|
| 95 |
else:
|
| 96 |
+
# Code finished but failed (e.g. Syntax Error)
|
| 97 |
stderr_log = process.stderr.decode('utf-8', 'ignore')
|
| 98 |
print(f"❌ Pre-check failed.\n{stderr_log}", flush=True)
|
| 99 |
return False, f"⚠️ ERROR: Your code failed the pre-check.\n\n--- ERROR LOG ---\n{stderr_log}"
|
| 100 |
|
| 101 |
except subprocess.TimeoutExpired:
|
| 102 |
+
# Code ran for 30s without crashing. likely valid but heavy.
|
| 103 |
+
print("⌛ Pre-check timed out (30s). Assuming code is valid but heavy.", flush=True)
|
| 104 |
+
return True, "⚠️ Warning: Pre-check timed out (30s). The code seems valid but is very heavy. Proceeding to full render..."
|
| 105 |
|
| 106 |
def cleanup_media_directory():
|
| 107 |
"""Wipes the media directory to prevent caching issues."""
|
|
|
|
| 168 |
def render_video_from_code(code, orientation, quality, timeout, preview_factor):
|
| 169 |
"""Renders a video from a given Manim code string."""
|
| 170 |
try:
|
| 171 |
+
# --- 1. Pre-Check (With Speed Hack & Soft Pass) ---
|
| 172 |
is_valid, logs = run_manim_pre_check(code)
|
| 173 |
+
|
| 174 |
+
# If is_valid is False, it means there was a real Error (Syntax, NameError, etc.)
|
| 175 |
if not is_valid:
|
| 176 |
return None, logs, gr.Button(visible=True)
|
| 177 |
|
| 178 |
+
# If is_valid is True, we proceed (even if it timed out)
|
| 179 |
+
|
| 180 |
cleanup_media_directory()
|
| 181 |
if not code or "from manim import" not in code:
|
| 182 |
return None, "Error: No valid code to render.", gr.Button(visible=False)
|
| 183 |
|
| 184 |
+
# --- 2. Prepare Code for Real Render ---
|
|
|
|
| 185 |
if quality == "Preview (360p)":
|
| 186 |
code_to_render = modify_animation_times(code, factor=float(preview_factor) or 0.5, for_precheck=False)
|
| 187 |
else:
|