akazemian commited on
Commit
6282cbe
Β·
verified Β·
1 Parent(s): b3908ac

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +266 -61
app.py CHANGED
@@ -13,15 +13,16 @@ INDEX_FILENAME = "index.csv"
13
  DB_PATH = "library.csv"
14
  ALLOWED_EXTS = {".html"}
15
 
16
- # Columns in DB (no model_name)
17
- EXTRA_COLS = ["category", "dataset"]
18
  BASE_COLS = ["id","filename","path","tags","keywords","notes","uploaded_at"]
19
  ALL_DB_COLS = BASE_COLS + EXTRA_COLS
20
 
21
- # Columns shown in the table (no model_name)
22
  TABLE_COLS = ["id","filename","category","dataset",
23
  "tags","keywords","notes","uploaded_at"]
24
 
 
25
  # ---------- DB helpers ----------
26
  def _load_db() -> pd.DataFrame:
27
  if os.path.exists(DB_PATH):
@@ -29,11 +30,19 @@ def _load_db() -> pd.DataFrame:
29
  for c in ALL_DB_COLS:
30
  if c not in df.columns:
31
  df[c] = ""
32
- for c in ["tags","keywords","notes","category","dataset"]:
33
  df[c] = df[c].fillna("").astype(str)
34
  return df[ALL_DB_COLS]
35
  return pd.DataFrame(columns=ALL_DB_COLS)
36
 
 
 
 
 
 
 
 
 
37
  def _save_db(df: pd.DataFrame):
38
  df.to_csv(DB_PATH, index=False)
39
 
@@ -81,52 +90,114 @@ def _load_hf_index() -> pd.DataFrame:
81
 
82
  # ---------- Sync by model (prefix inside HF dataset) ----------
83
  def sync_model(model_name: str):
84
- """
85
- Load index.csv from HF, add rows for the selected model (by relpath prefix),
86
- store HF URIs in DB, and show only that model’s files.
87
- """
88
  model_name = (model_name or "").strip()
89
  if not model_name:
90
- return gr.Info("Please enter a model name."), None, None, None, ""
91
 
 
92
  try:
93
  idx = _load_hf_index()
94
  except Exception as e:
95
  traceback.print_exc()
96
- return gr.Info(f"Failed to load index from HF: {e}"), None, None, None, ""
97
-
98
- # rows like "{model_name}/.../file.html"
99
- subset = idx[idx["relpath"].str.startswith(model_name + "/")]
100
- if subset.empty:
101
- return gr.Info(f"No HTML files found for model '{model_name}' on {HF_DATASET_REPO}"), None, None, None, ""
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- df = _load_db()
104
  now = datetime.datetime.now().isoformat(timespec="seconds")
105
  new_rows = []
106
-
107
- for _, r in subset.iterrows():
108
- relpath = r["relpath"]
109
- hub_uri = f"hf://{HF_DATASET_REPO}/{relpath}"
110
- if (df["path"] == hub_uri).any():
 
 
 
111
  continue
112
  new_rows.append({
113
- "id": r["id"] if r["id"] else uuid.uuid4().hex[:8],
114
  "filename": r["filename"],
115
- "path": hub_uri, # store HF URI
 
116
  "tags": r["tags"],
117
  "keywords": r["keywords"],
118
  "notes": r["notes"],
119
  "uploaded_at": r["uploaded_at"] or now,
120
  "category": r["category"],
121
- "dataset": r["dataset"]
122
  })
123
 
124
  if new_rows:
125
- df = pd.concat([df, pd.DataFrame(new_rows)], ignore_index=True)
126
- _save_db(df)
127
-
128
- current_model = model_name # remember which model prefix is active
129
- return refresh_view("", [], "", "", current_model) + (current_model,)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
  # ---------- Search / filters ----------
132
  def refresh_view(query, tag_filters, category_filter, dataset_filter, current_model):
