Surn commited on
Commit
7cb0b54
·
1 Parent(s): 0933474

Recover Lost File, Delete 3d_model folder

Browse files
Files changed (5) hide show
  1. .gitattributes +1 -1
  2. app.py +53 -6
  3. modules/constants.py +7 -1
  4. modules/storage.py +100 -0
  5. style_20250503.css +2 -2
.gitattributes CHANGED
@@ -40,4 +40,4 @@ images/beeuty_545jlbh1_v12_alpha96_300dpi_depth.png filter=lfs diff=lfs merge=lf
40
  *.gltf filter=lfs diff=lfs merge=lfs -text
41
  *.ply filter=lfs diff=lfs merge=lfs -text
42
  *.stl filter=lfs diff=lfs merge=lfs -text
43
- *.obj filter=lfs diff=lfs merge=lfs -text
 
40
  *.gltf filter=lfs diff=lfs merge=lfs -text
41
  *.ply filter=lfs diff=lfs merge=lfs -text
42
  *.stl filter=lfs diff=lfs merge=lfs -text
43
+ *.obj filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -1,10 +1,13 @@
1
  import gradio as gr
2
  import os
 
3
  import modules.constants as constants
4
  import modules.version_info as version_info
 
5
 
6
 
7
  user_dir = constants.TMPDIR
 
8
 
9
  def getVersions():
10
  #return html_versions
@@ -53,10 +56,10 @@ def process_upload(files, current_model, current_images):
53
  file_name = f.name if hasattr(f, "name") else f
54
  ext = os.path.splitext(file_name)[1].lower()
55
 
56
- if ext in [".glb", ".gltf", ".obj", ".ply"]:
57
  if extracted_model is None:
58
  extracted_model = file_name
59
- elif ext in [".png", ".jpg", ".jpeg"]:
60
  if len(extracted_images) < 2:
61
  extracted_images.append(file_name)
62
 
@@ -94,7 +97,8 @@ with gr.Blocks(css_paths="style_20250503.css", title="3D viewer", theme='Surn/be
94
  label="3D Model",
95
  value=None,
96
  height=480,
97
- elem_id="model_3d", key="model_3d"
 
98
 
99
  )
