Surn commited on
Commit
ff1cd45
·
1 Parent(s): f60228d

Upgrade for Audio and Visual Files

Browse files
.gitignore CHANGED
@@ -141,4 +141,5 @@ cspell.json
141
 
142
  mock
143
  _user_history
144
- _user_history_exports
 
 
141
 
142
  mock
143
  _user_history
144
+ _user_history_exports
145
+ /.vs
README.md CHANGED
@@ -21,7 +21,7 @@ space_ci:
21
  ## Key features:
22
 
23
  - 🤗 **Sign in with Hugging Face**
24
- - **Save** generated images with their metadata: prompts, timestamp, hyper-parameters, etc.
25
  - **Export** your history as zip.
26
  - **Delete** your history to respect privacy.
27
  - Compatible with **Persistent Storage** for long-term storage.
 
21
  ## Key features:
22
 
23
  - 🤗 **Sign in with Hugging Face**
24
+ - **Save** generated image, video, audio and document files with their metadata: prompts, timestamp, hyper-parameters, etc.
25
  - **Export** your history as zip.
26
  - **Delete** your history to respect privacy.
27
  - Compatible with **Persistent Storage** for long-term storage.
requirements.txt CHANGED
@@ -1,2 +1,3 @@
1
  git+https://huggingface.co/spaces/Wauplin/gradio-user-history
2
  gradio-space-ci @ git+https://huggingface.co/spaces/Wauplin/[email protected]
 
 
1
  git+https://huggingface.co/spaces/Wauplin/gradio-user-history
2
  gradio-space-ci @ git+https://huggingface.co/spaces/Wauplin/[email protected]
3
+ filetype @ git+https://github.com/h2non/filetype.py.git
src/gradio_user_history/__init__.py CHANGED
@@ -3,7 +3,7 @@ User History is a plugin that you can add to your Spaces to cache generated imag
3
 
4
  Key features:
5
  - 🤗 Sign in with Hugging Face
6
- - Save generated images with their metadata: prompts, timestamp, hyper-parameters, etc.
7
  - Export your history as zip.
8
  - Delete your history to respect privacy.
9
  - Compatible with Persistent Storage for long-term storage.
@@ -18,4 +18,4 @@ Useful links:
18
  from ._user_history import render, save_image, setup # noqa: F401
19
 
20
 
21
- __version__ = "0.1.0"
 
3
 
4
  Key features:
5
  - 🤗 Sign in with Hugging Face
6
+ - Save generated image, video, audio and document files with their metadata: prompts, timestamp, hyper-parameters, etc.
7
  - Export your history as zip.
8
  - Delete your history to respect privacy.
9
  - Compatible with Persistent Storage for long-term storage.
 
18
  from ._user_history import render, save_image, setup # noqa: F401
19
 
20
 
21
+ __version__ = "0.2.0"
src/gradio_user_history/_user_history.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import json
2
  import os
3
  import shutil
@@ -13,6 +14,7 @@ import numpy as np
13
  import requests
14
  from filelock import FileLock
15
  from PIL.Image import Image
 
16
 
17
 
18
  def setup(folder_path: str | Path | None = None) -> None:
