""" Forge-Anim Brick """ import gradio as gr import spaces # Robust import for local workspace + HF Space deployment (common is vendored on push) import sys from pathlib import Path HERE = Path(__file__).resolve().parent for candidate in (HERE.parent, HERE): if (candidate / "common" / "manifest.py").exists(): sys.path.insert(0, str(candidate)) break try: from common.manifest import create_manifest except ImportError as e: raise ImportError( "Failed to import shared 'common' package (manifest.py).\n" "For local development: run ./install.sh from the forge-bricks/ root.\n" "For HF Spaces: re-run scripts/push_to_hf.py so it vendors common/." ) from e import os from pathlib import Path from datetime import datetime @spaces.GPU(duration=30) def generate_anim(rig_data: str, motion_desc: str) -> dict: out = Path(os.environ.get("FORGE_BRICKS_OUTPUT", "./outputs/forge_anim")) out.mkdir(parents=True, exist_ok=True) ts = int(datetime.now().timestamp()) # Use VLM or simple logic + structured output for animation data # In production, could call a motion model Space or LLM for keyframe data anim = { "clips": ["idle", "walk", "attack"], "motion_desc": motion_desc, "rig_ref": rig_data[:100] if rig_data else "", "keyframe_suggestions": { "idle": "loop 0-30 frames, subtle breathing", "walk": "cycle 0-24 frames, foot plant at 0/12", "attack": "windup 0-10, impact 10-15, recover 15-30" }, "note": "Structured animation metadata. Apply in Godot/Blender using the rig_data." } man = create_manifest( name="anim", type="animation", source_brick="forge-anim", prompt_or_desc=motion_desc, files={"anim_data": str(out / f"anim_{ts}.json")}, metadata=anim, commercial_ok=True ) (out / f"anim_{ts}.json").write_text(str(anim)) man.save(out / f"manifest_{ts}.json") return {"anim_data": anim, "manifest": man.to_dict()} def build_ui(): with gr.Blocks() as d: gr.Markdown("# Forge-Anim") rig = gr.Textbox("rig json or description") motion = gr.Textbox("heroic walk cycle") btn = gr.Button("Generate Anim") out = gr.JSON() btn.click(generate_anim, [rig, motion], out) return d # Build at module level so that `demo` (and `gradio_app`) exist when the module is imported # (required for Hugging Face Spaces and for agent/MCP discovery). demo = build_ui() gradio_app = demo # alias for compatibility with tools/skills that expect `gradio_app` if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7867, mcp_server=True)