100
  image_slider = gr.ImageSlider(
@@ -105,12 +109,38 @@ with gr.Blocks(css_paths="style_20250503.css", title="3D viewer", theme='Surn/be
105
  type="filepath"
106
  )
107
 
 
 
 
108
  with gr.Row():
109
  upload_btn = gr.UploadButton(
110
- "Upload", elem_id="upload_btn", key="upload_btn",
111
  file_count="multiple",
112
- file_types=[".glb", ".gltf", ".obj", ".png", ".jpg", ".ply"]
 
 
 
 
 
 
 
 
 
 
113
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  with gr.Row():
115
  gr.HTML(value=getVersions(), visible=True, elem_id="versions")
116
 
@@ -136,9 +166,26 @@ with gr.Blocks(css_paths="style_20250503.css", title="3D viewer", theme='Surn/be
136
  show_progress=True
137
 
138
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  if __name__ == "__main__":
141
  viewer3d.launch(
142
- allowed_paths=["assets", "assets/", "./assets", "images/", "./images", 'e:/TMP', 'models/'],
143
  favicon_path="./assets/favicon.ico", show_api=True, strict_cors=False
144
  )
 
1
  import gradio as gr
2
  import os
3
+ import random
4
  import modules.constants as constants
5
  import modules.version_info as version_info
6
+ import modules.storage as storage
7
 
8
 
9
  user_dir = constants.TMPDIR
10
+ default_folder = "saved_models/3d_model_" + format(random.randint(1, 999999), "06d")
11
 
12
  def getVersions():
13
  #return html_versions
 
56
  file_name = f.name if hasattr(f, "name") else f
57
  ext = os.path.splitext(file_name)[1].lower()
58
 
59
+ if ext in constants.model_extensions:
60
  if extracted_model is None:
61
  extracted_model = file_name
62
+ elif ext in constants.image_extensions:
63
  if len(extracted_images) < 2:
64
  extracted_images.append(file_name)
65
 
 
97
  label="3D Model",
98
  value=None,
99
  height=480,
100
+ elem_id="model_3d", key="model_3d", clear_color=[1.0, 1.0, 1.0, 0.1],
101
+ elem_classes="centered solid imgcontainer", interactive=True
102
 
103
  )
104
  image_slider = gr.ImageSlider(
 
109
  type="filepath"
110
  )
111
 
112
+ with gr.Row():
113
+ gr.Markdown("## Upload your own files")
114
+ gr.Markdown("### Supported formats: " + ", ".join([f"`{ext}`" for ext in constants.upload_file_types]))
115
  with gr.Row():
116
  upload_btn = gr.UploadButton(
117
+ "Upload 3D Files", elem_id="upload_btn", key="upload_btn",
118
  file_count="multiple",
119
+ file_types=constants.upload_file_types
120
+ )
121
+
122
+ with gr.Row():
123
+ # New textbox for folder name.
124
+ folder_name_box = gr.Textbox(
125
+ label="Folder Name",
126
+ value=default_folder,
127
+ elem_id="folder_name",
128
+ key="folder_name",
129
+ placeholder="Enter folder name..."
130
  )
131
+ permalink_button = gr.Button("Generate Permalink", elem_id="permalink_button", key="permalink_button", elem_classes="solid small centered")
132
+
133
+ with gr.Row(visible=False, elem_id="permalink_row") as permalink_row:
134
+ permalink = gr.Textbox(
135
+ show_copy_button=True,
136
+ label="Permalink",
137
+ elem_id="permalink",
138
+ key="permalink",
139
+ elem_classes="solid small centered",
140
+ max_lines=5,
141
+ lines=3
142
+ )
143
+ gr.Markdown("### Copy the link above to share your model and images.")
144
  with gr.Row():
145
  gr.HTML(value=getVersions(), visible=True, elem_id="versions")
146
 
 
166
  show_progress=True
167
 
168
  )
169
+ # Generate a permalink based on the current model, images, and folder name.
170
+ permalink_button.click(
171
+ lambda model, images, folder: storage.upload_files_to_repo(
172
+ files=[model] + list(images),
173
+ repo_id="Surn/Storage",
174
+ folder_name=folder,
175
+ create_permalink=True,
176
+ repo_type="dataset"
177
+ )[1], # Extract the permalink from the returned tuple if criteria met.
178
+ inputs=[model_3d, image_slider, folder_name_box],
179
+ outputs=[permalink],
180
+ scroll_to_output=True
181
+ ).then(
182
+ lambda link: gr.update(visible=True) if link and len(link) > 0 else gr.update(visible=False),
183
+ inputs=[permalink],
184
+ outputs=[permalink_row]
185
+ )
186
 
187
  if __name__ == "__main__":
188
  viewer3d.launch(
189
+ allowed_paths=["assets", "assets/", "./assets", "images/", "./images", 'e:/TMP', 'models/', '3d_model_viewer/'],
190
  favicon_path="./assets/favicon.ico", show_api=True, strict_cors=False
191
  )
modules/constants.py CHANGED
@@ -21,4 +21,10 @@ try:
21
  except:
22
  TMPDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
23
 
24
- os.makedirs(TMPDIR, exist_ok=True)
 
 
 
 
 
 
 
21
  except:
22
  TMPDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
23
 
24
+ os.makedirs(TMPDIR, exist_ok=True)
25
+
26
+ model_extensions = {".glb", ".gltf", ".obj", ".ply"}
27
+ model_extensions_list = list(model_extensions)
28
+ image_extensions = {".png", ".jpg", ".jpeg", ".webp"}
29
+ image_extensions_list = list(image_extensions)
30
+ upload_file_types = model_extensions_list + image_extensions_list
modules/storage.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # modules/storage.py
2
+ import os
3
+ import urllib.parse
4
+ import tempfile
5
+ import shutil
6
+ from huggingface_hub import login, upload_folder
7
+ from modules.constants import HF_API_TOKEN, upload_file_types, model_extensions, image_extensions
8
+
9
+ def upload_files_to_repo(files, repo_id, folder_name, create_permalink=False, repo_type="dataset"):
10
+ """
11
+ Uploads multiple files to a Hugging Face repository using a batch upload approach via upload_folder.
12
+
13
+ Parameters:
14
+ files (list): A list of file paths (str) to upload.
15
+ repo_id (str): The repository ID on Hugging Face for storage, e.g. "Surn/Storage".
16
+ folder_name (str): The subfolder within the repository where files will be saved.
17
+ create_permalink (bool): If True and if exactly three files are uploaded (1 model and 2 images),
18
+ returns a single permalink to the project with query parameters.
19
+ Otherwise, returns individual permalinks for each file.
20
+ repo_type (str): Repository type ("space", "dataset", etc.). Default is "dataset".
21
+
22
+ Returns:
23
+ If create_permalink is True and files match the criteria:
24
+ tuple: (response, permalink) where response is the output of the batch upload
25
+ and permalink is the URL string (with fully qualified file paths) for the project.
26
+ Otherwise:
27
+ list: A list of tuples (response, permalink) for each file.
28
+ """
29
+ # Log in using the HF API token.
30
+ login(token=HF_API_TOKEN)
31
+
32
+ valid_files = []
33
+
34
+ # Ensure folder_name does not have a trailing slash.
35
+ folder_name = folder_name.rstrip("/")
36
+
37
+ # Filter for valid files based on allowed extensions.
38
+ for f in files:
39
+ file_name = f if isinstance(f, str) else f.name if hasattr(f, "name") else None
40
+ if file_name is None:
41
+ continue
42
+ ext = os.path.splitext(file_name)[1].lower()
43
+ if ext in upload_file_types:
44
+ valid_files.append(f)
45
+
46
+ if not valid_files:
47
+ return [] # or raise an exception
48
+
49
+ # Create a temporary directory and a sub-directory using folder_name; copy valid files into it.
50
+ with tempfile.TemporaryDirectory() as temp_dir:
51
+ target_dir = os.path.join(temp_dir, folder_name)
52
+ os.makedirs(target_dir, exist_ok=True)
53
+ for file_path in valid_files:
54
+ filename = os.path.basename(file_path)
55
+ dest_path = os.path.join(target_dir, filename)
56
+ shutil.copy(file_path, dest_path)
57
+
58
+ # Batch upload all files in the temporary folder.
59
+ # Files will be uploaded under the folder (path_in_repo) given by folder_name.
60
+ response = upload_folder(
61
+ folder_path=temp_dir,
62
+ repo_id=repo_id,
63
+ repo_type=repo_type,
64
+ path_in_repo=folder_name,
65
+ commit_message="Batch upload files"
66
+ )
67
+
68
+ # Construct external URLs for each uploaded file.
69
+ # For datasets, files are served at:
70
+ # https://huggingface.co/datasets/<repo_id>/resolve/main/<folder_name>/<filename>
71
+ base_url_external = f"https://huggingface.co/datasets/{repo_id}/resolve/main/{folder_name}"
72
+ individual_links = []
73
+ for file_path in valid_files:
74
+ filename = os.path.basename(file_path)
75
+ link = f"{base_url_external}/{filename}"
76
+ individual_links.append(link)
77
+
78
+ # If exactly 3 files are provided and create_permalink is True,
79
+ # check if they contain 1 model file and 2 image files.
80
+ if create_permalink and len(valid_files) == 3:
81
+ model_link = None
82
+ images_links = []
83
+ for f in valid_files:
84
+ filename = os.path.basename(f)
85
+ ext = os.path.splitext(filename)[1].lower()
86
+ if ext in model_extensions:
87
+ if model_link is None:
88
+ model_link = f"{base_url_external}/{filename}"
89
+ elif ext in image_extensions:
90
+ images_links.append(f"{base_url_external}/{filename}")
91
+ if model_link and len(images_links) == 2:
92
+ # Construct a permalink to the viewer project with querystring parameters.
93
+ base_viewer_url = "https://huggingface.co/spaces/Surn/3D-Viewer"
94
+ params = {"3d": model_link, "hm": images_links[0], "image": images_links[1]}
95
+ query_str = urllib.parse.urlencode(params)
96
+ permalink = f"{base_viewer_url}?{query_str}"
97
+ return response, permalink
98
+
99
+ # Otherwise, return individual tuples for each file.
100
+ return [(response, link) for link in individual_links]
style_20250503.css CHANGED
@@ -102,7 +102,7 @@ a {
102
  position: relative !important;
103
  }
104
 
105
- .gradio-container .image-container .preview.svelte-k63p1v {
106
  object-fit: cover;
107
  }
108
  .gradio-container::before {
@@ -115,7 +115,7 @@ a {
115
  height: 100%;
116
  opacity: 0.25;
117
  background-image: url('gradio_api/file=./images/logo.png');
118
- background-repeat:repeat ;
119
  background-position: 50% 0;
120
  background-size: contain;
121
  background-color: rgba(0,0,0,0.9);
 
102
  position: relative !important;
103
  }
104
 
105
+ .gradio-container .image-container .preview.svelte-k63p1v {
106
  object-fit: cover;
107
  }
108
  .gradio-container::before {
 
115
  height: 100%;
116
  opacity: 0.25;
117
  background-image: url('gradio_api/file=./images/logo.png');
118
+ background-repeat:repeat;
119
  background-position: 50% 0;
120
  background-size: contain;
121
  background-color: rgba(0,0,0,0.9);