@@ -184,30 +255,14 @@ def refresh_view(query, tag_filters, category_filter, dataset_filter, current_mo
184
  def _iframe_from_html_string(raw_html: str, height_px: int = 720) -> str:
185
  srcdoc = raw_html.replace("&", "&").replace('"', """)
186
  return f'<iframe style="width:100%;height:{height_px}px;border:1px solid #ddd;border-radius:8px;" srcdoc="{srcdoc}"></iframe>'
187
-
188
- def select_row(evt: gr.SelectData, table_value):
189
  try:
190
  view = _df_from_table_value(table_value)
191
  if view.empty:
192
  return "<em>No rows.</em>", ""
193
- # resolve row
194
- row_idx = None
195
- ix = getattr(evt, "index", None)
196
- if isinstance(ix, int):
197
- row_idx = ix
198
- elif isinstance(ix, (list, tuple)) and ix and isinstance(ix[0], int):
199
- row_idx = ix[0]
200
- if row_idx is None:
201
- val = getattr(evt, "value", None)
202
- if isinstance(val, dict) and "id" in val:
203
- hits = view.index[view["id"] == val["id"]].tolist()
204
- if hits: row_idx = hits[0]
205
- elif isinstance(val, list) and len(val) >= 1:
206
- hits = view.index[view["id"] == val[0]].tolist()
207
- if hits: row_idx = hits[0]
208
- if row_idx is None or not (0 <= row_idx < len(view)):
209
- return "<em>Invalid selection.</em>", ""
210
 
 
 
211
  row = view.iloc[row_idx]
212
  sel_id = row["id"]
213
 
@@ -216,31 +271,93 @@ def select_row(evt: gr.SelectData, table_value):
216
  if rec.empty:
217
  return "<em>Could not find file for this row.</em>", ""
218
 
219
- path_str = rec["path"].values[0]
 
 
 
220
 
221
- # Hub-backed path β†’ lazy download
222
- if str(path_str).startswith("hf://"):
 
 
223
  _, rest = path_str.split("hf://", 1)
224
  repo_id, relpath = rest.split("/", 1)
225
  local_path = hf_hub_download(repo_id=repo_id, repo_type="dataset", filename=relpath)
226
  raw_html = Path(local_path).read_text(encoding="utf-8")
227
- elif str(path_str).startswith("http"):
228
- # if you ever swap to CDN URLs, iframe the URL directly
 
 
229
  iframe = f'<iframe style="width:100%;height:720px;border:1px solid #ddd;border-radius:8px;" src="{_py_html.escape(path_str)}"></iframe>'
230
  return iframe, f"πŸ“„ {row['filename']}"
231
- else:
232
- # local file fallback (not used for HF flow, kept for compatibility)
233
- p = Path(path_str)
234
- if not p.exists():
235
- return f"<em>File not found:</em> <code>{_py_html.escape(str(p))}</code>", f"πŸ“„ {row['filename']}"
236
- raw_html = p.read_text(encoding="utf-8")
237
 
 
 
 
 
 
238
  iframe = _iframe_from_html_string(raw_html, height_px=720)
239
  return iframe, f"πŸ“„ {row['filename']}"
240
  except Exception as e:
241
  traceback.print_exc()
242
  return f"<pre>Failed to render (see terminal):\n{_py_html.escape(str(e))}</pre>", ""
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  # ---------- Save edits ----------
245
  def save_edits(edited_table, current_model):
246
  if edited_table is None or not len(edited_table):
@@ -298,9 +415,82 @@ custom_css = """
298
  }
299
  """
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  with gr.Blocks(title="Audio HTML Library", css=custom_css) as demo:
302
  gr.Markdown("## 🎧 Audio Reconstruction Reports β€” sync β€’ search β€’ view")
303
  current_model = gr.State("") # remembers active model prefix inside HF repo
 
304
 
305
  with gr.Row():
306
  with gr.Column(scale=1):
@@ -315,6 +505,15 @@ with gr.Blocks(title="Audio HTML Library", css=custom_css) as demo:
315
  tag_filter = gr.CheckboxGroup(choices=[], label="Filter by tags (AND)")
316
  category_filter = gr.Dropdown(choices=[], label="Category")
317
  dataset_filter = gr.Dropdown(choices=[], label="Dataset")
 
 
 
 
 
 
 
 
 
318
  refresh_btn = gr.Button("Refresh", elem_id="refresh-btn")
319
 
320
  with gr.Column(scale=2):
@@ -348,14 +547,20 @@ with gr.Blocks(title="Audio HTML Library", css=custom_css) as demo:
348
  [table, tag_filter, category_filter, dataset_filter, count_md]
349
  )
350
 
351
- for comp in (query, tag_filter, category_filter, dataset_filter):
 
352
  comp.change(
353
  refresh_view,
354
  [query, tag_filter, category_filter, dataset_filter, current_model],
355
  [table, tag_filter, category_filter, dataset_filter, count_md]
356
  )
357
 
358
- table.select(select_row, [table], [preview_html, preview_label])
 
 
 
 
 
359
  save_btn.click(save_edits, [table, current_model], [table])
360
 
361
  # initial load (no model yet)
 
13
  DB_PATH = "library.csv"
14
  ALLOWED_EXTS = {".html"}
15
 
16
+ # Columns in DB
17
+ EXTRA_COLS = ["category", "dataset", "hf_path"] # <-- add hf_path here
18
  BASE_COLS = ["id","filename","path","tags","keywords","notes","uploaded_at"]
19
  ALL_DB_COLS = BASE_COLS + EXTRA_COLS
20
 
21
+ # Columns shown in the table (don't show hf_path)
22
  TABLE_COLS = ["id","filename","category","dataset",
23
  "tags","keywords","notes","uploaded_at"]
24
 
25
+
26
  # ---------- DB helpers ----------
27
  def _load_db() -> pd.DataFrame:
28
  if os.path.exists(DB_PATH):
 
30
  for c in ALL_DB_COLS:
31
  if c not in df.columns:
32
  df[c] = ""
33
+ for c in ["tags","keywords","notes","category","dataset","hf_path","path","filename","id","uploaded_at"]:
34
  df[c] = df[c].fillna("").astype(str)
35
  return df[ALL_DB_COLS]
36
  return pd.DataFrame(columns=ALL_DB_COLS)
37
 
38
+ def _load_hf_index() -> pd.DataFrame:
39
+ p = hf_hub_download(repo_id=HF_DATASET_REPO, repo_type="dataset", filename=INDEX_FILENAME)
40
+ df = pd.read_csv(p)
41
+ for c in ["id","filename","relpath","category","dataset","tags","keywords","notes","uploaded_at"]:
42
+ if c not in df.columns:
43
+ df[c] = ""
44
+ return df.fillna("")
45
+
46
  def _save_db(df: pd.DataFrame):
47
  df.to_csv(DB_PATH, index=False)
48
 
 
90
 
91
  # ---------- Sync by model (prefix inside HF dataset) ----------
92
  def sync_model(model_name: str):
 
 
 
 
93
  model_name = (model_name or "").strip()
94
  if not model_name:
95
+ return gr.Info("Please enter a model name."), None, None, None, "", ""
96
 
97
+ # 1) read index from HF and filter to this model prefix
98
  try:
99
  idx = _load_hf_index()
100
  except Exception as e:
101
  traceback.print_exc()
102
+ return gr.Info(f"Failed to load index from HF: {e}"), None, None, None, "", ""
103
+
104
+ sub = idx[idx["relpath"].astype(str).str.startswith(f"{model_name}/")]
105
+ if sub.empty:
106
+ return gr.Info(f"No HTML files found for model '{model_name}' on {HF_DATASET_REPO}"), None, None, None, "", ""
107
+
108
+ # 2) load local DB, backfill hf_path for existing rows of this model
109
+ db = _load_db()
110
+
111
+ # any existing rows whose filename appears in this model β†’ rewrite hf_path
112
+ if not db.empty:
113
+ # Build map: filename -> relpath (works if filenames are unique per model)
114
+ rel_by_fname = dict(zip(sub["filename"].astype(str), sub["relpath"].astype(str)))
115
+ mask_model_rows = db["filename"].isin(rel_by_fname.keys())
116
+ db.loc[mask_model_rows, "hf_path"] = db.loc[mask_model_rows, "filename"].map(
117
+ lambda fn: f"hf://{HF_DATASET_REPO}/{rel_by_fname.get(fn, fn)}"
118
+ )
119
 
120
+ # 3) add any missing rows from HF index
121
  now = datetime.datetime.now().isoformat(timespec="seconds")
122
  new_rows = []
123
+ existing_hf = set(db["hf_path"].astype(str))
124
+ for _, r in sub.iterrows():
125
+ hf_uri = f"hf://{HF_DATASET_REPO}/{r['relpath']}"
126
+ if hf_uri in existing_hf:
127
+ continue
128
+ # try to find by filename match in local path rows
129
+ if not db[db["filename"] == r["filename"]].empty:
130
+ # row exists, just set hf_path (done above), skip adding duplicate line
131
  continue
132
  new_rows.append({
133
+ "id": (r["id"] or uuid.uuid4().hex[:8]),
134
  "filename": r["filename"],
135
+ "path": "", # no local path known
136
+ "hf_path": hf_uri, # <-- set hf path
137
  "tags": r["tags"],
138
  "keywords": r["keywords"],
139
  "notes": r["notes"],
140
  "uploaded_at": r["uploaded_at"] or now,
141
  "category": r["category"],
142
+ "dataset": r["dataset"],
143
  })
144
 
145
  if new_rows:
146
+ db = pd.concat([db, pd.DataFrame(new_rows)], ignore_index=True)
147
+ _save_db(db)
148
+ else:
149
+ _save_db(db) # still write back if we updated hf_path on existing rows
150
+
151
+ current_model = model_name
152
+ return refresh_view("", [], "", "", current_model) + (current_model, "HF")
153
+
154
+ # def sync_model(model_name: str):
155
+ # """
156
+ # Load index.csv from HF, add rows for the selected model (by relpath prefix),
157
+ # store HF URIs in DB, and show only that model’s files.
158
+ # """
159
+ # model_name = (model_name or "").strip()
160
+ # if not model_name:
161
+ # return gr.Info("Please enter a model name."), None, None, None, ""
162
+
163
+ # try:
164
+ # idx = _load_hf_index()
165
+ # except Exception as e:
166
+ # traceback.print_exc()
167
+ # return gr.Info(f"Failed to load index from HF: {e}"), None, None, None, ""
168
+
169
+ # # rows like "{model_name}/.../file.html"
170
+ # subset = idx[idx["relpath"].str.startswith(model_name + "/")]
171
+ # if subset.empty:
172
+ # return gr.Info(f"No HTML files found for model '{model_name}' on {HF_DATASET_REPO}"), None, None, None, ""
173
+
174
+ # df = _load_db()
175
+ # now = datetime.datetime.now().isoformat(timespec="seconds")
176
+ # new_rows = []
177
+
178
+ # for _, r in subset.iterrows():
179
+ # relpath = r["relpath"]
180
+ # hub_uri = f"hf://{HF_DATASET_REPO}/{relpath}"
181
+ # if (df["path"] == hub_uri).any():
182
+ # continue
183
+ # new_rows.append({
184
+ # "id": r["id"] if r["id"] else uuid.uuid4().hex[:8],
185
+ # "filename": r["filename"],
186
+ # "path": hub_uri, # store HF URI
187
+ # "tags": r["tags"],
188
+ # "keywords": r["keywords"],
189
+ # "notes": r["notes"],
190
+ # "uploaded_at": r["uploaded_at"] or now,
191
+ # "category": r["category"],
192
+ # "dataset": r["dataset"]
193
+ # })
194
+
195
+ # if new_rows:
196
+ # df = pd.concat([df, pd.DataFrame(new_rows)], ignore_index=True)
197
+ # _save_db(df)
198
+
199
+ # current_model = model_name # remember which model prefix is active
200
+ # return refresh_view("", [], "", "", current_model) + (current_model,)
201
 
202
  # ---------- Search / filters ----------
203
  def refresh_view(query, tag_filters, category_filter, dataset_filter, current_model):
 
255
  def _iframe_from_html_string(raw_html: str, height_px: int = 720) -> str:
256
  srcdoc = raw_html.replace("&", "&amp;").replace('"', "&quot;")
257
  return f'<iframe style="width:100%;height:{height_px}px;border:1px solid #ddd;border-radius:8px;" srcdoc="{srcdoc}"></iframe>'
258
+ def select_row(evt: gr.SelectData, table_value, source_mode):
 
259
  try:
260
  view = _df_from_table_value(table_value)
261
  if view.empty:
262
  return "<em>No rows.</em>", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
+ # resolve row_idx ... (unchanged)
265
+ # ...
266
  row = view.iloc[row_idx]
267
  sel_id = row["id"]
268
 
 
271
  if rec.empty:
272
  return "<em>Could not find file for this row.</em>", ""
273
 
274
+ # pick which column to use
275
+ use_hf = (str(source_mode).upper() == "HF")
276
+ path_str = rec["hf_path"].values[0] if use_hf else rec["path"].values[0]
277
+ path_str = str(path_str or "")
278
 
279
+ if not path_str:
280
+ return "<em>No path available for this source.</em>", f"πŸ“„ {row['filename']}"
281
+
282
+ if path_str.startswith("hf://"):
283
  _, rest = path_str.split("hf://", 1)
284
  repo_id, relpath = rest.split("/", 1)
285
  local_path = hf_hub_download(repo_id=repo_id, repo_type="dataset", filename=relpath)
286
  raw_html = Path(local_path).read_text(encoding="utf-8")
287
+ iframe = _iframe_from_html_string(raw_html, height_px=720)
288
+ return iframe, f"πŸ“„ {row['filename']}"
289
+
290
+ if path_str.startswith("http"):
291
  iframe = f'<iframe style="width:100%;height:720px;border:1px solid #ddd;border-radius:8px;" src="{_py_html.escape(path_str)}"></iframe>'
292
  return iframe, f"πŸ“„ {row['filename']}"
 
 
 
 
 
 
293
 
294
+ # local fallback
295
+ p = Path(path_str)
296
+ if not p.exists():
297
+ return f"<em>File not found:</em> <code>{_py_html.escape(str(p))}</code>", f"πŸ“„ {row['filename']}"
298
+ raw_html = p.read_text(encoding="utf-8")
299
  iframe = _iframe_from_html_string(raw_html, height_px=720)
300
  return iframe, f"πŸ“„ {row['filename']}"
301
  except Exception as e:
302
  traceback.print_exc()
303
  return f"<pre>Failed to render (see terminal):\n{_py_html.escape(str(e))}</pre>", ""
304
 
305
+ # def select_row(evt: gr.SelectData, table_value):
306
+ # try:
307
+ # view = _df_from_table_value(table_value)
308
+ # if view.empty:
309
+ # return "<em>No rows.</em>", ""
310
+ # # resolve row
311
+ # row_idx = None
312
+ # ix = getattr(evt, "index", None)
313
+ # if isinstance(ix, int):
314
+ # row_idx = ix
315
+ # elif isinstance(ix, (list, tuple)) and ix and isinstance(ix[0], int):
316
+ # row_idx = ix[0]
317
+ # if row_idx is None:
318
+ # val = getattr(evt, "value", None)
319
+ # if isinstance(val, dict) and "id" in val:
320
+ # hits = view.index[view["id"] == val["id"]].tolist()
321
+ # if hits: row_idx = hits[0]
322
+ # elif isinstance(val, list) and len(val) >= 1:
323
+ # hits = view.index[view["id"] == val[0]].tolist()
324
+ # if hits: row_idx = hits[0]
325
+ # if row_idx is None or not (0 <= row_idx < len(view)):
326
+ # return "<em>Invalid selection.</em>", ""
327
+
328
+ # row = view.iloc[row_idx]
329
+ # sel_id = row["id"]
330
+
331
+ # db = _load_db()
332
+ # rec = db[db["id"] == sel_id]
333
+ # if rec.empty:
334
+ # return "<em>Could not find file for this row.</em>", ""
335
+
336
+ # path_str = rec["path"].values[0]
337
+
338
+ # # Hub-backed path β†’ lazy download
339
+ # if str(path_str).startswith("hf://"):
340
+ # _, rest = path_str.split("hf://", 1)
341
+ # repo_id, relpath = rest.split("/", 1)
342
+ # local_path = hf_hub_download(repo_id=repo_id, repo_type="dataset", filename=relpath)
343
+ # raw_html = Path(local_path).read_text(encoding="utf-8")
344
+ # elif str(path_str).startswith("http"):
345
+ # # if you ever swap to CDN URLs, iframe the URL directly
346
+ # iframe = f'<iframe style="width:100%;height:720px;border:1px solid #ddd;border-radius:8px;" src="{_py_html.escape(path_str)}"></iframe>'
347
+ # return iframe, f"πŸ“„ {row['filename']}"
348
+ # else:
349
+ # # local file fallback (not used for HF flow, kept for compatibility)
350
+ # p = Path(path_str)
351
+ # if not p.exists():
352
+ # return f"<em>File not found:</em> <code>{_py_html.escape(str(p))}</code>", f"πŸ“„ {row['filename']}"
353
+ # raw_html = p.read_text(encoding="utf-8")
354
+
355
+ # iframe = _iframe_from_html_string(raw_html, height_px=720)
356
+ # return iframe, f"πŸ“„ {row['filename']}"
357
+ # except Exception as e:
358
+ # traceback.print_exc()
359
+ # return f"<pre>Failed to render (see terminal):\n{_py_html.escape(str(e))}</pre>", ""
360
+
361
  # ---------- Save edits ----------
362
  def save_edits(edited_table, current_model):
363
  if edited_table is None or not len(edited_table):
 
415
  }
