Spaces:
Running
Running
| import gradio as gr | |
| import requests | |
| import tempfile | |
| import os | |
| import trimesh | |
| def download_model(url): | |
| """Download model from URL to temporary file.""" | |
| try: | |
| response = requests.get(url, stream=True, timeout=10) | |
| response.raise_for_status() | |
| with tempfile.NamedTemporaryFile(suffix=".glb", delete=False) as tmp: | |
| for chunk in response.iter_content(chunk_size=8192): | |
| tmp.write(chunk) | |
| return tmp.name | |
| except Exception as e: | |
| print(f"Download error: {e}") | |
| return None | |
| def load_and_convert_model(url, target_format): | |
| """Load model from URL and convert to target format.""" | |
| if not url: | |
| return None | |
| # Download the GLB file | |
| glb_path = download_model(url) | |
| if not glb_path: | |
| return None | |
| try: | |
| # Load the model using trimesh | |
| mesh = trimesh.load(glb_path) | |
| # Save to temporary file in target format | |
| output_ext = target_format.lower() | |
| with tempfile.NamedTemporaryFile(suffix=f".{output_ext}", delete=False) as tmp: | |
| output_path = tmp.name | |
| # Export based on format | |
| if output_ext == "obj": | |
| mesh.export(output_path, file_type="obj") | |
| elif output_ext == "stl": | |
| mesh.export(output_path, file_type="stl") | |
| elif output_ext == "ply": | |
| mesh.export(output_path, file_type="ply") | |
| elif output_ext == "glb": | |
| mesh.export(output_path, file_type="glb") | |
| elif output_ext == "gltf": | |
| mesh.export(output_path, file_type="gltf") | |
| else: | |
| # For unsupported formats, return None | |
| return None | |
| return output_path | |
| except Exception as e: | |
| print(f"Conversion error: {e}") | |
| return None | |
| finally: | |
| # Clean up original downloaded file | |
| if os.path.exists(glb_path): | |
| os.unlink(glb_path) | |
| def cleanup(file_path): | |
| if file_path and os.path.exists(file_path): | |
| os.unlink(file_path) | |
| # Gradio interface | |
| with gr.Blocks(title="3D Model Converter") as demo: | |
| gr.Markdown("## 🌐 3D Model Viewer & Converter") | |
| gr.Markdown("Enter a URL to a GLB file to view and download in different formats.") | |
| with gr.Row(): | |
| url_input = gr.Textbox( | |
| label="GLB File URL", | |
| placeholder="https://example.com/model.glb", | |
| scale=4 | |
| ) | |
| submit_btn = gr.Button("Load Model", variant="primary", scale=1) | |
| model_output = gr.Model3D( | |
| label="3D Model Preview", | |
| clear_color=[0.2, 0.2, 0.2, 0.8], | |
| camera_position=(2, 2, 3), | |
| scale=1.0 | |
| ) | |
| gr.Markdown("### 💾 Download Options") | |
| with gr.Row(): | |
| obj_btn = gr.Button("Download as OBJ", variant="secondary") | |
| stl_btn = gr.Button("Download as STL", variant="secondary") | |
| ply_btn = gr.Button("Download as PLY", variant="secondary") | |
| glb_btn = gr.Button("Download as GLB", variant="secondary") | |
| obj_file = gr.File(label="Download OBJ", visible=False) | |
| stl_file = gr.File(label="Download STL", visible=False) | |
| ply_file = gr.File(label="Download PLY", visible=False) | |
| glb_file = gr.File(label="Download GLB", visible=False) | |
| # State to store the current URL | |
| current_url = gr.State() | |
| # When loading, store URL and display model | |
| submit_btn.click( | |
| fn=lambda url: (url, download_model(url)), | |
| inputs=url_input, | |
| outputs=[current_url, model_output] | |
| ) | |
| # Conversion functions | |
| def convert_and_download(url, format_type): | |
| if not url: | |
| return None | |
| output_path = load_and_convert_model(url, format_type) | |
| if output_path: | |
| return output_path | |
| return None | |
| # Wire up download buttons | |
| obj_btn.click( | |
| fn=lambda url: convert_and_download(url, "obj"), | |
| inputs=current_url, | |
| outputs=obj_file | |
| ).then( | |
| fn=lambda: gr.update(visible=True), | |
| outputs=obj_file | |
| ) | |
| stl_btn.click( | |
| fn=lambda url: convert_and_download(url, "stl"), | |
| inputs=current_url, | |
| outputs=stl_file | |
| ).then( | |
| fn=lambda: gr.update(visible=True), | |
| outputs=stl_file | |
| ) | |
| ply_btn.click( | |
| fn=lambda url: convert_and_download(url, "ply"), | |
| inputs=current_url, | |
| outputs=ply_file | |
| ).then( | |
| fn=lambda: gr.update(visible=True), | |
| outputs=ply_file | |
| ) | |
| glb_btn.click( | |
| fn=lambda url: convert_and_download(url, "glb"), | |
| inputs=current_url, | |
| outputs=glb_file | |
| ).then( | |
| fn=lambda: gr.update(visible=True), | |
| outputs=glb_file | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |