Hfzune commited on
Commit
eba4f56
·
verified ·
1 Parent(s): a78dd64

Update admin/panel.py

Browse files
Files changed (1) hide show
  1. admin/panel.py +162 -37
admin/panel.py CHANGED
@@ -18,22 +18,17 @@ def _gate(supplied: str) -> bool:
18
 
19
 
20
  def build_admin_tabs(admin_password: str = None):
21
- """
22
- Build the admin UI *inside* the current Gradio Blocks context.
23
- No second Gradio app, no mount, no SSR proxy.
24
- """
25
  global ADMIN_PASSWORD
26
  if admin_password:
27
  ADMIN_PASSWORD = admin_password
28
 
29
- # --- Login gate (always visible) ---
30
  with gr.Row():
31
  pw = gr.Textbox(label="Admin password", type="password", scale=3)
32
  login_btn = gr.Button("Login", scale=1, variant="primary")
33
 
34
  status_md = gr.Markdown("🔒 Locked. Enter password above.")
35
 
36
- # --- Admin content (hidden until login) ---
37
  with gr.Column(visible=False) as admin_area:
38
  with gr.Tabs():
39
 
@@ -121,8 +116,12 @@ def build_admin_tabs(admin_password: str = None):
121
  del_btn.click(_del, inputs=[del_uid], outputs=del_out,
122
  queue=False, show_progress=False)
123
 
124
- # ============ Conversations ============
125
  with gr.Tab("💬 Conversations"):
 
 
 
 
126
  with gr.Row():
127
  conv_uid = gr.Number(label="Filter user_id (blank = all)",
128
  precision=0, scale=2)
@@ -151,7 +150,7 @@ def build_admin_tabs(admin_password: str = None):
151
  outputs=conv_table,
152
  queue=False, show_progress=False)
153
 
154
- gr.Markdown("### Export")
155
  with gr.Row():
156
  exp_json_btn = gr.Button("📦 JSON")
157
  exp_csv_btn = gr.Button("📊 CSV")
@@ -184,6 +183,124 @@ def build_admin_tabs(admin_password: str = None):
184
  exp_md_btn.click(_write_md, outputs=exp_file,
185
  queue=False, show_progress=False)
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  # ============ Tokens ============
188
  with gr.Tab("🎟️ Tokens"):
189
  tok_table = gr.Dataframe(
@@ -236,30 +353,35 @@ def build_admin_tabs(admin_password: str = None):
236
  queue=False, show_progress=False)
237
 
238
  # ============ Settings ============
239
- with gr.Tab("⚙️ Settings"):
240
- gr.Markdown("Changes apply immediately.")
241
 
242
  window = gr.Number(label="conversation_window (turns)",
243
- value=int(dbm.get_setting("conversation_window", "6")),
244
- precision=0)
245
  max_new = gr.Number(label="max_new_tokens",
246
- value=int(dbm.get_setting("max_new_tokens", "1024")),
247
- precision=0)
248
- temp = gr.Number(label="temperature",
249
- value=float(dbm.get_setting("temperature", "0.7")))
250
- topp = gr.Number(label="top_p",
251
- value=float(dbm.get_setting("top_p", "0.9")))
252
- sys_prompt = gr.Textbox(label="system_prompt",
253
- value=dbm.get_setting("system_prompt",
254
- "You are a helpful assistant."),
255
- lines=4)
256
  daily_limit = gr.Number(label="daily_turn_limit",
257
- value=int(dbm.get_setting("daily_turn_limit", "100")),
258
- precision=0)
 
 
 
259
 
260
- save_settings = gr.Button("💾 Save settings", variant="primary")
261
  settings_out = gr.Markdown()
262
 
 
 
 
 
 
 
 
 
 
 
263
  def _save(w, mn, t, tp, sp, dl):
264
  dbm.set_setting("conversation_window", int(w))
265
  dbm.set_setting("max_new_tokens", int(mn))