416
  """
417
 
418
+ # with gr.Blocks(title="Audio HTML Library", css=custom_css) as demo:
419
+ # gr.Markdown("## 🎧 Audio Reconstruction Reports β€” sync β€’ search β€’ view")
420
+ # current_model = gr.State("") # remembers active model prefix inside HF repo
421
+ # source_mode = gr.State("HF") # default
422
+
423
+
424
+ # with gr.Row():
425
+ # with gr.Column(scale=1):
426
+ # # Choose model & sync
427
+ # gr.Markdown(f"**Model prefix on HF dataset:** `{HF_DATASET_REPO}/<model_name>/...`")
428
+ # model_in = gr.Textbox(label="Model name", placeholder="e.g., WavCochV8192")
429
+ # sync_btn = gr.Button("Sync this model", elem_id="sync-btn")
430
+
431
+ # # Search & filters
432
+ # gr.Markdown("---\n**Search & filter**")
433
+ # query = gr.Textbox(label="Keyword search (filename/tags/notes/category/dataset)", placeholder="type to search…")
434
+ # tag_filter = gr.CheckboxGroup(choices=[], label="Filter by tags (AND)")
435
+ # category_filter = gr.Dropdown(choices=[], label="Category")
436
+ # dataset_filter = gr.Dropdown(choices=[], label="Dataset")
437
+ # refresh_btn = gr.Button("Refresh", elem_id="refresh-btn")
438
+
439
+ # with gr.Column(scale=2):
440
+ # # Count of current view
441
+ # count_md = gr.Markdown("**Showing 0 file(s)**")
442
+ # gr.Markdown("**Library** (click a row to preview; edit cells and Save)")
443
+ # table = gr.Dataframe(
444
+ # headers=TABLE_COLS,
445
+ # datatype=["str"] * len(TABLE_COLS),
446
+ # interactive=True,
447
+ # wrap=True,
448
+ # row_count=(0, "dynamic"),
449
+ # col_count=(len(TABLE_COLS), "fixed")
450
+ # )
451
+ # with gr.Row():
452
+ # save_btn = gr.Button("Save Edits", elem_id="save-btn")
453
+ # preview_label = gr.Markdown("")
454
+ # preview_html = gr.HTML("")
455
+
456
+ # # wiring: sync (also sets current_model)
457
+ # sync_btn.click(
458
+ # sync_model,
459
+ # [model_in],
460
+ # [table, tag_filter, category_filter, dataset_filter, count_md, current_model]
461
+ # )
462
+
463
+ # # wiring: refresh + live filters (respect current_model)
464
+ # refresh_btn.click(
465
+ # refresh_view,
466
+ # [query, tag_filter, category_filter, dataset_filter, current_model],
467
+ # [table, tag_filter, category_filter, dataset_filter, count_md]
468
+ # )
469
+
470
+ # for comp in (query, tag_filter, category_filter, dataset_filter):
471
+ # comp.change(
472
+ # refresh_view,
473
+ # [query, tag_filter, category_filter, dataset_filter, current_model],
474
+ # [table, tag_filter, category_filter, dataset_filter, count_md]
475
+ # )
476
+
477
+ # table.select(select_row, [table], [preview_html, preview_label])
478
+ # save_btn.click(save_edits, [table, current_model], [table])
479
+
480
+ # # initial load (no model yet)
481
+ # demo.load(
482
+ # refresh_view,
483
+ # [query, tag_filter, category_filter, dataset_filter, current_model],
484
+ # [table, tag_filter, category_filter, dataset_filter, count_md]
485
+ # )
486
+
487
+ # if __name__ == "__main__":
488
+ # demo.launch(share=True) # auth optional
489
+
490
  with gr.Blocks(title="Audio HTML Library", css=custom_css) as demo:
491
  gr.Markdown("## 🎧 Audio Reconstruction Reports β€” sync β€’ search β€’ view")
492
  current_model = gr.State("") # remembers active model prefix inside HF repo
493
+ source_mode = gr.State("HF") # default
494
 
495
  with gr.Row():
496
  with gr.Column(scale=1):
 
505
  tag_filter = gr.CheckboxGroup(choices=[], label="Filter by tags (AND)")
506
  category_filter = gr.Dropdown(choices=[], label="Category")
507
  dataset_filter = gr.Dropdown(choices=[], label="Dataset")
508
+
509
+ # πŸ”½ Step 5: Source toggle (HF vs Local)
510
+ mode_radio = gr.Radio(
511
+ choices=["HF", "Local"],
512
+ value="HF",
513
+ label="Source",
514
+ info="Preview from HF dataset or local disk"
515
+ )
516
+
517
  refresh_btn = gr.Button("Refresh", elem_id="refresh-btn")
518
 
519
  with gr.Column(scale=2):
 
547
  [table, tag_filter, category_filter, dataset_filter, count_md]
548
  )
549
 
550
+ # Trigger refresh when any filter OR source mode changes
551
+ for comp in (query, tag_filter, category_filter, dataset_filter, mode_radio):
552
  comp.change(
553
  refresh_view,
554
  [query, tag_filter, category_filter, dataset_filter, current_model],
555
  [table, tag_filter, category_filter, dataset_filter, count_md]
556
  )
557
 
558
+ # Keep source_mode state in sync with the radio
559
+ mode_radio.change(lambda x: x, [mode_radio], [source_mode])
560
+
561
+ # Pass source_mode into select_row so it can choose hf_path vs path
562
+ table.select(select_row, [table, source_mode], [preview_html, preview_label])
563
+
564
  save_btn.click(save_edits, [table, current_model], [table])
565
 
566
  # initial load (no model yet)