File size: 4,761 Bytes
31d16ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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()