Wauplin HF staff commited on
Commit
581f422
1 Parent(s): 2c19eba

Remove migration script (it has been migrated now)

Browse files
Files changed (1) hide show
  1. user_history.py +18 -137
user_history.py CHANGED
@@ -37,18 +37,13 @@ def setup(folder_path: str | Path | None = None) -> None:
37
  user_history.folder_path = _resolve_folder_path(folder_path)
38
  user_history.initialized = True
39
 
40
- # TODO: remove this section once all Spaces have migrated
41
- _migrate_history()
42
-
43
 
44
  def render() -> None:
45
  user_history = _UserHistory()
46
 
47
  # initialize with default config
48
  if not user_history.initialized:
49
- print(
50
- "Initializing user history with default config. Use `user_history.setup(...)` to customize folder_path."
51
- )
52
  setup()
53
 
54
  # Render user history tab
@@ -83,18 +78,11 @@ def render() -> None:
83
 
84
  # "Export zip" row (hidden by default)
85
  with gr.Row():
86
- export_file = gr.File(
87
- file_count="single",
88
- file_types=[".zip"],
89
- label="Exported history",
90
- visible=False,
91
- )
92
 
93
  # "Config deletion" row (hidden by default)
94
  with gr.Row():
95
- confirm_button = gr.Button(
96
- "Confirm delete all history", variant="stop", visible=False
97
- )
98
  cancel_button = gr.Button("Cancel", visible=False)
99
 
100
  # Gallery
@@ -117,12 +105,8 @@ def render() -> None:
117
  gallery.attach_load_event(_fetch_user_history, every=None)
118
 
119
  # Interactions
120
- refresh_button.click(
121
- fn=_fetch_user_history, inputs=[], outputs=[gallery], queue=False
122
- )
123
- export_button.click(
124
- fn=_export_user_history, inputs=[], outputs=[export_file], queue=False
125
- )
126
 
127
  # Taken from https://github.com/gradio-app/gradio/issues/3324#issuecomment-1446382045
