File size: 7,087 Bytes
cc0e0a9
 
a099f98
cc0e0a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a099f98
 
 
 
 
 
 
cc0e0a9
 
a099f98
cc0e0a9
bc8dc7f
a099f98
 
bc8dc7f
 
cc0e0a9
 
bc8dc7f
a099f98
cc0e0a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a099f98
 
 
 
cc0e0a9
 
 
a099f98
 
 
 
 
cc0e0a9
a099f98
cc0e0a9
 
 
 
 
 
 
 
 
a099f98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
from toolbox import CatchException, update_ui
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
from .crazy_utils import input_clipping

def inspect_dependency(chatbot, history):
    # 尝试导入依赖,如果缺少依赖,则给出安装建议
    try:
        import manim
        return True
    except:
        chatbot.append(["导入依赖失败", "使用该模块需要额外依赖,安装方法:```pip install manimgl```"])
        yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
        return False

def gen_time_str():
    import time
    return time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())

def eval_manim(code):
    import subprocess, sys, os, shutil

    with open('gpt_log/MyAnimation.py', 'w', encoding='utf8') as f:
        f.write(code)

    def get_class_name(class_string):
        import re
        # Use regex to extract the class name
        class_name = re.search(r'class (\w+)\(Scene\)', class_string).group(1)
        return class_name

    class_name = get_class_name(code)

    try: 
        subprocess.check_output([sys.executable, '-c', f"from gpt_log.MyAnimation import {class_name}; {class_name}().render()"])
        shutil.copyfile('media/videos/1080p60/MyAnimation.mp4', f'gpt_log/{gen_time_str()}.mp4')
        return f'gpt_log/{gen_time_str()}.mp4'
    except subprocess.CalledProcessError as e:
        output = e.output.decode()
        print(f"Command returned non-zero exit status {e.returncode}: {output}.")
        return f"Evaluating python script failed: {e.output}."
    except: 
        print('generating mp4 failed')
        return "Generating mp4 failed."


def get_code_block(reply):
    import re
    pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks
    matches = re.findall(pattern, reply) # find all code blocks in text
    if len(matches) != 1: 
        raise RuntimeError("GPT is not generating proper code.")
    return matches[0].strip('python') #  code block

@CatchException
def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
    """
    txt             输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
    llm_kwargs      gpt模型参数,如温度和top_p等,一般原样传递下去就行
    plugin_kwargs   插件模型的参数,暂时没有用武之地
    chatbot         聊天显示框的句柄,用于显示给用户
    history         聊天历史,前情提要
    system_prompt   给gpt的静默提醒
    web_port        当前软件运行的端口号
    """
    # 清空历史,以免输入溢出
    history = []    

    # 基本信息:功能、贡献者
    chatbot.append([
        "函数插件功能?",
        "生成数学动画, 作者: binary-husky, 插件初始化中 ..."
    ])
    yield from update_ui(chatbot=chatbot, history=history) # 刷新界面

    # 尝试导入依赖, 如果缺少依赖, 则给出安装建议
    dep_ok = yield from inspect_dependency(chatbot=chatbot, history=history) # 刷新界面
    if not dep_ok: return
    
    # 输入
    i_say = f'Generate a animation to show: ' + txt
    demo = ["Here is some examples of manim", examples_of_manim()]
    _, demo = input_clipping(inputs="", history=demo, max_token_limit=2560)
    # 开始
    gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
        inputs=i_say, inputs_show_user=i_say, 
        llm_kwargs=llm_kwargs, chatbot=chatbot, history=demo, 
        sys_prompt=
        r"Write a animation script with 3blue1brown's manim. "+
        r"Please begin with `from manim import *` and name the class as `MyAnimation`. " + 
        r"Answer me with a code block wrapped by ```."
    )
    chatbot.append(["开始生成动画", "..."])
    history.extend([i_say, gpt_say])
    yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
    
    # 将代码转为动画
    code = get_code_block(gpt_say)
    res = eval_manim(code)

    chatbot.append(("生成的视频文件路径", res))
    yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新

# 在这里放一些网上搜集的demo,辅助gpt生成代码
def examples_of_manim():
    return """


```
# Moving Group To Destination
class MyAnimation(Scene):
    def construct(self):
        group = VGroup(Dot(LEFT), Dot(ORIGIN), Dot(RIGHT, color=RED), Dot(2 * RIGHT)).scale(1.4)
        dest = Dot([4, 3, 0], color=YELLOW)
        self.add(group, dest)
        self.play(group.animate.shift(dest.get_center() - group[2].get_center()))
        self.wait(0.5)

```


```
# Moving FrameBox
class MyAnimation(Scene):
    def construct(self):
        text=MathTex(
            "\\frac{d}{dx}f(x)g(x)=","f(x)\\frac{d}{dx}g(x)","+",
            "g(x)\\frac{d}{dx}f(x)"
        )
        self.play(Write(text))
        framebox1 = SurroundingRectangle(text[1], buff = .1)
        framebox2 = SurroundingRectangle(text[3], buff = .1)
        self.play(
            Create(framebox1),
        )
        self.wait()
        self.play(
            ReplacementTransform(framebox1,framebox2),
        )
        self.wait()

```



```
# Point With Trace
class MyAnimation(Scene):
    def construct(self):
        path = VMobject()
        dot = Dot()
        path.set_points_as_corners([dot.get_center(), dot.get_center()])
        def update_path(path):
            previous_path = path.copy()
            previous_path.add_points_as_corners([dot.get_center()])
            path.become(previous_path)
        path.add_updater(update_path)
        self.add(path, dot)
        self.play(Rotating(dot, radians=PI, about_point=RIGHT, run_time=2))
        self.wait()
        self.play(dot.animate.shift(UP))
        self.play(dot.animate.shift(LEFT))
        self.wait()

```

```
# SinAndCosFunctionPlot
class MyAnimation(Scene):
    def construct(self):
        axes = Axes(
            x_range=[-10, 10.3, 1],
            y_range=[-1.5, 1.5, 1],
            x_length=10,
            axis_config={"color": GREEN},
            x_axis_config={
                "numbers_to_include": np.arange(-10, 10.01, 2),
                "numbers_with_elongated_ticks": np.arange(-10, 10.01, 2),
            },
            tips=False,
        )
        axes_labels = axes.get_axis_labels()
        sin_graph = axes.plot(lambda x: np.sin(x), color=BLUE)
        cos_graph = axes.plot(lambda x: np.cos(x), color=RED)

        sin_label = axes.get_graph_label(
            sin_graph, "\\sin(x)", x_val=-10, direction=UP / 2
        )
        cos_label = axes.get_graph_label(cos_graph, label="\\cos(x)")

        vert_line = axes.get_vertical_line(
            axes.i2gp(TAU, cos_graph), color=YELLOW, line_func=Line
        )
        line_label = axes.get_graph_label(
            cos_graph, "x=2\pi", x_val=TAU, direction=UR, color=WHITE
        )

        plot = VGroup(axes, sin_graph, cos_graph, vert_line)
        labels = VGroup(axes_labels, sin_label, cos_label, line_label)
        self.add(plot, labels)

```




"""