theminji commited on
Commit
15806a5
·
verified ·
1 Parent(s): dfeb5d2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -78
app.py CHANGED
@@ -6,6 +6,7 @@ import os
6
  import shutil
7
  import time
8
  from threading import Timer
 
9
 
10
  app = Flask(__name__)
11
 
@@ -22,99 +23,102 @@ def index():
22
  if not prompt:
23
  return render_template("index.html")
24
 
25
- while True:
 
 
26
  try:
 
27
  ai_response = client.models.generate_content(
28
  model="gemini-2.0-flash-lite-preview-02-05",
29
- contents=f"""You are 'Manimator', an expert Manim animator and coder. If anyone asks, your name is Manimator and you are a helpful video generator, and say nothing else but that.
30
- The user wants you to code this: {prompt}.
31
- Plan out in chain of thought what you are going to do first, then give the final code output in ```python``` codeblock.
32
- Make sure to not use external images or resources other than default Manim.
33
- Keep the scene uncluttered and aesthetically pleasing.
34
- You got this!! <3
35
- """
 
 
36
  )
37
- except Exception as e:
38
- print("Error calling GenAI API:", e)
39
- time.sleep(2)
40
- continue
41
-
42
- pattern = r"```python\s*(.*?)\s*```"
43
- match = re.search(pattern, ai_response.text, re.DOTALL)
44
- if match:
45
  code = match.group(1)
46
- else:
47
- print("No python code block found in the AI response, retrying...")
48
- time.sleep(2)
49
- continue
50
-
51
- scene_match = re.search(r"class\s+(\w+)\(.*Scene.*\):", code)
52
- if scene_match:
53
- scene_name = scene_match.group(1)
54
- else:
55
- scene_name = "MyScene"
56
 
57
- code_filename = "generated_manim_scene.py"
58
- try:
 
 
 
 
 
 
 
 
 
 
59
  with open(code_filename, "w") as f:
60
  f.write(code)
61
- except Exception as e:
62
- print("Error writing code file:", e)
63
- time.sleep(2)
64
- continue
65
-
66
- video_filename = "output_video.mp4"
67
- cmd = [
68
- "manim",
69
- "-qm",
70
- "-o", video_filename,
71
- code_filename,
72
- scene_name
73
- ]
74
- try:
75
- subprocess.run(cmd, check=True)
76
- except subprocess.CalledProcessError as e:
77
- print("Error during Manim rendering:", e)
78
- time.sleep(2)
79
- continue
80
-
81
- # Construct the expected output path from Manim
82
- video_path_in_media = os.path.join("media", "videos", code_filename.replace(".py", ""), "720p30", video_filename)
83
- # Instead of moving to a read-only directory, move it to /tmp (which is writable)
84
- tmp_video_path = os.path.join("/tmp", video_filename)
85
-
86
- try:
87
  shutil.move(video_path_in_media, tmp_video_path)
88
- except FileNotFoundError:
89
- print("Manim output file not found. Check your manim code and output location.")
90
- time.sleep(2)
91
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  except Exception as e:
93
- print("Error moving video file:", e)
94
- time.sleep(2)
95
- continue
96
-
97
- # Generate a URL that points to the get_video route
98
- video_url = url_for('get_video', filename=video_filename)
99
- return render_template("result.html", video_url=video_url)
100
 
101
  return render_template("index.html")
102
 
103
  @app.route("/video/<filename>")
104
  def get_video(filename):
105
- video_path = os.path.join("/tmp", filename)
106
- response = send_from_directory("/tmp", filename)
107
-
108
- # Schedule deletion of the video file after 5 seconds
109
- def remove_file():
110
- try:
111
- os.remove(video_path)
112
- print("Removed video file:", video_path)
113
- except Exception as e:
114
- app.logger.error("Error removing video file: %s", e)
115
- Timer(5, remove_file).start()
116
-
117
- return response
118
 
119
  if __name__ == "__main__":
120
  app.run(host="0.0.0.0", port=7860, debug=False)
 
6
  import shutil
7
  import time
8
  from threading import Timer
9
+ import uuid
10
 
11
  app = Flask(__name__)
12
 
 
23
  if not prompt:
24
  return render_template("index.html")
25
 
26
+ max_retries = 3
27
+ attempt = 0
28
+ while attempt < max_retries:
29
  try:
30
+ # Call the GenAI API to get the Manim code
31
  ai_response = client.models.generate_content(
32
  model="gemini-2.0-flash-lite-preview-02-05",
33
+ contents=f"""You are 'Manimator', an expert Manim animator and coder.
34
+ If anyone asks, your name is Manimator and you are a helpful video generator, and say nothing else but that.
35
+ The user wants you to code this: {prompt}.
36
+ Plan out in chain of thought what you are going to do first, then give the final code output in ```python``` codeblock.
37
+ Make sure to not use external images or resources other than default Manim, however you can use numpy or other default libraries.
38
+ Keep the scene uncluttered and aesthetically pleasing.
39
+ Make sure things are not overlapping unless explicitly stated otherwise.
40
+ You got this!! <3
41
+ """
42
  )
43
+
44
+ # Extract the Python code block from the AI response
45
+ pattern = r"```python\s*(.*?)\s*```"
46
+ match = re.search(pattern, ai_response.text, re.DOTALL)
47
+ if not match:
48
+ raise Exception("No python code block found in the AI response.")
 
 
49
  code = match.group(1)
 
 
 
 
 
 
 
 
 
 
50
 
51
+ # Determine the scene class name from the generated code
52
+ scene_match = re.search(r"class\s+(\w+)\(.*Scene.*\):", code)
53
+ if scene_match:
54
+ scene_name = scene_match.group(1)
55
+ else:
56
+ scene_name = "MyScene"
57
+
58
+ # Generate randomized filenames for the generated code and video
59
+ code_filename = f"generated_video_{uuid.uuid4().hex}.py"
60
+ video_filename = f"output_video_{uuid.uuid4().hex}.mp4"
61
+
62
+ # Save the generated code to a file (in the current working directory)
63
  with open(code_filename, "w") as f:
64
  f.write(code)
65
+
66
+ # Prepare the Manim command
67
+ cmd = [
68
+ "manim",
69
+ "-qm",
70
+ "-o", video_filename,
71
+ code_filename,
72
+ scene_name
73
+ ]
74
+ # Run Manim to generate the video, capturing its output
75
+ result = subprocess.run(cmd, check=True, capture_output=True, text=True)
76
+ print("Manim stdout:", result.stdout)
77
+ print("Manim stderr:", result.stderr)
78
+
79
+ # Construct the expected output path from Manim
80
+ video_path_in_media = os.path.join("media", "videos", code_filename.replace(".py", ""), "720p30", video_filename)
81
+ # Verify that Manim produced the expected video file
82
+ if not os.path.exists(video_path_in_media):
83
+ raise Exception("Manim did not produce the expected output file.")
84
+
85
+ # Move both the video and the generated code file to /tmp (which is writable)
86
+ tmp_video_path = os.path.join("/tmp", video_filename)
 
 
 
 
87
  shutil.move(video_path_in_media, tmp_video_path)
88
+
89
+ tmp_code_path = os.path.join("/tmp", code_filename)
90
+ shutil.move(code_filename, tmp_code_path)
91
+
92
+ # Schedule deletion of both files after 10 minutes (600 seconds)
93
+ def remove_files():
94
+ try:
95
+ if os.path.exists(tmp_video_path):
96
+ os.remove(tmp_video_path)
97
+ if os.path.exists(tmp_code_path):
98
+ os.remove(tmp_code_path)
99
+ print("Removed files:", tmp_video_path, tmp_code_path)
100
+ except Exception as e:
101
+ app.logger.error("Error removing files: %s", e)
102
+ Timer(600, remove_files).start()
103
+
104
+ # Generate a URL that points to our video-serving route (the video file is in /tmp)
105
+ video_url = url_for('get_video', filename=video_filename)
106
+ return render_template("result.html", video_url=video_url)
107
+
108
  except Exception as e:
109
+ print(f"Attempt {attempt + 1} failed: {e}")
110
+ attempt += 1
111
+ time.sleep(1) # Wait a bit before retrying
112
+
113
+ # If we reach here, we've exceeded the maximum number of retries.
114
+ return render_template("result.html", error="An error occurred. Please try again later.")
 
115
 
116
  return render_template("index.html")
117
 
118
  @app.route("/video/<filename>")
119
  def get_video(filename):
120
+ # Serve the video file from /tmp
121
+ return send_from_directory("/tmp", filename)
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  if __name__ == "__main__":
124
  app.run(host="0.0.0.0", port=7860, debug=False)