Spaces:
Sleeping
Sleeping
| """ | |
| BPY MCP Server - Blender Chat Interface | |
| CPU-only 3D generation with SmolLM3 | |
| """ | |
| import os | |
| import tempfile | |
| import uuid | |
| import gradio as gr | |
| from huggingface_hub import snapshot_download | |
| import openvino_genai as ov_genai | |
| import bpy | |
| SMOLLM3_PIPE = None | |
| def load_smollm3(): | |
| global SMOLLM3_PIPE | |
| if SMOLLM3_PIPE is not None: | |
| return SMOLLM3_PIPE | |
| print("Loading SmolLM3...") | |
| model_path = snapshot_download("dev-bjoern/smollm3-int4-ov") | |
| SMOLLM3_PIPE = ov_genai.LLMPipeline(model_path, device="CPU") | |
| print("SmolLM3 loaded") | |
| return SMOLLM3_PIPE | |
| def export_glb() -> str: | |
| output_dir = tempfile.mkdtemp() | |
| glb_path = f"{output_dir}/scene_{uuid.uuid4().hex[:8]}.glb" | |
| bpy.ops.export_scene.gltf(filepath=glb_path, export_format='GLB') | |
| return glb_path | |
| def execute_bpy_code(code: str) -> bool: | |
| try: | |
| if "```python" in code: | |
| code = code.split("```python")[1].split("```")[0] | |
| elif "```" in code: | |
| parts = code.split("```") | |
| if len(parts) > 1: | |
| code = parts[1] | |
| code = code.replace("import bpy", "") | |
| exec(code, {"bpy": bpy, "math": __import__("math")}) | |
| return True | |
| except Exception as e: | |
| print(f"Error: {e}") | |
| return False | |
| def chat_with_blender(message: str, history: list): | |
| try: | |
| pipe = load_smollm3() | |
| prompt = f"""Write bpy Python code for: {message} | |
| Rules: | |
| 1. Clear scene: bpy.ops.object.select_all(action='SELECT'); bpy.ops.object.delete() | |
| 2. Use bpy.ops.mesh.primitive_* for objects | |
| 3. Add camera: bpy.ops.object.camera_add() | |
| 4. Add light: bpy.ops.object.light_add(type='SUN') | |
| Only Python code, no explanations.""" | |
| result = pipe.generate(prompt, max_new_tokens=512) | |
| success = execute_bpy_code(result) | |
| if success: | |
| glb_path = export_glb() | |
| return f"Done!\n```python\n{result}\n```", glb_path | |
| else: | |
| return f"Error:\n```python\n{result}\n```", None | |
| except Exception as e: | |
| return f"Error: {e}", None | |
| with gr.Blocks(title="BPY Chat") as demo: | |
| gr.Markdown("## Blender Chat") | |
| chatbot = gr.Chatbot(height=400) | |
| model_output = gr.Model3D(label="3D Scene") | |
| with gr.Row(): | |
| msg = gr.Textbox(placeholder="Describe a 3D scene...", show_label=False, scale=9) | |
| btn = gr.Button("Send", variant="primary", scale=1) | |
| def respond(message, chat_history): | |
| if not message.strip(): | |
| return "", chat_history, None | |
| response, glb_path = chat_with_blender(message, chat_history) | |
| chat_history.append((message, response)) | |
| return "", chat_history, glb_path | |
| btn.click(respond, [msg, chatbot], [msg, chatbot, model_output]) | |
| msg.submit(respond, [msg, chatbot], [msg, chatbot, model_output]) | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=7860, mcp_server=True) | |