128
  delete_button.click(
@@ -150,24 +134,6 @@ def save_image(
150
  image: Image | np.ndarray | str | Path,
151
  label: str | None = None,
152
  metadata: Dict | None = None,
153
- ):
154
- """Save an image in user history.
155
-
156
- You are guaranteed that calling `save_image` will not interrupt the main process. However, it is possible that for
157
- some reason the image is not saved correctly (wrong configuration, disk is full, image not valid,...). In that case
158
- the exception is silently ignored and a log is printed for Space owners.
159
- """
160
- try:
161
- _save_image(profile, image, label, metadata)
162
- except Exception as e:
163
- print("Error while saving image! ", e)
164
-
165
-
166
- def _save_image(
167
- profile: gr.OAuthProfile | None,
168
- image: Image | np.ndarray | str | Path,
169
- label: str | None = None,
170
- metadata: Dict | None = None,
171
  ):
172
  # Ignore images from logged out users
173
  if profile is None:
@@ -221,9 +187,7 @@ class _UserHistory(object):
221
 
222
  def _user_lock(self, username: str) -> FileLock:
223
  """Ensure history is not corrupted if concurrent calls."""
224
- return FileLock(
225
- self.folder_path / f"{username}.lock"
226
- ) # lock outside of folder => better when exporting ZIP
227
 
228
  def _user_jsonl_path(self, username: str) -> Path:
229
  return self._user_path(username) / "history.jsonl"
@@ -243,9 +207,7 @@ def _fetch_user_history(profile: gr.OAuthProfile | None) -> List[Tuple[str, str]
243
 
244
  user_history = _UserHistory()
245
  if not user_history.initialized:
246
- warnings.warn(
247
- "User history is not set in Gradio demo. You must use `user_history.render(...)` first."
248
- )
249
  return []
250
 
251
  with user_history._user_lock(username):
@@ -271,17 +233,13 @@ def _export_user_history(profile: gr.OAuthProfile | None) -> Dict | None:
271
 
272
  user_history = _UserHistory()
273
  if not user_history.initialized:
274
- warnings.warn(
275
- "User history is not set in Gradio demo. You must use `user_history.render(...)` first."
276
- )
277
  return None
278
 
279
  # Zip history
280
  with user_history._user_lock(username):
281
  path = shutil.make_archive(
282
- str(_archives_path() / f"history_{username}"),
283
- "zip",
284
- user_history._user_path(username),
285
  )
286
 
287
  return gr.update(visible=True, value=path)
@@ -296,9 +254,7 @@ def _delete_user_history(profile: gr.OAuthProfile | None) -> None:
296
 
297
  user_history = _UserHistory()
298
  if not user_history.initialized:
299
- warnings.warn(
300
- "User history is not set in Gradio demo. You must use `user_history.render(...)` first."
301
- )
302
  return
303
 
304
  with user_history._user_lock(username):
@@ -335,9 +291,7 @@ def _resolve_folder_path(folder_path: str | Path | None) -> Path:
335
  if folder_path is not None:
336
  return Path(folder_path).expanduser().resolve()
337
 
338
- if os.getenv("SYSTEM") == "spaces" and os.path.exists(
339
- "/data"
340
- ): # Persistent storage is enabled!
341
  return Path("/data") / "_user_history"
342
 
343
  # Not in a Space or Persistent storage not enabled => local folder
@@ -398,10 +352,8 @@ def _get_nb_users() -> int:
398
  user_history = _UserHistory()
399
  if not user_history.initialized:
400
  return 0
401
- if user_history.folder_path is not None:
402
- return len(
403
- [path for path in user_history.folder_path.iterdir() if path.is_dir()]
404
- )
405
  return 0
406
 
407
 
@@ -409,7 +361,7 @@ def _get_nb_images() -> int:
409
  user_history = _UserHistory()
410
  if not user_history.initialized:
411
  return 0
412
- if user_history.folder_path is not None:
413
  return len([path for path in user_history.folder_path.glob("*/images/*")])
414
  return 0
415
 
@@ -443,14 +395,10 @@ def _disk_space_warning_message() -> str:
443
 
444
 
445
  def _get_disk_usage(path: Path) -> Tuple[int, int, int]:
446
- for path in [path] + list(
447
- path.parents
448
- ): # first check target_dir, then each parents one by one
449
  try:
450
  return shutil.disk_usage(path)
451
- except (
452
- OSError
453
- ): # if doesn't exist or can't read => fail silently and try parent one
454
  pass
455
  return 0, 0, 0
456
 
@@ -469,74 +417,7 @@ def _fetch_admins() -> List[str]:
469
  # Running in Space => try to fetch organization members
470
  # Otherwise, it's not an organization => namespace is the user
471
  namespace = space_id.split("/")[0]
472
- response = requests.get(
473
- f"https://huggingface.co/api/organizations/{namespace}/members"
474
- )
475
  if response.status_code == 200:
476
- return sorted(
477
- (member["user"] for member in response.json()), key=lambda x: x.lower()
478
- )
479
  return [namespace]
480
-
481
-
482
- ################################################################
483
- # Legacy helpers to migrate image structure to new data format #
484
- ################################################################
485
- # TODO: remove this section once all Spaces have migrated
486
-
487
-
488
- def _migrate_history():
489
- """Script to migrate user history from v0 to v1."""
490
- legacy_history_path = _legacy_get_history_folder_path()
491
- if not legacy_history_path.exists():
492
- return
493
-
494
- error_count = 0
495
- for json_path in legacy_history_path.glob("*.json"):
496
- username = json_path.stem
497
- print(f"Migrating history for user {username}...")
498
- error_count += _legacy_move_user_history(username)
499
- print("Done.")
500
- print(f"Migration complete. {error_count} error(s) happened.")
501
-
502
- if error_count == 0:
503
- shutil.rmtree(legacy_history_path, ignore_errors=True)
504
-
505
-
506
- def _legacy_move_user_history(username: str) -> int:
507
- history = _legacy_read_user_history(username)
508
- error_count = 0
509
- for image, prompt in reversed(history):
510
- try:
511
- save_image(
512
- label=prompt, image=image, profile={"preferred_username": username}
513
- )
514
- except Exception as e:
515
- print("Issue while migrating image:", e)
516
- error_count += 1
517
- return error_count
518
-
519
-
520
- def _legacy_get_history_folder_path() -> Path:
521
- _folder = os.environ.get("HISTORY_FOLDER")
522
- if _folder is None:
523
- _folder = Path(__file__).parent / "history"
524
- return Path(_folder)
525
-
526
-
527
- def _legacy_read_user_history(username: str) -> List[Tuple[str, str]]:
528
- """Return saved history for that user."""
529
- with _legacy_user_lock(username):
530
- path = _legacy_user_history_path(username)
531
- if path.exists():
532
- return json.loads(path.read_text())
533
- return [] # No history yet
534
-
535
-
536
- def _legacy_user_history_path(username: str) -> Path:
537
- return _legacy_get_history_folder_path() / f"{username}.json"
538
-
539
-
540
- def _legacy_user_lock(username: str) -> FileLock:
541
- """Ensure history is not corrupted if concurrent calls."""
542
- return FileLock(f"{_legacy_user_history_path(username)}.lock")
 
37
  user_history.folder_path = _resolve_folder_path(folder_path)
38
  user_history.initialized = True
39
 
 
 
 
40
 
41
  def render() -> None:
42
  user_history = _UserHistory()
43
 
44
  # initialize with default config
45
  if not user_history.initialized:
46
+ print("Initializing user history with default config. Use `user_history.setup(...)` to customize folder_path.")
 
 
47
  setup()
48
 
49
  # Render user history tab
 
78
 
79
  # "Export zip" row (hidden by default)
80
  with gr.Row():
81
+ export_file = gr.File(file_count="single", file_types=[".zip"], label="Exported history", visible=False)
 
 
 
 
 
82
 
83
  # "Config deletion" row (hidden by default)
84
  with gr.Row():
85
+ confirm_button = gr.Button("Confirm delete all history", variant="stop", visible=False)
 
 
86
  cancel_button = gr.Button("Cancel", visible=False)
87
 
88
  # Gallery
 
105
  gallery.attach_load_event(_fetch_user_history, every=None)
106
 
107
  # Interactions
108
+ refresh_button.click(fn=_fetch_user_history, inputs=[], outputs=[gallery], queue=False)
109
+ export_button.click(fn=_export_user_history, inputs=[], outputs=[export_file], queue=False)
 
 
 
 
110
 
111
  # Taken from https://github.com/gradio-app/gradio/issues/3324#issuecomment-1446382045
112
  delete_button.click(
 
134
  image: Image | np.ndarray | str | Path,
135
  label: str | None = None,
136
  metadata: Dict | None = None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  ):
138
  # Ignore images from logged out users
139
  if profile is None:
 
187
 
188
  def _user_lock(self, username: str) -> FileLock:
189
  """Ensure history is not corrupted if concurrent calls."""
190
+ return FileLock(self.folder_path / f"{username}.lock") # lock outside of folder => better when exporting ZIP
 
 
191
 
192
  def _user_jsonl_path(self, username: str) -> Path:
193
  return self._user_path(username) / "history.jsonl"
 
207
 
208
  user_history = _UserHistory()
209
  if not user_history.initialized:
210
+ warnings.warn("User history is not set in Gradio demo. You must use `user_history.render(...)` first.")
 
 
211
  return []
212
 
213
  with user_history._user_lock(username):
 
233
 
234
  user_history = _UserHistory()
235
  if not user_history.initialized:
236
+ warnings.warn("User history is not set in Gradio demo. You must use `user_history.render(...)` first.")
 
 
237
  return None
238
 
239
  # Zip history
240
  with user_history._user_lock(username):
241
  path = shutil.make_archive(
242
+ str(_archives_path() / f"history_{username}"), "zip", user_history._user_path(username)
 
 
243
  )
244
 
245
  return gr.update(visible=True, value=path)
 
254
 
255
  user_history = _UserHistory()
256
  if not user_history.initialized:
257
+ warnings.warn("User history is not set in Gradio demo. You must use `user_history.render(...)` first.")
 
 
258
  return
259
 
260
  with user_history._user_lock(username):
 
291
  if folder_path is not None:
292
  return Path(folder_path).expanduser().resolve()
293
 
294
+ if os.getenv("SYSTEM") == "spaces" and os.path.exists("/data"): # Persistent storage is enabled!
 
 
295
  return Path("/data") / "_user_history"
296
 
297
  # Not in a Space or Persistent storage not enabled => local folder
 
352
  user_history = _UserHistory()
353
  if not user_history.initialized:
354
  return 0
355
+ if user_history.folder_path is not None and user_history.folder_path.exists():
356
+ return len([path for path in user_history.folder_path.iterdir() if path.is_dir()])
 
 
357
  return 0
358
 
359
 
 
361
  user_history = _UserHistory()
362
  if not user_history.initialized:
363
  return 0
364
+ if user_history.folder_path is not None and user_history.folder_path.exists():
365
  return len([path for path in user_history.folder_path.glob("*/images/*")])
366
  return 0
367
 
 
395
 
396
 
397
  def _get_disk_usage(path: Path) -> Tuple[int, int, int]:
398
+ for path in [path] + list(path.parents): # first check target_dir, then each parents one by one
 
 
399
  try:
400
  return shutil.disk_usage(path)
401
+ except OSError: # if doesn't exist or can't read => fail silently and try parent one
 
 
402
  pass
403
  return 0, 0, 0
404
 
 
417
  # Running in Space => try to fetch organization members
418
  # Otherwise, it's not an organization => namespace is the user
419
  namespace = space_id.split("/")[0]
420
+ response = requests.get(f"https://huggingface.co/api/organizations/{namespace}/members")
 
 
421
  if response.status_code == 200:
422
+ return sorted((member["user"] for member in response.json()), key=lambda x: x.lower())
 
 
423
  return [namespace]