@@ -267,7 +389,9 @@ def build_admin_tabs(admin_password: str = None):
267
  dbm.set_setting("top_p", float(tp))
268
  dbm.set_setting("system_prompt", sp)
269
  dbm.set_setting("daily_turn_limit", int(dl))
270
- return "✅ Saved."
 
 
271
 
272
  save_settings.click(
273
  _save,
@@ -276,6 +400,18 @@ def build_admin_tabs(admin_password: str = None):
276
  queue=False, show_progress=False,
277
  )
278
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  # ============ Health ============
280
  with gr.Tab("🩺 Health"):
281
  health_md = gr.Markdown()
@@ -301,12 +437,6 @@ def build_admin_tabs(admin_password: str = None):
301
  refresh_health.click(_recent, outputs=recent_gpu,
302
  queue=False, show_progress=False)
303
 
304
- # ----------------------------------------------------------
305
- # Login wiring — must be OUTSIDE the `with gr.Column` block
306
- # so it can see both `admin_area` and `_dash`.
307
- # We chain .then(_dash) so the dashboard populates immediately
308
- # after successful login (replaces the invalid .change() call).
309
- # ----------------------------------------------------------
310
  def _login(p):
311
  if _gate(p):
312
  return gr.update(visible=True), "✅ Logged in as admin."
@@ -318,9 +448,4 @@ def build_admin_tabs(admin_password: str = None):
318
  outputs=[admin_area, status_md],
319
  queue=False,
320
  show_progress=False,
321
- ).then(
322
- _dash,
323
- outputs=dash_md,
324
- queue=False,
325
- show_progress=False,
326
  )
 
18
 
19
 
20
  def build_admin_tabs(admin_password: str = None):
 
 
 
 
21
  global ADMIN_PASSWORD
22
  if admin_password:
23
  ADMIN_PASSWORD = admin_password
24
 
25
+ # --- Login gate ---
26
  with gr.Row():
27
  pw = gr.Textbox(label="Admin password", type="password", scale=3)
28
  login_btn = gr.Button("Login", scale=1, variant="primary")
29
 
30
  status_md = gr.Markdown("🔒 Locked. Enter password above.")
31
 
 
32
  with gr.Column(visible=False) as admin_area:
33
  with gr.Tabs():
34
 
 
116
  del_btn.click(_del, inputs=[del_uid], outputs=del_out,
117
  queue=False, show_progress=False)
118
 
119
+ # ============ Conversations (live context) ============
120
  with gr.Tab("💬 Conversations"):
121
+ gr.Markdown(
122
+ "_Live context only — cleared by user `/reset`._ "
123
+ "See **📁 Sessions** tab for the permanent archive."
124
+ )
125
  with gr.Row():
126
  conv_uid = gr.Number(label="Filter user_id (blank = all)",
127
  precision=0, scale=2)
 
150
  outputs=conv_table,
151
  queue=False, show_progress=False)
152
 
153
+ gr.Markdown("### Export (live + full archive)")
154
  with gr.Row():
155
  exp_json_btn = gr.Button("📦 JSON")
156
  exp_csv_btn = gr.Button("📊 CSV")
 
183
  exp_md_btn.click(_write_md, outputs=exp_file,
184
  queue=False, show_progress=False)
185
 
