Wauplin HF staff commited on
Commit
bb7fa45
1 Parent(s): 50c63ac

add migratin script

Browse files
Files changed (1) hide show
  1. user_history.py +93 -3
user_history.py CHANGED
@@ -1,3 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import json
2
  import os
3
  import shutil
@@ -20,6 +37,9 @@ def setup(folder_path: str | Path | None = None) -> None:
20
  user_history.folder_path = _resolve_folder_path(folder_path)
21
  user_history.initialized = True
22
 
 
 
 
23
 
24
  def render() -> None:
25
  user_history = _UserHistory()
@@ -46,9 +66,18 @@ def render() -> None:
46
  with gr.Row():
47
  gr.LoginButton(min_width=250)
48
  gr.LogoutButton(min_width=250)
49
- refresh_button = gr.Button("Refresh", icon="./assets/icon_refresh.png")
50
- export_button = gr.Button("Export", icon="./assets/icon_download.png")
51
- delete_button = gr.Button("Delete history", icon="./assets/icon_delete.png")
 
 
 
 
 
 
 
 
 
52
 
53
  # "Export zip" row (hidden by default)
54
  with gr.Row():
@@ -395,3 +424,64 @@ def _fetch_admins() -> List[str]:
395
  if response.status_code == 200:
396
  return sorted((member["user"] for member in response.json()), key=lambda x: x.lower())
397
  return [namespace]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ User History is a plugin that you can add to your Spaces to cache generated images for your users.
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.
10
+ - Admin panel to check configuration and disk usage .
11
+
12
+ Useful links:
13
+ - Demo: https://huggingface.co/spaces/Wauplin/gradio-user-history
14
+ - README: https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/README.md
15
+ - Source file: https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/user_history.py
16
+ - Discussions: https://huggingface.co/spaces/Wauplin/gradio-user-history/discussions
17
+ """
18
  import json
19
  import os
20
  import shutil
 
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()
 
66
  with gr.Row():
67
  gr.LoginButton(min_width=250)
68
  gr.LogoutButton(min_width=250)
69
+ refresh_button = gr.Button(
70
+ "Refresh",
71
+ icon="https://huggingface.co/spaces/Wauplin/gradio-user-history/resolve/main/assets/icon_refresh.png",
72
+ )
73
+ export_button = gr.Button(
74
+ "Export",
75
+ icon="https://huggingface.co/spaces/Wauplin/gradio-user-history/resolve/main/assets/icon_download.png",
76
+ )
77
+ delete_button = gr.Button(
78
+ "Delete history",
79
+ icon="https://huggingface.co/spaces/Wauplin/gradio-user-history/resolve/main/assets/icon_delete.png",
80
+ )
81
 
82
  # "Export zip" row (hidden by default)
83
  with gr.Row():
 
424
  if response.status_code == 200:
425
  return sorted((member["user"] for member in response.json()), key=lambda x: x.lower())
426
  return [namespace]
427
+
428
+
429
+ ################################################################
430
+ # Legacy helpers to migrate image structure to new data format #
431
+ ################################################################
432
+ # TODO: remove this section once all Spaces have migrated
433
+
434
+
435
+ def _migrate_history():
436
+ """Script to migrate user history from v0 to v1."""
437
+ legacy_history_path = _legacy_get_history_folder_path()
438
+ if not legacy_history_path.exists():
439
+ return
440
+
441
+ error_count = 0
442
+ for json_path in legacy_history_path.glob("*.json"):
443
+ username = json_path.stem
444
+ print(f"Migrating history for user {username}...")
445
+ error_count += _legacy_move_user_history(username)
446
+ print("Done.")
447
+ print(f"Migration complete. {error_count} error(s) happened.")
448
+
449
+ if error_count == 0:
450
+ shutil.rmtree(legacy_history_path, ignore_errors=True)
451
+
452
+
453
+ def _legacy_move_user_history(username: str) -> int:
454
+ history = _legacy_read_user_history(username)
455
+ error_count = 0
456
+ for image, prompt in reversed(history):
457
+ try:
458
+ save_image(label=prompt, image=image, profile={"preferred_username": username})
459
+ except Exception as e:
460
+ print("Issue while migrating image:", e)
461
+ error_count += 1
462
+ return error_count
463
+
464
+
465
+ def _legacy_get_history_folder_path() -> Path:
466
+ _folder = os.environ.get("HISTORY_FOLDER")
467
+ if _folder is None:
468
+ _folder = Path(__file__).parent / "history"
469
+ return Path(_folder)
470
+
471
+
472
+ def _legacy_read_user_history(username: str) -> List[Tuple[str, str]]:
473
+ """Return saved history for that user."""
474
+ with _legacy_user_lock(username):
475
+ path = _legacy_user_history_path(username)
476
+ if path.exists():
477
+ return json.loads(path.read_text())
478
+ return [] # No history yet
479
+
480
+
481
+ def _legacy_user_history_path(username: str) -> Path:
482
+ return _legacy_get_history_folder_path() / f"{username}.json"
483
+
484
+
485
+ def _legacy_user_lock(username: str) -> FileLock:
486
+ """Ensure history is not corrupted if concurrent calls."""
487
+ return FileLock(f"{_legacy_user_history_path(username)}.lock")