vankhieu Codex commited on
Commit
c18ba1c
·
1 Parent(s): 2ca2225

Use manim-trainer prompt templates

Browse files

Co-authored-by: Codex <codex@openai.com>

Files changed (3) hide show
  1. app.py +1 -12
  2. generator.py +5 -46
  3. prompt_templates.py +154 -0
app.py CHANGED
@@ -214,17 +214,6 @@ footer,
214
  box-shadow: inset 0 0 22px rgba(0, 255, 204, 0.08);
215
  }
216
 
217
- .viewport-frame::before {
218
- content: "";
219
- position: absolute;
220
- top: 10px;
221
- left: 14px;
222
- z-index: 5;
223
- color: var(--cyber-cyan);
224
- font-size: 12px;
225
- text-shadow: 0 0 8px var(--cyber-cyan);
226
- }
227
-
228
  .viewport-frame::after {
229
  content: "";
230
  position: absolute;
@@ -482,7 +471,7 @@ with gr.Blocks(css=custom_css, title="SciVisual-Agent") as demo:
482
  with gr.Tabs():
483
  with gr.Tab("Rendered Video"):
484
  video = gr.Video(label=None, elem_id="render-video", height=560)
485
- with gr.Tab("Generated Source"):
486
  source = gr.Textbox(
487
  label="Clean Python Source",
488
  lines=24,
 
214
  box-shadow: inset 0 0 22px rgba(0, 255, 204, 0.08);
215
  }
216
 
 
 
 
 
 
 
 
 
 
 
 
217
  .viewport-frame::after {
218
  content: "";
219
  position: absolute;
 
471
  with gr.Tabs():
472
  with gr.Tab("Rendered Video"):
473
  video = gr.Video(label=None, elem_id="render-video", height=560)
474
+ with gr.Tab("Generated Code"):
475
  source = gr.Textbox(
476
  label="Clean Python Source",
477
  lines=24,
generator.py CHANGED
@@ -15,6 +15,7 @@ from pathlib import Path
15
  from typing import Dict, List, Optional, Tuple
16
 
17
  from executor import render_manim_scene
 
18
 
19
 
20
  DEFAULT_MODEL_PATH = "vankhieu/Seed_Coder_8B_Instruct_unsloth_bnb_4bit_lora_r8_sft_grpo_rw_mean_text_visual"
@@ -22,25 +23,6 @@ DEFAULT_SELECTED_MODEL = "unsloth/Seed-Coder-8B-Instruct-unsloth-bnb-4bit"
22
  THINKING_TOKEN_ID = 151668
23
  THINKING_TOKEN = "</think>"
24
 
25
- SYSTEM_PROMPT = """You are SciVisual-Agent, a Physics and Mathematics visualization genius using ManimCE.
26
- Return only complete executable Python code for a Manim scene.
27
-
28
- Rules:
29
- - Put the code inside exactly one <CODE>...</CODE> block or exactly one ```python ... ``` block.
30
- - Use `from manim import *`.
31
- - Define a renderable Scene class, preferably `MainScene`.
32
- - Always include `construct(self)`.
33
- - Avoid external assets, file reads, network calls, audio, and interactive input.
34
- - Keep the animation concise enough for low-quality fast rendering.
35
- - Use readable labels and high-contrast colors on a dark background.
36
- """
37
-
38
- MATH_PROMPT = """Generate ManimCE code for this mathematics visualization.
39
- Emphasize intuition, labeled diagrams, clean equations, and a clear progression."""
40
-
41
- PHYSICS_PROMPT = """Generate ManimCE code for this physics visualization.
42
- Emphasize motion, forces, fields, trajectories, waves, and cause/effect relationships."""
43
-
44
 
45
  @dataclass
46
  class LocalModelConfig:
@@ -371,18 +353,8 @@ class ManimVisualAgent:
371
  return completion
372
 
373
  def _initial_messages(self, user_prompt: str, domain: str) -> List[Dict[str, str]]:
374
- domain_prompt = PHYSICS_PROMPT if domain.lower().startswith("phys") else MATH_PROMPT
375
- return [
376
- {"role": "system", "content": SYSTEM_PROMPT},
377
- {
378
- "role": "user",
379
- "content": (
380
- f"{domain_prompt}\n\n"
381
- f"Text script:\n{user_prompt.strip()}\n\n"
382
- "Now generate the ManimCE Python code."
383
- ),
384
- },
385
- ]
386
 
387
  def _feedback_messages(
388
  self,
@@ -391,21 +363,8 @@ class ManimVisualAgent:
391
  initial_code: str,
392
  render_errors: str,
393
  ) -> List[Dict[str, str]]:
394
- domain_prompt = PHYSICS_PROMPT if domain.lower().startswith("phys") else MATH_PROMPT
395
- return [
396
- {"role": "system", "content": SYSTEM_PROMPT},
397
- {
398
- "role": "user",
399
- "content": (
400
- f"{domain_prompt}\n\n"
401
- f"Text script:\n{user_prompt.strip()}\n\n"
402
- "The previous ManimCE code failed to render. Fix it completely.\n\n"
403
- f"<INITIAL_CODE>\n{initial_code}\n</INITIAL_CODE>\n\n"
404
- f"<RENDER_ERRORS>\n{render_errors}\n</RENDER_ERRORS>\n\n"
405
- "Return the corrected complete code in one <CODE>...</CODE> block."
406
- ),
407
- },
408
- ]
409
 
410
  def _fallback_scene(self, prompt: str) -> str:
411
  safe_message = (self.model_error or "Local model is not ready.").replace("\\", "\\\\").replace('"', '\\"')
 
15
  from typing import Dict, List, Optional, Tuple
16
 
17
  from executor import render_manim_scene
18
+ from prompt_templates import build_feedback_messages, build_initial_messages
19
 
20
 
21
  DEFAULT_MODEL_PATH = "vankhieu/Seed_Coder_8B_Instruct_unsloth_bnb_4bit_lora_r8_sft_grpo_rw_mean_text_visual"
 
23
  THINKING_TOKEN_ID = 151668
24
  THINKING_TOKEN = "</think>"
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  @dataclass
28
  class LocalModelConfig:
 
353
  return completion
354
 
355
  def _initial_messages(self, user_prompt: str, domain: str) -> List[Dict[str, str]]:
356
+ del domain
357
+ return build_initial_messages(user_prompt)
 
 
 
 
 
 
 
 
 
 
358
 
359
  def _feedback_messages(
360
  self,
 
363
  initial_code: str,
364
  render_errors: str,
365
  ) -> List[Dict[str, str]]:
366
+ del domain
367
+ return build_feedback_messages(user_prompt, initial_code, render_errors)
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
  def _fallback_scene(self, prompt: str) -> str:
370
  safe_message = (self.model_error or "Local model is not ready.").replace("\\", "\\\\").replace('"', '\\"')
prompt_templates.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Prompt templates aligned with the manim-trainer fine-tuning format."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Dict, List
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class PromptChatTemplate:
11
+ system_prompt_template: str
12
+ user_prompt_template: str
13
+ completion_prompt_template: str = ""
14
+
15
+
16
+ MANIM_VIDEO_GEN_CHAT_TEMPLATE = PromptChatTemplate(
17
+ system_prompt_template="""You are an expert Manim Community Edition (ManimCE) educator and Python developer.
18
+
19
+ Please follow these steps precisely:
20
+ 1. Read the `<TEXT_SCRIPT>` block which contains a description of a Manim animation that user want to create.
21
+ 2. DO NOT provide any explanations.
22
+ 3. Generate only executable Python code for Manim, wrapped between `<CODE>` and `</CODE>`.
23
+ 4. Do not include any explanations, comments, or instructions on how to run the code. Only include the code wrapped between `<CODE>` and `</CODE>`.
24
+
25
+
26
+ Example format:
27
+
28
+ <TEXT_SCRIPT>
29
+ Display a red square centered on screen, then transform it into a circle.
30
+ </TEXT_SCRIPT>
31
+
32
+ <CODE>
33
+ ```python
34
+ from manim import *
35
+ class RedSquareToCircle(Scene):
36
+ def construct(self):
37
+ square = Square(color=RED)
38
+ self.play(Create(square))
39
+ circle = Circle(color=RED)
40
+ self.play(Transform(square, circle))
41
+ self.wait()
42
+ ```
43
+ </CODE>""",
44
+ user_prompt_template="""Generate code for the following text script:
45
+ <TEXT_SCRIPT>
46
+ {reviewed_description}
47
+ </TEXT_SCRIPT>
48
+
49
+ """,
50
+ completion_prompt_template="""<CODE>
51
+ ```python
52
+ {code}
53
+ ```
54
+ </CODE>""",
55
+ )
56
+
57
+
58
+ MANIM_VIDEO_GEN_CHAT_FB_ONLY_TEMPLATE = PromptChatTemplate(
59
+ system_prompt_template="""You are an expert Manim Community Edition (ManimCE) educator and Python developer.
60
+
61
+ Please follow these steps precisely:
62
+ 1. Read the `<TEXT_SCRIPT>` block which contains a description of a Manim animation that I want to create.
63
+ 2. Analyze the initial code provided in the `<INITIAL_CODE>` block.
64
+ 3. Use the provided render errors (if any) in `<RENDER_ERRORS>` block to revise and fix the initial code.
65
+ 4. Generate only executable Python code for Manim, wrapped between `<CODE>` and `</CODE>`.
66
+ 5. DO NOT include any explanations, comments, or instructions on how to run the code. Only include the code wrapped between `<CODE>` and `</CODE>`.
67
+
68
+
69
+ Example format:
70
+
71
+ <TEXT_SCRIPT>
72
+ Display a red square centered on screen, then transform it into a circle.
73
+ </TEXT_SCRIPT>
74
+
75
+ <INITIAL_CODE>
76
+ ```python
77
+ from manim import *
78
+
79
+ class RedSquareToCircle(Scene):
80
+ def construct(self):
81
+ square = Square(bg_color=RED)
82
+ self.play(Create(square))
83
+ circle = Circle(bg_color=RED)
84
+ self.play(Transform(square, circle))
85
+ self.wait()
86
+ ```
87
+ </INITIAL_CODE>
88
+
89
+ <RENDER_ERRORS>
90
+ ```text
91
+ TypeError: Mobject.__init__() got an unexpected keyword argument 'bg_color'
92
+ ```
93
+ </RENDER_ERRORS>
94
+
95
+ <CODE>
96
+ ```python
97
+ from manim import *
98
+
99
+ class RedSquareToCircle(Scene):
100
+ def construct(self):
101
+ square = Square(color=RED)
102
+ self.play(Create(square))
103
+ circle = Circle(color=RED)
104
+ self.play(Transform(square, circle))
105
+ self.wait()
106
+ ```
107
+ </CODE>""",
108
+ user_prompt_template="""Generate code for the following text script adapting initial code based on the render errors occured from the initial code:
109
+
110
+ <TEXT_SCRIPT>
111
+ {reviewed_description}
112
+ </TEXT_SCRIPT>
113
+
114
+ <INITIAL_CODE>
115
+ ```python
116
+ {initial_code}
117
+ ```
118
+ </INITIAL_CODE>
119
+
120
+ <RENDER_ERRORS>
121
+ ```text
122
+ {render_errors}
123
+ ```
124
+ </RENDER_ERRORS>
125
+
126
+ """,
127
+ )
128
+
129
+
130
+ def build_initial_messages(text_script: str) -> List[Dict[str, str]]:
131
+ return [
132
+ {"role": "system", "content": MANIM_VIDEO_GEN_CHAT_TEMPLATE.system_prompt_template},
133
+ {
134
+ "role": "user",
135
+ "content": MANIM_VIDEO_GEN_CHAT_TEMPLATE.user_prompt_template.format(
136
+ reviewed_description=text_script.strip()
137
+ ),
138
+ },
139
+ ]
140
+
141
+
142
+ def build_feedback_messages(text_script: str, initial_code: str, render_errors: str) -> List[Dict[str, str]]:
143
+ return [
144
+ {"role": "system", "content": MANIM_VIDEO_GEN_CHAT_FB_ONLY_TEMPLATE.system_prompt_template},
145
+ {
146
+ "role": "user",
147
+ "content": MANIM_VIDEO_GEN_CHAT_FB_ONLY_TEMPLATE.user_prompt_template.format(
148
+ reviewed_description=text_script.strip(),
149
+ initial_code=initial_code.strip(),
150
+ render_errors=(render_errors or "NONE").strip() or "NONE",
151
+ ),
152
+ },
153
+ ]
154
+