186
+ # ============ Sessions (per-session markdown archive) ============
187
+ with gr.Tab("📁 Sessions"):
188
+ gr.Markdown(
189
+ "**Permanent archive.** One markdown file per session, "
190
+ "stored at `/data/chat_logs/{user_id}/{timestamp}.md`. "
191
+ "User `/reset` closes a session and starts a new file — "
192
+ "**nothing is ever deleted** except by admin action here."
193
+ )
194
+
195
+ with gr.Row():
196
+ sess_uid = gr.Number(label="Filter by user_id (blank = all)",
197
+ precision=0, scale=2)
198
+ sess_refresh = gr.Button("🔄 Refresh sessions",
199
+ variant="primary", scale=1)
200
+
201
+ sess_table = gr.Dataframe(
202
+ headers=["user_id", "filename", "size_bytes", "modified", "path"],
203
+ interactive=False,
204
+ wrap=True,
205
+ )
206
+
207
+ def _sess_rows(uid):
208
+ uid_int = int(uid) if uid else None
209
+ rows = dbm.archive_list(uid_int)
210
+ return [[r["user_id"], r["filename"], r["size"],
211
+ r["modified"], r["path"]] for r in rows]
212
+
213
+ sess_refresh.click(_sess_rows, inputs=[sess_uid],
214
+ outputs=sess_table,
215
+ queue=False, show_progress=False)
216
+
217
+ gr.Markdown("### View a session")
218
+ with gr.Row():
219
+ view_uid = gr.Number(label="User ID", precision=0, scale=1)
220
+ view_file = gr.Textbox(label="Filename (e.g. 20261016T123045.md)",
221
+ scale=3)
222
+ view_btn = gr.Button("📖 Load", variant="primary", scale=1)
223
+
224
+ view_code = gr.Code(label="Session transcript",
225
+ language="markdown",
226
+ lines=25,
227
+ interactive=False)
228
+
229
+ def _view(uid, fn):
230
+ if not uid or not fn:
231
+ return ""
232
+ return dbm.archive_read(int(uid), fn.strip())
233
+
234
+ view_btn.click(_view, inputs=[view_uid, view_file],
235
+ outputs=view_code,
236
+ queue=False, show_progress=False)
237
+
238
+ gr.Markdown("### Download full transcript for a user")
239
+ with gr.Row():
240
+ dl_uid = gr.Number(label="User ID", precision=0, scale=2)
241
+ dl_btn = gr.Button("📦 Build combined .md", scale=1)
242
+ dl_file = gr.File(label="Combined transcript", interactive=False)
243
+
244
+ def _build_combined(uid):
245
+ if not uid:
246
+ return None
247
+ p = f"/tmp/transcript_{int(uid)}.md"
248
+ with open(p, "w", encoding="utf-8") as f:
249
+ f.write(dbm.archive_export_user(int(uid)))
250
+ return p
251
+
252
+ dl_btn.click(_build_combined, inputs=[dl_uid],
253
+ outputs=dl_file,
254
+ queue=False, show_progress=False)
255
+
256
+ gr.Markdown("### Manage sessions")
257
+ with gr.Row():
258
+ del_uid = gr.Number(label="Delete one file — user_id",
259
+ precision=0, scale=1)
260
+ del_file = gr.Textbox(label="Filename", scale=3)
261
+ del_btn = gr.Button("🗑️ Delete file", variant="stop", scale=1)
262
+ del_out = gr.Markdown()
263
+
264
+ def _del_file(uid, fn):
265
+ if not uid or not fn:
266
+ return "Enter user_id and filename."
267
+ ok = dbm.archive_delete(int(uid), fn.strip())
268
+ return ("✅ Deleted." if ok else "⚠️ File not found.")
269
+
270
+ del_btn.click(_del_file, inputs=[del_uid, del_file],
271
+ outputs=del_out,
272
+ queue=False, show_progress=False)
273
+
274
+ with gr.Row():
275
+ del_user_uid = gr.Number(label="Delete ALL files for user_id",
276
+ precision=0, scale=2)
277
+ del_user_btn = gr.Button("🗑️ Delete user's sessions",
278
+ variant="stop", scale=1)
279
+ del_user_out = gr.Markdown()
280
+
281
+ def _del_user(uid):
282
+ if not uid:
283
+ return "Enter a user_id."
284
+ n = dbm.archive_delete_user(int(uid))
285
+ return f"🗑️ Deleted {n} session file(s) for {int(uid)}."
286
+
287
+ del_user_btn.click(_del_user, inputs=[del_user_uid],
288
+ outputs=del_user_out,
289
+ queue=False, show_progress=False)
290
+
291
+ gr.Markdown("---")
292
+ gr.Markdown("### ⚠️ Danger zone")
293
+ clear_all_btn = gr.Button("🗑️ Delete ALL sessions for ALL users",
294
+ variant="stop")
295
+ clear_all_out = gr.Markdown()
296
+
297
+ def _clear_all():
298
+ n = dbm.archive_delete_all()
299
+ return f"🗑️ Deleted {n} session file(s) total."
300
+
301
+ clear_all_btn.click(_clear_all, outputs=clear_all_out,
302
+ queue=False, show_progress=False)
303
+
304
  # ============ Tokens ============
