broadfield-dev commited on
Commit
e7079a7
Β·
verified Β·
1 Parent(s): f4ee209

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -57
app.py CHANGED
@@ -269,10 +269,7 @@ def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_na
269
  global current_chat_session_history
270
  cleared_input, updated_gr_hist, status_txt = "", list(gr_hist_list), "Initializing..."
271
  def_detect_out_md, def_fmt_out_txt = gr.Markdown("*Processing...*"), gr.Textbox("*Waiting...*")
272
- # For DownloadButton, create a placeholder value that's a valid file path (even if empty initially)
273
- # Or simply update it to gr.DownloadButton(interactive=False, value=None, visible=False)
274
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
275
-
276
  if not user_msg_txt.strip():
277
  status_txt = "Error: Empty message."
278
  updated_gr_hist.append((user_msg_txt or "(Empty)", status_txt))
@@ -302,12 +299,10 @@ def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_na
302
  if updated_gr_hist and updated_gr_hist[-1][0] == user_msg_txt: updated_gr_hist[-1] = (user_msg_txt, curr_bot_disp_msg or "(No text)")
303
  def_fmt_out_txt = gr.Textbox(value=curr_bot_disp_msg)
304
  if curr_bot_disp_msg and not curr_bot_disp_msg.startswith("Error:"):
305
- # Create a temporary file for the download
306
  with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md", encoding='utf-8') as tmpfile:
307
  tmpfile.write(curr_bot_disp_msg)
308
- temp_dl_file_path = tmpfile.name # This path will be passed to DownloadButton
309
- # Update DownloadButton with the path to the temp file
310
- def_dl_btn = gr.DownloadButton(label="Download Report (.md)", value=temp_dl_file_path, visible=True, interactive=True)
311
  else: def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
312
  insights_md = "### Insights Considered:\n" + ("\n".join([f"- **[{i.get('type','N/A')}|{i.get('score','N/A')}]** {i.get('text','N/A')[:100]}..." for i in insights_used_parsed[:3]]) if insights_used_parsed else "*None specific.*")
313
  def_detect_out_md = gr.Markdown(insights_md)
@@ -328,14 +323,9 @@ def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_na
328
  status_txt = "Response complete. Background learning initiated."
329
  else: status_txt = "Processing finished; no response or error."
330
  yield (cleared_input, updated_gr_hist, status_txt, def_detect_out_md, def_fmt_out_txt, def_dl_btn)
331
- # Clean up the temporary file after the download button has been yielded (and potentially used)
332
- # This cleanup is tricky with Gradio's yield. The file needs to exist when Gradio processes the yield.
333
- # A more robust way is to have Gradio manage the temp file or use a cleanup mechanism that runs after the HTTP response.
334
- # For simplicity, we'll leave it, but in a prod app, temp files should be managed.
335
- # if temp_dl_file_path and os.path.exists(temp_dl_file_path):
336
- # try: os.unlink(temp_dl_file_path)
337
- # except Exception as e_unlink: logger.error(f"Error deleting temp download file {temp_dl_file_path}: {e_unlink}")
338
-
339
 
340
  def ui_view_rules_action_fn(): return "\n\n---\n\n".join(get_all_rules_cached()) or "No rules found."
341
  def ui_upload_rules_action_fn(uploaded_file_obj, progress=gr.Progress()):
@@ -392,71 +382,92 @@ def ui_upload_memories_action_fn(uploaded_file_obj, progress=gr.Progress()):
392
  msg = f"Memories Upload: Processed {total_to_process}. Added: {added_count}, Format Errors: {format_error_count}, Save Errors: {save_error_count}."
393
  logger.info(msg); return msg
394
 
