|
|
import gradio as gr |
|
|
import tempfile, os, subprocess, json |
|
|
|
|
|
BLENDER = "blender" |
|
|
|
|
|
def build_prop(spec_file): |
|
|
|
|
|
try: |
|
|
spec_path = spec_file.name |
|
|
with open(spec_path, "r") as f: |
|
|
spec = json.load(f) |
|
|
except Exception as e: |
|
|
return None, f"Invalid JSON: {e}" |
|
|
|
|
|
|
|
|
ptype = spec.get("type") |
|
|
if not ptype: |
|
|
return None, "Spec must include a 'type' field (e.g., 'book')." |
|
|
if "name" not in spec: |
|
|
spec["name"] = f"{ptype}_auto" |
|
|
|
|
|
|
|
|
generator = "generate_book.py" if ptype == "book" else "generate_book.py" |
|
|
|
|
|
out_dir = tempfile.mkdtemp() |
|
|
cmd = [BLENDER, "-b", "-P", generator, "--", "--spec", spec_path, "--out", out_dir] |
|
|
|
|
|
try: |
|
|
run = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) |
|
|
logs = run.stdout |
|
|
except subprocess.CalledProcessError as e: |
|
|
return None, f"Blender failed:\n{e.stdout}" |
|
|
|
|
|
|
|
|
glbs = [os.path.join(out_dir, f) for f in os.listdir(out_dir) if f.lower().endswith(".glb")] |
|
|
if not glbs: |
|
|
return None, f"No .glb exported.\nLogs:\n{logs}" |
|
|
return glbs[0], "Success." |
|
|
|
|
|
demo = gr.Interface( |
|
|
fn=build_prop, |
|
|
inputs=gr.File(label="Upload PropSpec JSON"), |
|
|
outputs=[gr.File(label="Generated .glb"), gr.Textbox(label="Log")], |
|
|
title="Code‑Generated Props (Blender Headless)", |
|
|
description="Upload a JSON PropSpec (supports 'book' for now) and download a .glb.", |
|
|
allow_flagging="never" |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860"))) |