Spaces:
Sleeping
Sleeping
| 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) |