haraberget commited on
Commit
9ef31b0
·
verified ·
1 Parent(s): 50b12aa

Upload jsonapp.py

Browse files
Files changed (1) hide show
  1. jsonapp.py +185 -0
jsonapp.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import tempfile
4
+ import os
5
+ import trimesh
6
+ import json
7
+
8
+ # ------------------------------
9
+ # Load default models from JSON
10
+ # ------------------------------
11
+ # Option 1: Load external models.json (if exists)
12
+ def load_default_models():
13
+ try:
14
+ with open("models.json", "r") as f:
15
+ data = json.load(f)
16
+ return data.get("default_models", [])
17
+ except FileNotFoundError:
18
+ # Fallback embedded list
19
+ return [
20
+ {"name": "Damaged Helmet", "url": "https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf"},
21
+ {"name": "Flight Helmet", "url": "https://threejs.org/examples/models/gltf/FlightHelmet/glTF/FlightHelmet.gltf"},
22
+ {"name": "Horse", "url": "https://threejs.org/examples/models/gltf/Horse.glb"},
23
+ {"name": "Fox", "url": "https://threejs.org/examples/models/gltf/Fox.glb"},
24
+ {"name": "Camera", "url": "https://raw.githubusercontent.com/ektogamat/camera-webgi/master/assets/camera.glb"},
25
+ ]
26
+
27
+ DEFAULT_MODELS = load_default_models()
28
+
29
+ # ------------------------------
30
+ # Helper functions
31
+ # ------------------------------
32
+ def download_model(url):
33
+ try:
34
+ response = requests.get(url, stream=True, timeout=15)
35
+ response.raise_for_status()
36
+ # Determine suffix from URL or content-type
37
+ suffix = ".glb"
38
+ if url.lower().endswith(".gltf"):
39
+ suffix = ".gltf"
40
+ with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
41
+ for chunk in response.iter_content(chunk_size=8192):
42
+ tmp.write(chunk)
43
+ return tmp.name
44
+ except Exception as e:
45
+ print(f"Download error: {e}")
46
+ return None
47
+
48
+ def load_and_convert_model(url, target_format):
49
+ if not url:
50
+ return None
51
+ # Download original
52
+ original_path = download_model(url)
53
+ if not original_path:
54
+ return None
55
+ try:
56
+ mesh = trimesh.load(original_path)
57
+ # Export
58
+ ext = target_format.lower()
59
+ with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
60
+ out_path = tmp.name
61
+ if ext in ["obj", "stl", "ply", "glb", "gltf"]:
62
+ mesh.export(out_path, file_type=ext)
63
+ else:
64
+ return None
65
+ return out_path
66
+ except Exception as e:
67
+ print(f"Conversion error: {e}")
68
+ return None
69
+ finally:
70
+ if os.path.exists(original_path):
71
+ os.unlink(original_path)
72
+
73
+ def display_model_from_url(url):
74
+ if not url:
75
+ return None
76
+ return download_model(url)
77
+
78
+ # ------------------------------
79
+ # Gradio UI
80
+ # ------------------------------
81
+ with gr.Blocks(title="3D Model Viewer & Converter") as demo:
82
+ gr.Markdown("## 🌐 3D Model Hub")
83
+ gr.Markdown("Select a default model or paste any GLB/GLTF URL.")
84
+
85
+ with gr.Row():
86
+ # Dropdown for default models
87
+ default_choices = [m["name"] for m in DEFAULT_MODELS]
88
+ default_dropdown = gr.Dropdown(
89
+ choices=default_choices,
90
+ label="📦 Default Models",
91
+ value=default_choices[0] if default_choices else None
92
+ )
93
+ # Custom URL input
94
+ url_input = gr.Textbox(
95
+ label="🔗 Or paste custom URL",
96
+ placeholder="https://example.com/model.glb",
97
+ scale=3
98
+ )
99
+ load_btn = gr.Button("Load Model", variant="primary")
100
+
101
+ model_output = gr.Model3D(
102
+ label="3D Preview",
103
+ clear_color=[0.2, 0.2, 0.2, 0.8],
104
+ camera_position=(2, 2, 3)
105
+ )
106
+
107
+ gr.Markdown("### 💾 Download as...")
108
+ with gr.Row():
109
+ obj_btn = gr.Button("OBJ")
110
+ stl_btn = gr.Button("STL")
111
+ ply_btn = gr.Button("PLY")
112
+ glb_btn = gr.Button("GLB")
113
+ gltf_btn = gr.Button("glTF")
114
+
115
+ # Hidden file outputs
116
+ obj_file = gr.File(label="Download OBJ", visible=False)
117
+ stl_file = gr.File(label="Download STL", visible=False)
118
+ ply_file = gr.File(label="Download PLY", visible=False)
119
+ glb_file = gr.File(label="Download GLB", visible=False)
120
+ gltf_file = gr.File(label="Download glTF", visible=False)
121
+
122
+ # State to hold current URL
123
+ current_url = gr.State()
124
+
125
+ # When dropdown changes, update the custom URL textbox (optional)
126
+ def update_url_from_dropdown(selected_name):
127
+ for model in DEFAULT_MODELS:
128
+ if model["name"] == selected_name:
129
+ return model["url"]
130
+ return ""
131
+
132
+ default_dropdown.change(fn=update_url_from_dropdown, inputs=default_dropdown, outputs=url_input)
133
+
134
+ # Load model from either dropdown or custom URL
135
+ def load_model(selected_name, custom_url):
136
+ # Prioritize custom URL if non-empty, else use selected default
137
+ if custom_url and custom_url.strip():
138
+ url = custom_url.strip()
139
+ else:
140
+ for model in DEFAULT_MODELS:
141
+ if model["name"] == selected_name:
142
+ url = model["url"]
143
+ break
144
+ else:
145
+ return None
146
+ # Download and return file path for preview
147
+ return download_model(url)
148
+
149
+ load_btn.click(
150
+ fn=load_model,
151
+ inputs=[default_dropdown, url_input],
152
+ outputs=model_output
153
+ ).then(
154
+ fn=lambda selected_name, custom_url: (
155
+ custom_url.strip() if custom_url and custom_url.strip()
156
+ else next((m["url"] for m in DEFAULT_MODELS if m["name"] == selected_name), "")
157
+ ),
158
+ inputs=[default_dropdown, url_input],
159
+ outputs=current_url
160
+ )
161
+
162
+ # Conversion buttons
163
+ def convert_and_download(url, fmt):
164
+ if not url:
165
+ return None
166
+ return load_and_convert_model(url, fmt)
167
+
168
+ for fmt, btn, out in [
169
+ ("obj", obj_btn, obj_file),
170
+ ("stl", stl_btn, stl_file),
171
+ ("ply", ply_btn, ply_file),
172
+ ("glb", glb_btn, glb_file),
173
+ ("gltf", gltf_btn, gltf_file),
174
+ ]:
175
+ btn.click(
176
+ fn=lambda url, f=fmt: convert_and_download(url, f),
177
+ inputs=current_url,
178
+ outputs=out
179
+ ).then(
180
+ fn=lambda: gr.update(visible=True),
181
+ outputs=out
182
+ )
183
+
184
+ if __name__ == "__main__":
185
+ demo.launch()