305
  with gr.Tab("🎟️ Tokens"):
306
  tok_table = gr.Dataframe(
 
353
  queue=False, show_progress=False)
354
 
355
  # ============ Settings ============
356
+ with gr.Tab("⚙️ Settings") as settings_tab:
357
+ gr.Markdown("Changes apply immediately. Use **🔄 Reload from DB** if values look stale.")
358
 
359
  window = gr.Number(label="conversation_window (turns)",
360
+ value=6, precision=0)
 
361
  max_new = gr.Number(label="max_new_tokens",
362
+ value=1024, precision=0)
363
+ temp = gr.Number(label="temperature", value=0.7)
364
+ topp = gr.Number(label="top_p", value=0.9)
365
+ sys_prompt = gr.Textbox(label="system_prompt", value="", lines=10)
 
 
 
 
 
 
366
  daily_limit = gr.Number(label="daily_turn_limit",
367
+ value=100, precision=0)
368
+
369
+ with gr.Row():
370
+ save_settings = gr.Button("💾 Save settings", variant="primary")
371
+ reload_settings = gr.Button("🔄 Reload from DB")
372
 
 
373
  settings_out = gr.Markdown()
374
 
375
+ def _load_settings():
376
+ return (
377
+ int(dbm.get_setting("conversation_window", "6")),
378
+ int(dbm.get_setting("max_new_tokens", "1024")),
379
+ float(dbm.get_setting("temperature", "0.7")),
380
+ float(dbm.get_setting("top_p", "0.9")),
381
+ dbm.get_setting("system_prompt", "You are a helpful assistant."),
382
+ int(dbm.get_setting("daily_turn_limit", "100")),
383
+ )
384
+
385
  def _save(w, mn, t, tp, sp, dl):
386
  dbm.set_setting("conversation_window", int(w))
387
  dbm.set_setting("max_new_tokens", int(mn))
 
389
  dbm.set_setting("top_p", float(tp))
390
  dbm.set_setting("system_prompt", sp)
391
  dbm.set_setting("daily_turn_limit", int(dl))
392
+ import datetime as _d
393
+ return (f"✅ Saved at {_d.datetime.now().strftime('%H:%M:%S')}. "
394
+ f"Prompt length: {len(sp)} chars.")
395
 
396
  save_settings.click(
397
  _save,
 
400
  queue=False, show_progress=False,
401
  )
402
 
403
+ reload_settings.click(
404
+ _load_settings,
405
+ outputs=[window, max_new, temp, topp, sys_prompt, daily_limit],
406
+ queue=False, show_progress=False,
407
+ )
408
+
409
+ settings_tab.select(
410
+ _load_settings,
411
+ outputs=[window, max_new, temp, topp, sys_prompt, daily_limit],
412
+ queue=False, show_progress=False,
413
+ )
414
+
415
  # ============ Health ============
416
  with gr.Tab("🩺 Health"):
417
  health_md = gr.Markdown()
 
437
  refresh_health.click(_recent, outputs=recent_gpu,
438
  queue=False, show_progress=False)
439
 
 
 
 
 
 
 
440
  def _login(p):
441
  if _gate(p):
442
  return gr.update(visible=True), "✅ Logged in as admin."
 
448
  outputs=[admin_area, status_md],
449
  queue=False,
450
  show_progress=False,
 
 
 
 
 
451
  )