395
- custom_theme = gr.themes.Base(primary_hue="teal", secondary_hue="purple", neutral_hue="zinc", text_size="sm", spacing_size="sm", radius_size="sm", font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"])
396
- custom_css = """ body { font-family: 'Inter', sans-serif; } .gradio-container { max-width: 98% !important; margin: auto !important; padding-top: 0.5rem !important; } footer { display: none !important; } .gr-button { white-space: nowrap; } .gr-input, .gr-textarea textarea, .gr-dropdown input { border-radius: 8px !important; } .gr-chatbot .message { border-radius: 10px !important; box-shadow: 0 2px 5px rgba(0,0,0,0.08) !important; } .prose { h1 { font-size: 1.8rem; margin-bottom: 0.6em; margin-top: 0.8em; } h2 { font-size: 1.4rem; margin-bottom: 0.5em; margin-top: 0.7em; } h3 { font-size: 1.15rem; margin-bottom: 0.4em; margin-top: 0.6em; } p { margin-bottom: 0.8em; line-height: 1.65; } ul, ol { margin-left: 1.5em; margin-bottom: 0.8em; } code { background-color: #f1f5f9; padding: 0.2em 0.45em; border-radius: 4px; font-size: 0.9em; } pre > code { display: block; padding: 0.8em; overflow-x: auto; background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px;}} .compact-group .gr-input-label, .compact-group .gr-dropdown-label { font-size: 0.8rem !important; padding-bottom: 2px !important;} .status-bar { padding: 0.5em; margin-bottom: 0.5em; border-radius: 6px; background-color: #eef2ff;} """ # Added status-bar style
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
- with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Mega Agent v5") as demo:
399
- gr.Markdown("# πŸš€ AI Research Mega Agent", elem_classes="prose")
400
 
401
  avail_provs = get_available_providers()
402
  def_prov = avail_provs[0] if avail_provs else None
403
  def_models = get_model_display_names_for_provider(def_prov) if def_prov else []
404
  def_model_disp = get_default_model_display_name_for_provider(def_prov) if def_prov else None
 
405
 
406
- with gr.Row(elem_classes="status-bar"):
407
- agent_stat_tb = gr.Textbox(label="Agent Status", interactive=False, lines=1, value="Initializing systems...", scale=3)
408
- memory_backend_info_tb = gr.Textbox(label="Memory Backend", value=f"{MEMORY_STORAGE_BACKEND}", interactive=False, scale=1)
409
  if MEMORY_STORAGE_BACKEND == "SQLITE":
410
- gr.Textbox(label="SQLite Path", value=f"{MEMORY_SQLITE_PATH}", interactive=False, scale=2)
411
  elif MEMORY_STORAGE_BACKEND == "HF_DATASET":
412
- gr.Textbox(label="HF Repos", value=f"M: {MEMORY_HF_MEM_REPO}, R: {MEMORY_HF_RULES_REPO}", interactive=False, scale=2)
413
-
414
-
415
  with gr.Tabs() as main_tabs:
416
- with gr.TabItem("πŸ’¬ Dashboard & Chat", id=0):
417
  with gr.Row():
418
- with gr.Column(scale=1, min_width=320):
419
- gr.Markdown("### βš™οΈ LLM Configuration", elem_classes="prose")
420
- with gr.Group(elem_classes="compact-group"):
421
- prov_sel_dd = gr.Dropdown(label="Provider", choices=avail_provs, value=def_prov, interactive=True)
422
- model_sel_dd = gr.Dropdown(label="Model", choices=def_models, value=def_model_disp, interactive=True)
423
- api_key_tb = gr.Textbox(label="API Key Override (Optional)", type="password", placeholder="Enter API key if not in .env")
424
- with gr.Group(elem_classes="compact-group"):
425
  sys_prompt_tb = gr.Textbox(label="System Prompt Base", lines=10, value=DEFAULT_SYSTEM_PROMPT, interactive=True)
426
 
427
  with gr.Column(scale=2):
428
- main_chat_disp = gr.Chatbot(label="AI Research Chat", height=600, bubble_full_width=False, avatar_images=(None, "https://raw.githubusercontent.com/huggingface/brand-assets/main/hf-logo-with-title.png"), show_copy_button=True, render_markdown=True, sanitize_html=True)
 
429
  with gr.Row():
430
- user_msg_tb = gr.Textbox(show_label=False, placeholder="Ask a question or give an instruction...", scale=7, lines=1, max_lines=5, autofocus=True)
431
  send_btn = gr.Button("Send", variant="primary", scale=1, min_width=100)
432
 
433
- with gr.Accordion("πŸ“ Full Response / Output", open=True):
434
- fmt_report_tb = gr.Textbox(label="Current Research Output", lines=10, interactive=True, show_copy_button=True, value="*AI responses will appear here...*")
435
  dl_report_btn = gr.DownloadButton("Download Report", interactive=False, visible=False)
436
- detect_out_md = gr.Markdown("*Insights used or other intermediate details will show here...*")
437
 
438
  with gr.TabItem("🧠 Knowledge Base Management", id=1):
439
- gr.Markdown("## Manage Stored Knowledge (Backend: " + MEMORY_STORAGE_BACKEND + ")", elem_classes="prose")
440
  with gr.Row(equal_height=False):
441
  with gr.Column(scale=1):
442
- gr.Markdown("### Rules (Learned Insights)", elem_classes="prose")
443
  rules_disp_ta = gr.TextArea(label="View/Edit Rules (one per line or '---' separated)", lines=15, interactive=True, placeholder="Load or type rules here...")
444
  with gr.Row():
445
- view_rules_btn = gr.Button("πŸ”„ Load/Refresh Rules View")
446
- save_edited_rules_btn = gr.Button("πŸ’Ύ Save Edited Rules", variant="primary")
447
  upload_rules_fobj = gr.File(label="Upload Rules File (.txt/.jsonl)", file_types=[".txt", ".jsonl"])
448
- rules_stat_tb = gr.Textbox(label="Rules Action Status", interactive=False, lines=2, placeholder="Status of rule operations...")
449
  with gr.Row():
450
  clear_rules_btn = gr.Button("⚠️ Clear All Rules", variant="stop")
451
- save_faiss_ram_btn = gr.Button("Save FAISS Indices", visible=(MEMORY_STORAGE_BACKEND == "RAM"))
 
452
 
453
  with gr.Column(scale=1):
454
- gr.Markdown("### Memories (Past Interactions)", elem_classes="prose")
455
- mems_disp_json = gr.JSON(label="View Memories (JSON format)", scale=2) # scale makes it taller
456
- with gr.Row():
457
- view_mems_btn = gr.Button("πŸ”„ Load/Refresh Memories View")
458
  upload_mems_fobj = gr.File(label="Upload Memories File (.jsonl)", file_types=[".jsonl"])
459
- mems_stat_tb = gr.Textbox(label="Memories Action Status", interactive=False, lines=2, placeholder="Status of memory operations...")
460
  clear_mems_btn = gr.Button("⚠️ Clear All Memories", variant="stop")
461
 
462
  def dyn_upd_model_dd(sel_prov_dyn:str): models_dyn, def_model_dyn = get_model_display_names_for_provider(sel_prov_dyn), get_default_model_display_name_for_provider(sel_prov_dyn); return gr.Dropdown(choices=models_dyn, value=def_model_dyn, interactive=True)
@@ -486,9 +497,9 @@ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Mega Agent
486
  upload_rules_fobj.upload(fn=ui_upload_rules_action_fn, inputs=[upload_rules_fobj], outputs=[rules_stat_tb], show_progress="full").then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
487
  clear_rules_btn.click(fn=lambda: "All rules cleared." if clear_all_rules_data_backend() else "Error clearing rules.", outputs=rules_stat_tb).then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
488
 
489
- if MEMORY_STORAGE_BACKEND == "RAM" and save_faiss_ram_btn is not None:
490
- def save_faiss_action_with_feedback_fn(): save_faiss_indices_to_disk(); gr.Info("Attempted to save FAISS indices to disk.")
491
- save_faiss_ram_btn.click(fn=save_faiss_action_with_feedback_fn, inputs=None, outputs=None)
492
 
493
  view_mems_btn.click(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
494
  upload_mems_fobj.upload(fn=ui_upload_memories_action_fn, inputs=[upload_mems_fobj], outputs=[mems_stat_tb], show_progress="full").then(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
@@ -497,18 +508,27 @@ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Mega Agent
497
  def app_load_fn():
498
  initialize_memory_system()
499
  logger.info("App loaded. Memory system initialized.")
500
- backend_status = f"AI Systems Initialized (Backend: {MEMORY_STORAGE_BACKEND}). Ready."
501
- # Initial load for KB views
502
  rules_on_load = ui_view_rules_action_fn()
503
  mems_on_load = ui_view_memories_action_fn()
 
 
 
 
 
 
 
 
 
 
 
504
  return backend_status, rules_on_load, mems_on_load
505
 
506
  # Update outputs of demo.load to populate the KB views on startup
507
  demo.load(fn=app_load_fn, inputs=None, outputs=[agent_stat_tb, rules_disp_ta, mems_disp_json])
508
 
509
-
510
  if __name__ == "__main__":
511
- logger.info(f"Starting Gradio AI Research Mega Agent (v5 with Dashboard UI & Advanced Memory: {MEMORY_STORAGE_BACKEND})...")
512
  app_port, app_server = int(os.getenv("GRADIO_PORT", 7860)), os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
513
  app_debug, app_share = os.getenv("GRADIO_DEBUG", "False").lower()=="true", os.getenv("GRADIO_SHARE", "False").lower()=="true"
514
  logger.info(f"Launching Gradio server: http://{app_server}:{app_port}. Debug: {app_debug}, Share: {app_share}")
 
269
  global current_chat_session_history
270
  cleared_input, updated_gr_hist, status_txt = "", list(gr_hist_list), "Initializing..."
271
  def_detect_out_md, def_fmt_out_txt = gr.Markdown("*Processing...*"), gr.Textbox("*Waiting...*")
 
 
272
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
 
273
  if not user_msg_txt.strip():
274
  status_txt = "Error: Empty message."
275
  updated_gr_hist.append((user_msg_txt or "(Empty)", status_txt))
 
299
  if updated_gr_hist and updated_gr_hist[-1][0] == user_msg_txt: updated_gr_hist[-1] = (user_msg_txt, curr_bot_disp_msg or "(No text)")
300
  def_fmt_out_txt = gr.Textbox(value=curr_bot_disp_msg)
301
  if curr_bot_disp_msg and not curr_bot_disp_msg.startswith("Error:"):
 
302
  with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md", encoding='utf-8') as tmpfile:
303
  tmpfile.write(curr_bot_disp_msg)
304
+ temp_dl_file_path = tmpfile.name
305
+ def_dl_btn = gr.DownloadButton(value=temp_dl_file_path, visible=True, interactive=True) # `label` is optional here, Gradio uses filename
 
306
  else: def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
307
  insights_md = "### Insights Considered:\n" + ("\n".join([f"- **[{i.get('type','N/A')}|{i.get('score','N/A')}]** {i.get('text','N/A')[:100]}..." for i in insights_used_parsed[:3]]) if insights_used_parsed else "*None specific.*")
308
  def_detect_out_md = gr.Markdown(insights_md)
 
323
  status_txt = "Response complete. Background learning initiated."
324
  else: status_txt = "Processing finished; no response or error."
325
  yield (cleared_input, updated_gr_hist, status_txt, def_detect_out_md, def_fmt_out_txt, def_dl_btn)
326
+ if temp_dl_file_path and os.path.exists(temp_dl_file_path):
327
+ try: os.unlink(temp_dl_file_path)
328
+ except Exception as e_unlink: logger.error(f"Error deleting temp download file {temp_dl_file_path}: {e_unlink}")
 
 
 
 
 
329
 
330
  def ui_view_rules_action_fn(): return "\n\n---\n\n".join(get_all_rules_cached()) or "No rules found."
331
  def ui_upload_rules_action_fn(uploaded_file_obj, progress=gr.Progress()):
 
382
  msg = f"Memories Upload: Processed {total_to_process}. Added: {added_count}, Format Errors: {format_error_count}, Save Errors: {save_error_count}."
383
  logger.info(msg); return msg
384
 
385
+ custom_theme = gr.themes.Base(primary_hue="teal", secondary_hue="purple", neutral_hue="zinc", text_size="sm", spacing_size="md", radius_size="sm", font=["System UI", "sans-serif"])
386
+ custom_css = """
387
+ body { background: linear-gradient(to bottom right, #2c3e50, #34495e); color: #ecf0f1; min-height: 100vh; }
388
+ .gradio-container { background: transparent !important; max-width: 100% !important; padding: 10px !important;}
389
+ .gr-box, .gr-panel, .gr-tabs { background-color: rgba(44, 62, 80, 0.85) !important; border-color: rgba(189, 195, 199, 0.2) !important; border-radius: 8px !important;}
390
+ .gr-tabitem { background-color: rgba(52, 73, 94, 0.7) !important; border-radius: 6px !important; margin-bottom: 5px !important;}
391
+ .gr-accordion { background-color: rgba(52, 73, 94, 0.75) !important; border-radius: 6px !important; }
392
+ .gr-textbox, .gr-dropdown, .gr-button, .gr-code, .gr-chat-message, .gr-json { border-color: rgba(189, 195, 199, 0.3) !important; background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; border-radius: 6px !important;}
393
+ .gr-textarea textarea { color: #ecf0f1 !important; } /* Ensure textarea text is light */
394
+ .gr-button.gr-button-primary { background-color: #1abc9c !important; color: white !important; border-color: #16a085 !important; }
395
+ .gr-button.gr-button-secondary { background-color: #9b59b6 !important; color: white !important; border-color: #8e44ad !important; }
396
+ .gr-button.gr-button-stop { background-color: #e74c3c !important; color: white !important; border-color: #c0392b !important; }
397
+ .gr-markdown { background-color: transparent !important; padding: 0px; border-radius: 0px; } /* Make markdown background transparent within styled boxes */
398
+ .gr-markdown h1, .gr-markdown h2, .gr-markdown h3 { color: #1abc9c !important; border-bottom: 1px solid rgba(189, 195, 199, 0.2) !important; padding-bottom: 0.3em; margin-top:1em; }
399
+ .gr-markdown p, .gr-markdown li { color: #ecf0f1 !important; }
400
+ .gr-markdown pre code { background-color: rgba(30, 40, 50, 0.95) !important; border-color: rgba(189, 195, 199, 0.3) !important; color: #ecf0f1; border-radius: 4px; padding: 0.8em; }
401
+ .gr-chatbot { background-color: rgba(44, 62, 80, 0.7) !important; border-color: rgba(189, 195, 199, 0.2) !important; }
402
+ .gr-chatbot .message { background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; border: 1px solid rgba(189, 195, 199, 0.2) !important; box-shadow: 0 1px 2px rgba(0,0,0,0.1) !important; }
403
+ .gr-chatbot .message.user { background-color: rgba(46, 204, 113, 0.8) !important; color: #2c3e50 !important; }
404
+ .gr-input-label > .label-text, .gr-dropdown-label > .label-text { color: #bdc3c7 !important; font-size: 0.9rem !important; } /* Lighter labels */
405
+ .gr-info { color: #bdc3c7 !important; font-size: 0.85rem !important; }
406
+ #status_bar_info { background-color: rgba(44, 62, 80, 0.8) !important; padding: 8px; border-radius: 6px; margin-bottom: 10px; }
407
+ """
408
 
409
+ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Mega Agent v5.1") as demo:
410
+ gr.Markdown("# πŸš€ AI Research Mega Agent Dashboard")
411
 
412
  avail_provs = get_available_providers()
413
  def_prov = avail_provs[0] if avail_provs else None
414
  def_models = get_model_display_names_for_provider(def_prov) if def_prov else []
415
  def_model_disp = get_default_model_display_name_for_provider(def_prov) if def_prov else None
416
+ save_faiss_ram_btn_kb = None # For KB tab
417
 
418
+ with gr.Row(elem_id="status_bar_info"):
419
+ with gr.Column(scale=2): agent_stat_tb = gr.Textbox(label="Agent Status", interactive=False, lines=1, value="Initializing systems...")
420
+ with gr.Column(scale=1): memory_backend_info_tb = gr.Textbox(label="Memory Backend", value=f"{MEMORY_STORAGE_BACKEND}", interactive=False)
421
  if MEMORY_STORAGE_BACKEND == "SQLITE":
422
+ with gr.Column(scale=2): gr.Textbox(label="SQLite Path", value=f"{MEMORY_SQLITE_PATH}", interactive=False)
423
  elif MEMORY_STORAGE_BACKEND == "HF_DATASET":
424
+ with gr.Column(scale=2): gr.Textbox(label="HF Repos", value=f"M: {MEMORY_HF_MEM_REPO}, R: {MEMORY_HF_RULES_REPO}", interactive=False)
425
+
 
426
  with gr.Tabs() as main_tabs:
427
+ with gr.TabItem("βš™οΈ Agent Configuration & Chat", id=0):
428
  with gr.Row():
429
+ with gr.Column(scale=1, min_width=350):
430
+ gr.Markdown("## βš™οΈ LLM & System Configuration")
431
+ with gr.Group():
432
+ prov_sel_dd = gr.Dropdown(label="AI Provider", choices=avail_provs, value=def_prov, interactive=True)
433
+ model_sel_dd = gr.Dropdown(label="AI Model", choices=def_models, value=def_model_disp, interactive=True)
434
+ api_key_tb = gr.Textbox(label="API Key Override (Optional)", type="password", placeholder="Paste key for selected provider")
435
+ with gr.Group():
436
  sys_prompt_tb = gr.Textbox(label="System Prompt Base", lines=10, value=DEFAULT_SYSTEM_PROMPT, interactive=True)
437
 
438
  with gr.Column(scale=2):
439
+ gr.Markdown("## πŸ’¬ AI Chat Interface")
440
+ main_chat_disp = gr.Chatbot(label="AI Research Chat", height=550, bubble_full_width=False, avatar_images=(None, "https://raw.githubusercontent.com/huggingface/brand-assets/main/hf-logo-with-title.png"), show_copy_button=True, render_markdown=True, sanitize_html=True)
441
  with gr.Row():
442
+ user_msg_tb = gr.Textbox(show_label=False, placeholder="Ask your research question or give an instruction...", scale=7, lines=1, max_lines=5, autofocus=True)
443
  send_btn = gr.Button("Send", variant="primary", scale=1, min_width=100)
444
 
445
+ with gr.Accordion("πŸ“ Full Response / Output Details", open=False):
446
+ fmt_report_tb = gr.Textbox(label="Full AI Response", lines=10, interactive=True, show_copy_button=True, value="*AI responses will appear here...*")
447
  dl_report_btn = gr.DownloadButton("Download Report", interactive=False, visible=False)
448
+ detect_out_md = gr.Markdown("*Insights used or other intermediate details will show here...*")
449
 
450
  with gr.TabItem("🧠 Knowledge Base Management", id=1):
451
+ gr.Markdown("## Manage Stored Knowledge")
452
  with gr.Row(equal_height=False):
453
  with gr.Column(scale=1):
454
+ gr.Markdown("### πŸ“œ Rules (Learned Insights)")
455
  rules_disp_ta = gr.TextArea(label="View/Edit Rules (one per line or '---' separated)", lines=15, interactive=True, placeholder="Load or type rules here...")
456
  with gr.Row():
457
+ view_rules_btn = gr.Button("πŸ”„ Load/Refresh Rules"); save_edited_rules_btn = gr.Button("πŸ’Ύ Save Edited Rules", variant="primary")
 
458
  upload_rules_fobj = gr.File(label="Upload Rules File (.txt/.jsonl)", file_types=[".txt", ".jsonl"])
459
+ rules_stat_tb = gr.Textbox(label="Rules Op Status", interactive=False, lines=2, placeholder="Status...")
460
  with gr.Row():
461
  clear_rules_btn = gr.Button("⚠️ Clear All Rules", variant="stop")
462
+ if MEMORY_STORAGE_BACKEND == "RAM":
463
+ save_faiss_ram_btn_kb = gr.Button("Save FAISS Indices")
464
 
465
  with gr.Column(scale=1):
466
+ gr.Markdown("### πŸ“š Memories (Past Interactions)")
467
+ mems_disp_json = gr.JSON(label="View Memories (JSON format)", scale=2)
468
+ with gr.Row(): view_mems_btn = gr.Button("πŸ”„ Load/Refresh Memories")
 
469
  upload_mems_fobj = gr.File(label="Upload Memories File (.jsonl)", file_types=[".jsonl"])
470
+ mems_stat_tb = gr.Textbox(label="Memories Op Status", interactive=False, lines=2, placeholder="Status...")
471
  clear_mems_btn = gr.Button("⚠️ Clear All Memories", variant="stop")
472
 
473
  def dyn_upd_model_dd(sel_prov_dyn:str): models_dyn, def_model_dyn = get_model_display_names_for_provider(sel_prov_dyn), get_default_model_display_name_for_provider(sel_prov_dyn); return gr.Dropdown(choices=models_dyn, value=def_model_dyn, interactive=True)
 
497
  upload_rules_fobj.upload(fn=ui_upload_rules_action_fn, inputs=[upload_rules_fobj], outputs=[rules_stat_tb], show_progress="full").then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
498
  clear_rules_btn.click(fn=lambda: "All rules cleared." if clear_all_rules_data_backend() else "Error clearing rules.", outputs=rules_stat_tb).then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
499
 
500
+ if MEMORY_STORAGE_BACKEND == "RAM" and save_faiss_ram_btn_kb is not None:
501
+ def save_faiss_action_with_feedback_fn_kb(): save_faiss_indices_to_disk(); gr.Info("Attempted to save FAISS indices to disk.")
502
+ save_faiss_ram_btn_kb.click(fn=save_faiss_action_with_feedback_fn_kb, inputs=None, outputs=None)
503
 
504
  view_mems_btn.click(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
505
  upload_mems_fobj.upload(fn=ui_upload_memories_action_fn, inputs=[upload_mems_fobj], outputs=[mems_stat_tb], show_progress="full").then(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
 
508
  def app_load_fn():
509
  initialize_memory_system()
510
  logger.info("App loaded. Memory system initialized.")
511
+ backend_status = f"AI Systems Initialized. Ready." # Agent status, backend info is separate
 
512
  rules_on_load = ui_view_rules_action_fn()
513
  mems_on_load = ui_view_memories_action_fn()
514
+ # Update memory backend info text box too
515
+ mem_backend_text = f"{MEMORY_STORAGE_BACKEND}"
516
+ if MEMORY_STORAGE_BACKEND == "SQLITE": mem_backend_path_text = f"{MEMORY_SQLITE_PATH}"
517
+ elif MEMORY_STORAGE_BACKEND == "HF_DATASET": mem_backend_path_text = f"M: {MEMORY_HF_MEM_REPO}, R: {MEMORY_HF_RULES_REPO}"
518
+ else: mem_backend_path_text = "N/A" # For RAM
519
+
520
+ # The number of outputs from app_load_fn must match the number of components in demo.load's outputs list
521
+ # Make sure memory_backend_info_tb and its potential path display are updated if they are separate components
522
+ # The current UI has one tb for backend and one for path (conditional)
523
+ # For simplicity here, I'll assume they are part of the static display or updated differently if needed.
524
+ # The agent_stat_tb is the primary one to update here.
525
  return backend_status, rules_on_load, mems_on_load
526
 
527
  # Update outputs of demo.load to populate the KB views on startup
528
  demo.load(fn=app_load_fn, inputs=None, outputs=[agent_stat_tb, rules_disp_ta, mems_disp_json])
529
 
 
530
  if __name__ == "__main__":
531
+ logger.info(f"Starting Gradio AI Research Mega Agent (v5.1 with New UI & Advanced Memory: {MEMORY_STORAGE_BACKEND})...")
532
  app_port, app_server = int(os.getenv("GRADIO_PORT", 7860)), os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
533
  app_debug, app_share = os.getenv("GRADIO_DEBUG", "False").lower()=="true", os.getenv("GRADIO_SHARE", "False").lower()=="true"
534
  logger.info(f"Launching Gradio server: http://{app_server}:{app_port}. Debug: {app_debug}, Share: {app_share}")