Patrick Rathje
Do not install everytime for new projects
b1a5ae8
raw
history blame
5.01 kB
import gradio as gr
import os
import shutil
import uuid
import subprocess
from threading import Timer
from functools import partial
from gradio_motioncanvasplayer import MotionCanvasPlayer
example_project_path = "https://prathje-gradio-motioncanvasplayer.hf.space/gradio_api/file=/home/user/app/public/project-3.17.2.js"
loading_project_path = ""
failed_project_path = ""
BUILD_TIMEOUT = 60
gr.set_static_paths(paths=[os.path.join(os.path.dirname(__file__), "public")])
def get_local_path(project_id):
return os.path.join(os.path.dirname(__file__), "public", "project-" + project_id + ".js")
def get_public_path(project_id):
return "/gradio_api/file=" + get_local_path(project_id)
def build_project(code):
# TODO: as soon as gradio supports states, we should keep the project_id for some time...
# TODO: In the best case, we start a separate container for each project!
yield loading_project_path, "Preparing project...",
# generate a random uuid for the project
project_id = str(uuid.uuid4())
tmp_dir = os.path.join("/tmp/", project_id)
shutil.copytree(os.environ['MC_PROJECT_DIR'], tmp_dir, dirs_exist_ok=False, symlinks=True)
acc_logs = ""
try:
yield loading_project_path, "Building project...",
# write code to scene.ts
with open(os.path.join(tmp_dir, "src", "scenes", "example.tsx"), "w") as f:
f.write(code)
process = subprocess.Popen(
"npm run build",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
shell=True,
cwd=tmp_dir
)
timer = Timer(BUILD_TIMEOUT, process.kill)
timer.start()
while True:
line = process.stdout.readline()
if line:
acc_logs += line.rstrip() + "\n"
yield loading_project_path, acc_logs
elif process.poll() is not None:
break
timer.cancel()
# Check for errors
stderr_output = process.stderr.read()
if stderr_output:
acc_logs += "\n" + "Error building project: " + stderr_output
# check if the build was successful
if process.returncode != 0:
yield failed_project_path, acc_logs
else:
# copy dist/project.js to get_local_path(id)
shutil.copy(os.path.join(tmp_dir, "dist", "project.js"), get_local_path(project_id))
yield get_public_path(project_id), acc_logs
except Exception as e:
yield failed_project_path, acc_logs + "\n" + "Error building project: " + str(e)
finally:
# cleanup tmp dir
shutil.rmtree(tmp_dir)
def load_example_code(example_name):
return open(os.path.join(os.path.dirname(__file__), "examples", example_name + ".tsx")).read()
def build_example(example_name):
iterator = build_project(load_example_code(example_name))
last = next(iterator)
for last in iterator:
continue
path = last[0]
assert path, "Failed to build example: " + last[1]
return path
print("Building examples...")
EXAMPLES = [
{
"name": "Gradio + Motion Canvas",
"code": load_example_code("gradio-motion-canvas-example"),
"project_path": build_example("gradio-motion-canvas-example")
},
{
"name": "Blur",
"code": load_example_code("motion-canvas-blur"),
"project_path": build_example("motion-canvas-blur")
},
{
"name": "Latex",
"code": load_example_code("latex"),
"project_path": build_example("latex")
},
{
"name": "Code",
"code": load_example_code("code"),
"project_path": build_example("code")
},
]
print("Examples built!")
def load_example(example):
return example['project_path'], example['code'], ""
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
gr.Markdown("# Motion Canvas MCP Server")
with gr.Row():
with gr.Column():
gr.Markdown("## TypeScript Input for Your Scene")
gr.Markdown("Leverage the power of Motion Canvas to create your own animations using TypeScript.")
code = gr.Code(value=EXAMPLES[0]['code'], language="typescript")
submit = gr.Button("Build", variant="primary")
logs = gr.Textbox(value="", label="Build Logs", interactive=False)
with gr.Column():
gr.Markdown("## Preview")
player = MotionCanvasPlayer(EXAMPLES[0]['project_path'], auto=True, quality=0.5, width=1920, height=1080, variables="{}")
for ex in EXAMPLES:
btn = gr.Button("Load Example: " + ex["name"], variant="secondary")
btn.click(partial(load_example, ex), outputs=[player, code, logs])
submit.click(build_project, inputs=[code], outputs=[player, logs], api_name="build_project")
if __name__ == "__main__":
demo.launch(mcp_server=True, strict_cors=False)