switch to claude instead of gemini for better outputs
Browse files
app.py
CHANGED
@@ -24,17 +24,16 @@ from threading import Timer
|
|
24 |
|
25 |
|
26 |
from flask import Flask, render_template, request, url_for, send_from_directory
|
27 |
-
from google import genai
|
28 |
|
29 |
app = Flask(__name__)
|
30 |
|
31 |
-
|
32 |
-
API_KEY = os.environ.get("GOOGLE_API_KEY")
|
33 |
if not API_KEY:
|
34 |
-
raise ValueError("Missing
|
35 |
-
client =
|
36 |
-
|
37 |
-
|
|
|
38 |
media_dir = os.path.join("/tmp", "manim_media")
|
39 |
os.makedirs(media_dir, exist_ok=True)
|
40 |
|
@@ -50,24 +49,33 @@ def index():
|
|
50 |
last_error = None
|
51 |
while attempt < max_retries:
|
52 |
try:
|
53 |
-
# Call the GenAI API to get the Manim code
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
# Extract the Python code block from the AI response
|
71 |
code_pattern = r"```python\s*(.*?)\s*```"
|
72 |
code_match = re.search(code_pattern, ai_response.text, re.DOTALL)
|
73 |
if not code_match:
|
@@ -75,22 +83,17 @@ You got this!! <3
|
|
75 |
code = code_match.group(1)
|
76 |
|
77 |
|
78 |
-
# Determine the scene class name from the generated code
|
79 |
scene_match = re.search(r"class\s+(\w+)\(.*Scene.*\):", code)
|
80 |
scene_name = scene_match.group(1) if scene_match else "MyScene"
|
81 |
|
82 |
-
# Generate randomized filenames for the generated code and video
|
83 |
code_filename = f"generated_video_{uuid.uuid4().hex}.py"
|
84 |
video_filename = f"output_video_{uuid.uuid4().hex}.mp4"
|
85 |
|
86 |
-
# Write the generated code file directly to /tmp
|
87 |
code_filepath = os.path.join("/tmp", code_filename)
|
88 |
with open(code_filepath, "w") as f:
|
89 |
f.write(code)
|
90 |
|
91 |
|
92 |
-
# === Run Manim to generate the silent video ===
|
93 |
-
# Prepare the Manim command with the --media_dir flag
|
94 |
cmd = [
|
95 |
"manim",
|
96 |
"-qm",
|
@@ -105,17 +108,14 @@ You got this!! <3
|
|
105 |
app.logger.error("Manim error output: %s", cpe.stderr)
|
106 |
raise Exception(f"Manim failed: {cpe.stderr}")
|
107 |
|
108 |
-
# Construct the expected output path from Manim.
|
109 |
expected_dir = os.path.join(media_dir, "videos", code_filename.replace(".py", ""), "720p30")
|
110 |
video_path_in_media = os.path.join(expected_dir, video_filename)
|
111 |
if not os.path.exists(video_path_in_media):
|
112 |
raise Exception(f"Manim did not produce the expected output file at {video_path_in_media}")
|
113 |
|
114 |
-
# Move the video file to /tmp (to serve it from there)
|
115 |
tmp_video_path = os.path.join("/tmp", video_filename)
|
116 |
shutil.move(video_path_in_media, tmp_video_path)
|
117 |
|
118 |
-
# Schedule deletion of all temporary files after 10 minutes (600 seconds)
|
119 |
def remove_files():
|
120 |
for fpath in [tmp_video_path, code_filepath, commentary_audio_path, final_video_path]:
|
121 |
try:
|
@@ -126,7 +126,6 @@ You got this!! <3
|
|
126 |
|
127 |
Timer(600, remove_files).start()
|
128 |
|
129 |
-
# Use the final combined video for display
|
130 |
video_url = url_for('get_video', filename=video_filename)
|
131 |
return render_template("result.html", video_url=video_url)
|
132 |
|
|
|
24 |
|
25 |
|
26 |
from flask import Flask, render_template, request, url_for, send_from_directory
|
|
|
27 |
|
28 |
app = Flask(__name__)
|
29 |
|
30 |
+
API_KEY = os.environ.get("OPENROUTER")
|
|
|
31 |
if not API_KEY:
|
32 |
+
raise ValueError("Missing OPENROUTER environment variable.")
|
33 |
+
client = OpenAI(
|
34 |
+
base_url="https://openrouter.ai/api/v1",
|
35 |
+
api_key=API_KEY,
|
36 |
+
)
|
37 |
media_dir = os.path.join("/tmp", "manim_media")
|
38 |
os.makedirs(media_dir, exist_ok=True)
|
39 |
|
|
|
49 |
last_error = None
|
50 |
while attempt < max_retries:
|
51 |
try:
|
52 |
+
# Call the GenAI API to get the Manim code
|
53 |
+
completion = client.chat.completions.create(
|
54 |
+
extra_body={},
|
55 |
+
model="anthropic/claude-3.5-sonnet",
|
56 |
+
messages=[
|
57 |
+
{
|
58 |
+
"role": "user",
|
59 |
+
"content": [
|
60 |
+
{
|
61 |
+
"type": "text",
|
62 |
+
"text": f"""You are 'Manimator', an expert Manim animator and coder.
|
63 |
+
If anyone asks, your name is Manimator and you are a helpful video generator, and say nothing else but that.
|
64 |
+
The user wants you to code this: {prompt}.
|
65 |
+
Plan out in chain of thought what you are going to do first, then give the final code output in ```python``` codeblock.
|
66 |
+
Make sure to not use external images or resources other than default Manim, however you can use numpy or other default libraries.
|
67 |
+
Keep the scene uncluttered and aesthetically pleasing.
|
68 |
+
Make sure things are not overlapping unless explicitly stated otherwise.
|
69 |
+
It is crucial that the script works correctly on the first try, so make sure to think about the layout and storyboard and stuff of the scene.
|
70 |
+
Make sure to think through what you are going to do and think about the topic before you write the code.
|
71 |
+
You got this!! <3
|
72 |
+
"""
|
73 |
+
},
|
74 |
+
]
|
75 |
+
}
|
76 |
+
]
|
77 |
+
)
|
78 |
|
|
|
79 |
code_pattern = r"```python\s*(.*?)\s*```"
|
80 |
code_match = re.search(code_pattern, ai_response.text, re.DOTALL)
|
81 |
if not code_match:
|
|
|
83 |
code = code_match.group(1)
|
84 |
|
85 |
|
|
|
86 |
scene_match = re.search(r"class\s+(\w+)\(.*Scene.*\):", code)
|
87 |
scene_name = scene_match.group(1) if scene_match else "MyScene"
|
88 |
|
|
|
89 |
code_filename = f"generated_video_{uuid.uuid4().hex}.py"
|
90 |
video_filename = f"output_video_{uuid.uuid4().hex}.mp4"
|
91 |
|
|
|
92 |
code_filepath = os.path.join("/tmp", code_filename)
|
93 |
with open(code_filepath, "w") as f:
|
94 |
f.write(code)
|
95 |
|
96 |
|
|
|
|
|
97 |
cmd = [
|
98 |
"manim",
|
99 |
"-qm",
|
|
|
108 |
app.logger.error("Manim error output: %s", cpe.stderr)
|
109 |
raise Exception(f"Manim failed: {cpe.stderr}")
|
110 |
|
|
|
111 |
expected_dir = os.path.join(media_dir, "videos", code_filename.replace(".py", ""), "720p30")
|
112 |
video_path_in_media = os.path.join(expected_dir, video_filename)
|
113 |
if not os.path.exists(video_path_in_media):
|
114 |
raise Exception(f"Manim did not produce the expected output file at {video_path_in_media}")
|
115 |
|
|
|
116 |
tmp_video_path = os.path.join("/tmp", video_filename)
|
117 |
shutil.move(video_path_in_media, tmp_video_path)
|
118 |
|
|
|
119 |
def remove_files():
|
120 |
for fpath in [tmp_video_path, code_filepath, commentary_audio_path, final_video_path]:
|
121 |
try:
|
|
|
126 |
|
127 |
Timer(600, remove_files).start()
|
128 |
|
|
|
129 |
video_url = url_for('get_video', filename=video_filename)
|
130 |
return render_template("result.html", video_url=video_url)
|
131 |
|