Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import shutil | |
| import uuid | |
| import subprocess | |
| from threading import Timer | |
| 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... | |
| 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) | |
| acc_logs = "" | |
| try: | |
| yield loading_project_path, "Building project...", | |
| process = subprocess.Popen( | |
| "npm install && 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) | |
| # generate a random uuid for the project | |
| # copy whole MC_PROJECT_DIR to a random tmp dir | |
| # write code to scene.ts | |
| # run npm run build | |
| # return [logs, project_api_path] | |
| # if successful copy MC_PROJECT_DIR/dist/project.js to get_local_path(id) | |
| # always: log the output to logs | |
| # always delete the tmp dir after the build is done | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Motion Canvas MCP Server") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("## TS Input for scene.ts") | |
| code = gr.Code(language="typescript") | |
| submit = gr.Button("Build") | |
| logs = gr.Textbox(value="", label="Build Logs", interactive=False) | |
| with gr.Column(): | |
| gr.Markdown("## Preview") | |
| player = MotionCanvasPlayer(example_project_path, auto=True, quality=0.5, width=1920, height=1080, variables="{}") | |
| submit.click(build_project, inputs=[code], outputs=[player, logs], api_name="build_project") | |
| if __name__ == "__main__": | |
| demo.launch(mcp_server=True, strict_cors=False) |