@@ -143,6 +145,56 @@ def save_image(
143
  with user_history._user_lock(username):
144
  with user_history._user_jsonl_path(username).open("a") as f:
145
  f.write(json.dumps(data) + "\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
 
148
  #############
@@ -178,7 +230,13 @@ class _UserHistory(object):
178
  path = self._user_path(username) / "images"
179
  path.mkdir(parents=True, exist_ok=True)
180
  return path
181
-
 
 
 
 
 
 
182
 
183
  def _fetch_user_history(profile: gr.OAuthProfile | None) -> List[Tuple[str, str]]:
184
  """Return saved history for that user, if it exists."""
@@ -262,12 +320,37 @@ def _copy_image(image: Image | np.ndarray | str | Path, dst_folder: Path) -> Pat
262
  if isinstance(image, np.ndarray):
263
  image = Image.fromarray(image)
264
  if isinstance(image, Image):
265
- dst = dst_folder / f"{uuid4().hex}.png"
266
  image.save(dst)
267
  return dst
268
 
269
  raise ValueError(f"Unsupported image type: {type(image)}")
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
  def _resolve_folder_path(folder_path: str | Path | None) -> Path:
273
  if folder_path is not None:
 
1
+
2
  import json
3
  import os
4
  import shutil
 
14
  import requests
15
  from filelock import FileLock
16
  from PIL.Image import Image
17
+ import filetype
18
 
19
 
20
  def setup(folder_path: str | Path | None = None) -> None:
 
145
  with user_history._user_lock(username):
146
  with user_history._user_jsonl_path(username).open("a") as f:
147
  f.write(json.dumps(data) + "\n")
148
+
149
+ def save_av(
150
+ profile: gr.OAuthProfile | None,
151
+ image: Image | np.ndarray | str | Path | None = None,
152
+ video: str | Path | None = None,
153
+ audio: str | Path | None = None,
154
+ document: str | Path | None = None,
155
+ label: str | None = None,
156
+ metadata: Dict | None = None,
157
+ ):
158
+ # Ignore files from logged out users
159
+ if profile is None:
160
+ return
161
+ username = profile["preferred_username"]
162
+
163
+ # Ignore files if user history not used
164
+ user_history = _UserHistory()
165
+ if not user_history.initialized:
166
+ warnings.warn(
167
+ "User history is not set in Gradio demo. Saving files is ignored. You must use `user_history.render(...)`"
168
+ " first."
169
+ )
170
+ return
171
+
172
+ # Copy image to storage
173
+ image_path = None
174
+ if image is not None:
175
+ image_path = _copy_image(image, dst_folder=user_history._user_images_path(username))
176
+
177
+ # Copy video to storage
178
+ if video is not None:
179
+ video_path = _copy_file(video, dst_folder=user_history._user_file_path(username, "videos"))
180
+
181
+ # Copy audio to storage
182
+ if audio is not None:
183
+ audio_path = _copy_file(audio, dst_folder=user_history._user_file_path(username, "audios"))
184
+
185
+ # Copy document to storage
186
+ if document is not None:
187
+ document_path = _copy_file(document, dst_folder=user_history._user_file_path(username, "documents"))
188
+
189
+ # Save new files + metadata
190
+ if metadata is None:
191
+ metadata = {}
192
+ if "datetime" not in metadata:
193
+ metadata["datetime"] = str(datetime.now())
194
+ data = {"image_path": str(image_path), "video_path": str(video_path), "audio_path": str(audio_path), "document_path": str(document_path), "label": label, "metadata": metadata}
195
+ with user_history._user_lock(username):
196
+ with user_history._user_jsonl_path(username).open("a") as f:
197
+ f.write(json.dumps(data) + "\n")
198
 
199
 
200
  #############
 
230
  path = self._user_path(username) / "images"
231
  path.mkdir(parents=True, exist_ok=True)
232
  return path
233
+
234
+ def _user_file_path(self, username: str, filetype: str = "images") -> Path:
235
+ path = self._user_path(username) / filetype
236
+ path.mkdir(parents=True, exist_ok=True)
237
+ return path
238
+
239
+
240
 
241
  def _fetch_user_history(profile: gr.OAuthProfile | None) -> List[Tuple[str, str]]:
242
  """Return saved history for that user, if it exists."""
 
320
  if isinstance(image, np.ndarray):
321
  image = Image.fromarray(image)
322
  if isinstance(image, Image):
323
+ dst = dst_folder / f"Path(file).name}_{uuid4().hex}.png"
324
  image.save(dst)
325
  return dst
326
 
327
  raise ValueError(f"Unsupported image type: {type(image)}")
328
 
329
+ def _copy_file(file: any | np.ndarray | str | Path, dst_folder: Path) -> Path:
330
+ """Copy file to the appropriate folder."""
331
+ # Already a path => copy it
332
+ if isinstance(file, str):
333
+ file = Path(file)
334
+ if isinstance(file, Path):
335
+ dst = dst_folder / f"{file.stem}_{uuid4().hex}{file.suffix}" # keep file ext
336
+ shutil.copyfile(file, dst)
337
+ return dst
338
+
339
+ # Still a Python object => serialize it
340
+ if isinstance(file, np.ndarray):
341
+ file = Image.fromarray(file)
342
+ dst = dst_folder / f"{file.filename}_{uuid4().hex}{file.suffix}"
343
+ file.save(dst)
344
+ return dst
345
+
346
+ # try other file types
347
+ kind = filetype.guess(file)
348
+ if kind is not None:
349
+ dst = dst_folder / f"{Path(file).stem}_{uuid4().hex}.{kind.extension}"
350
+ shutil.copyfile(file, dst)
351
+ return dst
352
+ raise ValueError(f"Unsupported file type: {type(file)}")
353
+
354
 
355
  def _resolve_folder_path(folder_path: str | Path | None) -> Path:
356
  if folder_path is not None: