Add versions info and project description
Browse files- README.md +71 -0
- app.py +19 -11
- modules/version_info.py +127 -0
README.md
CHANGED
@@ -16,4 +16,75 @@ thumbnail: >-
|
|
16 |
https://cdn-uploads.huggingface.co/production/uploads/6346595c9e5f0fe83fc60444/s0fQvcoiSBlH36AXpVwPi.png
|
17 |
---
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
16 |
https://cdn-uploads.huggingface.co/production/uploads/6346595c9e5f0fe83fc60444/s0fQvcoiSBlH36AXpVwPi.png
|
17 |
---
|
18 |
|
19 |
+
# 3D Viewer
|
20 |
+
|
21 |
+
**3D Viewer** is a lightweight web application built with [Gradio](https://gradio.app) that allows users to view 3D models along with their corresponding height map and source images. The app dynamically loads these resources by parsing URL query string parameters, providing a seamless and interactive experience.
|
22 |
+
|
23 |
+
## Features
|
24 |
+
|
25 |
+
- **3D Model Display:**
|
26 |
+
Uses `gr.Model3D` to render 3D models dynamically from a URL parameter (`3d`).
|
27 |
+
|
28 |
+
- **Image Slider:**
|
29 |
+
Displays images (height map and source image) using `gr.ImageSlider`. The images are loaded via URL query parameters named `hm` (height map) and `image` (source image).
|
30 |
+
|
31 |
+
- **File Upload:**
|
32 |
+
Includes an `gr.UploadButton` for uploading new file types like `.glb`, `.gltf`, `.obj`, `.png`, `.jpg`, and `.ply`.
|
33 |
+
|
34 |
+
- **Custom Theming:**
|
35 |
+
The interface is styled with the `Surn/Beeuty` theme to ensure a modern and cohesive look.
|
36 |
+
|
37 |
+
## How It Works
|
38 |
+
|
39 |
+
- **Query String Parsing:**
|
40 |
+
While running in Gradio, since the Python callback does not operate within a conventional HTTP request context, the app retrieves query string values by using client-side JavaScript. This JavaScript snippet captures the URL parameters and passes them to the Python callback, which then updates the components accordingly.
|
41 |
+
|
42 |
+
- **Static Paths:**
|
43 |
+
The app sets static paths for directories such as `images/`, `models/`, and `assets/` for accessing local resources.
|
44 |
+
|
45 |
+
## Getting Started
|
46 |
+
|
47 |
+
1. **Install Dependencies:**
|
48 |
+
|
49 |
+
Ensure you have Python 3.12.8 installed and install Gradio (v5.29.0 or compatible):
|
50 |
+
|
51 |
+
```pip install gradio==5.29.0```
|
52 |
+
|
53 |
+
|
54 |
+
2. **Run the Application:**
|
55 |
+
|
56 |
+
Start the app by executing:
|
57 |
+
|
58 |
+
```python app.py```
|
59 |
+
|
60 |
+
|
61 |
+
3. **Use the Query String:**
|
62 |
+
|
63 |
+
After launching, the app can load specific resources if you pass the following query parameters in the URL:
|
64 |
+
|
65 |
+
- `3d`: URL for the 3D model (e.g., `?3d=https://example.com/model.glb`)
|
66 |
+
- `hm`: URL for the height map image (e.g., `?hm=https://example.com/heightmap.png`)
|
67 |
+
- `image`: URL for the source image (e.g., `?image=https://example.com/source.png`)
|
68 |
+
|
69 |
+
Example URL:
|
70 |
+
|
71 |
+
```http://localhost:7860/?3d=https://example.com/model.glb&hm=https://example.com/heightmap.png&image=https://example.com/source.png```
|
72 |
+
|
73 |
+
|
74 |
+
## Project Structure
|
75 |
+
|
76 |
+
- **app.py:**
|
77 |
+
The core application script defining the Gradio interface, callbacks, and dynamic query string processing.
|
78 |
+
|
79 |
+
- **README.md:**
|
80 |
+
This documentation file outlining the project details and configuration.
|
81 |
+
|
82 |
+
- **assets, images, models:**
|
83 |
+
Directories containing static resources such as images, 3D models, and other assets.
|
84 |
+
|
85 |
+
## License
|
86 |
+
|
87 |
+
This project is licensed under the Apache-2.0 license.
|
88 |
+
|
89 |
+
|
90 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
CHANGED
@@ -1,4 +1,9 @@
|
|
1 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
def load_data(query_params, model_3d, image_slider):
|
4 |
# set default values or pull from querystring
|
@@ -21,23 +26,26 @@ with gr.Blocks(css_paths="style_20250314.css", title="3D viewer", theme='Surn/Be
|
|
21 |
gr.Markdown("# 3D Model Viewer")
|
22 |
|
23 |
with gr.Row():
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
34 |
|
35 |
with gr.Row():
|
36 |
upload_btn = gr.UploadButton(
|
37 |
"Upload",
|
38 |
file_types=[".glb", ".gltf", ".obj", ".png", ".jpg", ".ply"]
|
39 |
)
|
40 |
-
|
|
|
|
|
41 |
# Use JavaScript to pass the query parameters to your callback.
|
42 |
viewer3d.load(
|
43 |
load_data,
|
|
|
1 |
import gradio as gr
|
2 |
+
import modules.version_info as version_info
|
3 |
+
|
4 |
+
def getVersions():
|
5 |
+
#return html_versions
|
6 |
+
return version_info.versions_html()
|
7 |
|
8 |
def load_data(query_params, model_3d, image_slider):
|
9 |
# set default values or pull from querystring
|
|
|
26 |
gr.Markdown("# 3D Model Viewer")
|
27 |
|
28 |
with gr.Row():
|
29 |
+
with gr.Column():
|
30 |
+
model_3d = gr.Model3D(
|
31 |
+
label="3D Model",
|
32 |
+
value=None,
|
33 |
+
height=400
|
34 |
+
)
|
35 |
+
image_slider = gr.ImageSlider(
|
36 |
+
label="Images",
|
37 |
+
value=None,
|
38 |
+
height=400
|
39 |
+
)
|
40 |
|
41 |
with gr.Row():
|
42 |
upload_btn = gr.UploadButton(
|
43 |
"Upload",
|
44 |
file_types=[".glb", ".gltf", ".obj", ".png", ".jpg", ".ply"]
|
45 |
)
|
46 |
+
with gr.Row():
|
47 |
+
gr.HTML(value=getVersions(), visible=True, elem_id="versions")
|
48 |
+
|
49 |
# Use JavaScript to pass the query parameters to your callback.
|
50 |
viewer3d.load(
|
51 |
load_data,
|
modules/version_info.py
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# modules/version_info.py
|
2 |
+
|
3 |
+
import subprocess
|
4 |
+
import os
|
5 |
+
import sys
|
6 |
+
import gc
|
7 |
+
import gradio as gr
|
8 |
+
|
9 |
+
git = os.environ.get('GIT', "git")
|
10 |
+
|
11 |
+
def commit_hash():
|
12 |
+
try:
|
13 |
+
return subprocess.check_output([git, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()
|
14 |
+
except Exception:
|
15 |
+
return "<none>"
|
16 |
+
|
17 |
+
def get_xformers_version():
|
18 |
+
try:
|
19 |
+
import xformers
|
20 |
+
return xformers.__version__
|
21 |
+
except Exception:
|
22 |
+
return "<none>"
|
23 |
+
def get_transformers_version():
|
24 |
+
try:
|
25 |
+
import transformers
|
26 |
+
return transformers.__version__
|
27 |
+
except Exception:
|
28 |
+
return "<none>"
|
29 |
+
|
30 |
+
def get_accelerate_version():
|
31 |
+
try:
|
32 |
+
import accelerate
|
33 |
+
return accelerate.__version__
|
34 |
+
except Exception:
|
35 |
+
return "<none>"
|
36 |
+
def get_safetensors_version():
|
37 |
+
try:
|
38 |
+
import safetensors
|
39 |
+
return safetensors.__version__
|
40 |
+
except Exception:
|
41 |
+
return "<none>"
|
42 |
+
def get_diffusers_version():
|
43 |
+
try:
|
44 |
+
import diffusers
|
45 |
+
return diffusers.__version__
|
46 |
+
except Exception:
|
47 |
+
return "<none>"
|
48 |
+
def get_open3d_version():
|
49 |
+
try:
|
50 |
+
import open3d
|
51 |
+
return f"{open3d.__version__} cuda:{open3d.core.cuda.is_available()}"
|
52 |
+
except Exception:
|
53 |
+
return "<none>"
|
54 |
+
|
55 |
+
def get_torch_info():
|
56 |
+
from torch import __version__ as torch_version_, version, cuda, backends
|
57 |
+
initialize_cuda()
|
58 |
+
try:
|
59 |
+
info = [torch_version_, f"CUDA Version:{version.cuda}", f"Available:{cuda.is_available()}", f"flash attention enabled: {backends.cuda.flash_sdp_enabled()}", f"Capabilities: {cuda.get_device_capability(0)}", f"Device Name: {cuda.get_device_name(0)}", f"Device Count: {cuda.device_count()}",f"Devices: {os.environ['CUDA_VISIBLE_DEVICES']}", f"Zero :{os.environ['CUDA_MODULE_LOADING']}"]
|
60 |
+
del torch_version_, version, cuda, backends
|
61 |
+
return info
|
62 |
+
except Exception:
|
63 |
+
del torch_version_, version, cuda, backends
|
64 |
+
return "<none>"
|
65 |
+
|
66 |
+
def release_torch_resources():
|
67 |
+
from torch import cuda
|
68 |
+
if cuda.is_available():
|
69 |
+
# Clear the CUDA cache
|
70 |
+
cuda.empty_cache()
|
71 |
+
cuda.ipc_collect()
|
72 |
+
# Delete any objects that are using GPU memory
|
73 |
+
#for obj in gc.get_objects():
|
74 |
+
# if is_tensor(obj) or (hasattr(obj, 'data') and is_tensor(obj.data)):
|
75 |
+
# del obj
|
76 |
+
# Run garbage collection
|
77 |
+
del cuda
|
78 |
+
gc.collect()
|
79 |
+
|
80 |
+
|
81 |
+
def initialize_cuda():
|
82 |
+
from torch import cuda, version
|
83 |
+
if cuda.is_available():
|
84 |
+
device = cuda.device("cuda")
|
85 |
+
print(f"CUDA is available. Using device: {cuda.get_device_name(0)} with CUDA version: {version.cuda}")
|
86 |
+
result = "cuda"
|
87 |
+
else:
|
88 |
+
#device = cuda.device("cpu")
|
89 |
+
print("CUDA is not available. Using CPU.")
|
90 |
+
result = "cpu"
|
91 |
+
return result
|
92 |
+
|
93 |
+
def versions_html():
|
94 |
+
from torch import __version__ as torch_version_
|
95 |
+
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
96 |
+
commit = commit_hash()
|
97 |
+
|
98 |
+
# Define the Toggle Dark Mode link with JavaScript
|
99 |
+
toggle_dark_link = '''
|
100 |
+
<a href="#" onclick="document.body.classList.toggle('dark'); return false;" style="cursor: pointer; text-decoration: underline;">
|
101 |
+
Toggle Dark Mode
|
102 |
+
</a>
|
103 |
+
'''
|
104 |
+
|
105 |
+
v_html = f"""
|
106 |
+
version: <a href="https://huggingface.co/spaces/Surn/3D-Viewer/commit/{"huggingface" if commit == "<none>" else commit}" target="_blank">{"huggingface" if commit == "<none>" else commit}</a>
|
107 |
+
 • 
|
108 |
+
python: <span title="{sys.version}">{python_version}</span>
|
109 |
+
 • 
|
110 |
+
torch: {torch_version_}
|
111 |
+
 • 
|
112 |
+
diffusers: {get_diffusers_version()}
|
113 |
+
 • 
|
114 |
+
transformers: {get_transformers_version()}
|
115 |
+
 • 
|
116 |
+
safetensors: {get_safetensors_version()}
|
117 |
+
 • 
|
118 |
+
open3d: {get_open3d_version()}
|
119 |
+
 • 
|
120 |
+
gradio: {gr.__version__}
|
121 |
+
 • 
|
122 |
+
{toggle_dark_link}
|
123 |
+
<br>
|
124 |
+
Full GPU Info:{get_torch_info()}
|
125 |
+
"""
|
126 |
+
del torch_version_
|
127 |
+
return v_html
|