broadfield-dev commited on
Commit
bfd7251
Β·
verified Β·
1 Parent(s): 26cbf7f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -105
app.py CHANGED
@@ -395,125 +395,118 @@ def ui_upload_memories_action_fn(uploaded_file_obj, progress=gr.Progress()):
395
  logger.info(msg); return msg
396
 
397
  # --- UI Definition ---
 
398
  custom_theme = gr.themes.Base(
399
  primary_hue="teal",
400
  secondary_hue="purple",
401
  neutral_hue="zinc",
402
- text_size="sm",
403
- spacing_size="md",
404
  radius_size="sm",
405
- font=[gr.themes.GoogleFont("Inter"), "System UI", "sans-serif"]
406
  )
407
 
408
- # Adjusted CSS for better layout control and scrolling
409
  custom_css = """
410
- body, html { margin: 0; padding: 0; height: 100%; overflow-x: hidden; /* Prevent horizontal scroll on body */ }
411
- body { background: linear-gradient(to bottom right, #2c3e50, #34495e); color: #ecf0f1; font-family: 'Inter', 'System UI', sans-serif;}
412
- .gradio-container { background: transparent !important; max-width: 100% !important; padding: 0 !important; /* Remove container padding */ box-sizing: border-box; min-height: 100vh; display: flex; flex-direction: column; overflow: hidden !important; /* Gradio container should not scroll itself */ }
413
- .main-app-content-wrapper { padding: 1rem; overflow-y: auto; flex-grow: 1; /* This makes the content area scrollable */ }
414
- .gr-block.gr-group, .gr-tabs, .gr-accordion { background-color: rgba(44, 62, 80, 0.85) !important; border: 1px solid rgba(189, 195, 199, 0.2) !important; border-radius: 8px !important; box-shadow: 0 3px 5px rgba(0,0,0,0.15); margin-bottom: 1em; padding: 1em; }
415
- .gr-tabitem { background-color: rgba(52, 73, 94, 0.8) !important; border-radius: 6px !important; padding: 1em !important; border: 1px solid rgba(189, 195, 199, 0.1) !important;}
416
- .gr-textbox, .gr-dropdown, .gr-button, .gr-code, .gr-chat-message, .gr-json, .gr-file input[type="file"], .gr-file button { border: 1px solid rgba(189, 195, 199, 0.3) !important; background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; border-radius: 6px !important;}
417
- .gr-file { background-color: transparent !important; border: none !important; padding:0 !important;}
418
- .gr-file > .label-text { color: #bdc3c7 !important;}
419
- .gr-textarea textarea, .gr-textbox input { color: #ecf0f1 !important; background-color: transparent !important; }
420
  .gr-button.gr-button-primary { background-color: #1abc9c !important; color: white !important; border-color: #16a085 !important; }
421
- .gr-button.gr-button-secondary { background-color: #9b59b6 !important; color: white !important; border-color: #8e44ad !important; }
422
- .gr-button.gr-button-stop { background-color: #e74c3c !important; color: white !important; border-color: #c0392b !important; }
423
- .gr-markdown { padding: 5px; }
424
- .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:0.5em; margin-bottom: 0.5em; }
425
- .gr-markdown p, .gr-markdown li { color: #ecf0f1 !important; line-height:1.6;}
426
- .gr-markdown pre code { background-color: rgba(30, 40, 50, 0.95) !important; border: 1px solid rgba(189, 195, 199, 0.3) !important; color: #ecf0f1; border-radius: 4px; padding: 0.8em; }
427
- .gr-chatbot { background-color: rgba(44, 62, 80, 0.7) !important; border: 1px solid rgba(189, 195, 199, 0.2) !important; }
428
- .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; }
429
- .gr-chatbot .message.user { background-color: rgba(46, 204, 113, 0.8) !important; color: #2c3e50 !important; }
430
- .gr-input-label > .label-text, .gr-dropdown-label > .label-text, .gr-checkbox-label > .label-text { color: #bdc3c7 !important; font-size: 0.9rem !important; margin-bottom: 0.2rem !important; }
431
- .gr-info { color: #bdc3c7 !important; font-size: 0.85rem !important; }
432
- .status-bar { background-color: rgba(44, 62, 80, 0.8) !important; padding: 0.75rem 1rem !important; border-radius: 8px; margin-bottom: 1rem; }
433
- .tabnav button { background-color: rgba(52, 73, 94, 0.8) !important; color: #ecf0f1 !important; border-bottom: 3px solid transparent !important; border-top-left-radius: 6px !important; border-top-right-radius: 6px !important; margin-right: 3px !important; padding: 0.6em 1.2em !important; font-weight: 500;}
434
- .tabnav button.selected { background-color: rgba(44, 62, 80, 0.95) !important; color: #1abc9c !important; border-bottom: 3px solid #1abc9c !important;}
435
- .main-title { text-align: center; margin: 0 0 0.25rem 0 !important; padding-top: 0.5rem !important; color: #ecf0f1 !important; font-size: 2rem !important;} /* Added padding-top */
436
- .main-subtitle { text-align: center; color: #bdc3c7; font-size: 1rem; margin: 0 0 1rem 0 !important; }
437
- .sidebar-column { max-height: calc(100vh - 10rem); overflow-y: auto; /* Make sidebar scrollable if content exceeds height */ }
438
- .main-content-column { max-height: calc(100vh - 10rem); overflow-y: auto; /* Make main content scrollable */ }
 
 
 
439
  """
440
 
441
- with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Agent v5.6") as demo:
442
- gr.HTML("<style>" + custom_css + "</style>")
443
-
444
- with gr.Column(elem_classes="main-app-content-wrapper"): # This outer column will handle overall page scroll
445
- gr.Markdown("# πŸ€– AI Research Agent", elem_classes="main-title")
446
- gr.Markdown("Configure AI, chat for research, and manage its knowledge base.", elem_classes="main-subtitle")
447
-
448
- avail_provs = get_available_providers()
449
- def_prov = avail_provs[0] if avail_provs else None
450
- def_models = get_model_display_names_for_provider(def_prov) if def_prov else []
451
- def_model_disp = get_default_model_display_name_for_provider(def_prov) if def_prov else None
452
-
453
- with gr.Row(elem_classes="status-bar"):
454
- with gr.Column(scale=3): agent_stat_tb = gr.Textbox(label="Agent Status", interactive=False, lines=1, value="Initializing systems...")
455
- with gr.Column(scale=1): memory_backend_info_tb = gr.Textbox(label="Memory Backend", value=f"{MEMORY_STORAGE_BACKEND}", interactive=False)
456
- if MEMORY_STORAGE_BACKEND == "SQLITE":
457
- with gr.Column(scale=2): gr.Textbox(label="SQLite Path", value=f"{MEMORY_SQLITE_PATH}", interactive=False)
458
- elif MEMORY_STORAGE_BACKEND == "HF_DATASET":
459
- with gr.Column(scale=2): gr.Textbox(label="HF Repos", value=f"M: {MEMORY_HF_MEM_REPO}, R: {MEMORY_HF_RULES_REPO}", interactive=False)
460
 
461
- with gr.Row(equal_height=False):
462
- with gr.Column(scale=1, min_width=360, elem_classes="sidebar-column"):
463
- gr.Markdown("## βš™οΈ Configuration")
464
- with gr.Group():
465
- gr.Markdown("### AI Model Settings")
466
- api_key_tb = gr.Textbox(label="AI Provider API Key (Optional Override)", type="password", placeholder="Paste key or use .env")
467
- prov_sel_dd = gr.Dropdown(label="AI Provider", choices=avail_provs, value=def_prov, interactive=True)
468
- model_sel_dd = gr.Dropdown(label="AI Model", choices=def_models, value=def_model_disp, interactive=True)
469
- with gr.Group():
470
- gr.Markdown("### System Prompt")
471
- sys_prompt_tb = gr.Textbox(label="System Prompt Base", lines=12, value=DEFAULT_SYSTEM_PROMPT, interactive=True)
472
- gr.Markdown(f"**Memory Backend:** {MEMORY_STORAGE_BACKEND}")
473
- if MEMORY_STORAGE_BACKEND == "RAM":
474
- save_faiss_sidebar_btn = gr.Button("Save FAISS Indices", variant="secondary")
475
 
476
- with gr.Column(scale=2, elem_classes="main-content-column"):
477
- with gr.Tabs():
478
- with gr.TabItem("πŸ’¬ AI Chat & Research Output"):
479
- gr.Markdown("## πŸ’¬ AI Chat Interface")
480
- main_chat_disp = gr.Chatbot(label="AI Research Chat", height=500, 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)
 
481
  with gr.Row():
482
- 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)
483
  send_btn = gr.Button("Send", variant="primary", scale=1, min_width=100)
484
- with gr.Accordion("πŸ“ Full Response / Output Details", open=True):
485
- fmt_report_tb = gr.Textbox(label="Full AI Response", lines=10, interactive=True, show_copy_button=True, value="*AI responses will appear here...*")
486
- dl_report_btn = gr.DownloadButton("Download Report", interactive=False, visible=False)
487
- detect_out_md = gr.Markdown("*Insights used or other intermediate details will show here...*")
488
 
489
- with gr.TabItem("🧠 Knowledge Base Management"):
490
- gr.Markdown("## Manage Stored Knowledge")
491
- with gr.Row(equal_height=False):
492
- with gr.Column(scale=1):
493
- with gr.Group():
494
- gr.Markdown("### πŸ“œ Rules (Learned Insights)")
495
- rules_disp_ta = gr.TextArea(label="View/Edit Rules", lines=15, interactive=True, placeholder="Load or type rules here (one per line or '---' separated for multiple).")
496
- with gr.Row():
497
- view_rules_btn = gr.Button("πŸ”„ Load/Refresh Rules"); save_edited_rules_btn = gr.Button("πŸ’Ύ Save Edited Rules", variant="primary")
498
- upload_rules_fobj = gr.File(label="Upload Rules File (.txt/.jsonl)", file_types=[".txt", ".jsonl"])
499
- rules_stat_tb = gr.Textbox(label="Rules Operation Status", interactive=False, lines=2, placeholder="Status...")
500
- with gr.Row(): clear_rules_btn = gr.Button("⚠️ Clear All Rules", variant="stop")
501
-
502
- with gr.Column(scale=1): # This was nested incorrectly before
503
- with gr.Group():
504
- gr.Markdown("### πŸ“š Memories (Past Interactions)")
505
- mems_disp_json = gr.JSON(label="View Memories (JSON format)")
506
- with gr.Row(): view_mems_btn = gr.Button("πŸ”„ Load/Refresh Memories")
507
- upload_mems_fobj = gr.File(label="Upload Memories File (.jsonl)", file_types=[".jsonl"])
508
- mems_stat_tb = gr.Textbox(label="Memories Operation Status", interactive=False, lines=2, placeholder="Status...")
509
- clear_mems_btn = gr.Button("⚠️ Clear All Memories", variant="stop")
510
 
511
  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)
512
  prov_sel_dd.change(fn=dyn_upd_model_dd, inputs=prov_sel_dd, outputs=model_sel_dd)
513
  chat_ins = [user_msg_tb, main_chat_disp, prov_sel_dd, model_sel_dd, api_key_tb, sys_prompt_tb]
514
  chat_outs = [user_msg_tb, main_chat_disp, agent_stat_tb, detect_out_md, fmt_report_tb, dl_report_btn]
515
  send_btn.click(fn=handle_gradio_chat_submit, inputs=chat_ins, outputs=chat_outs); user_msg_tb.submit(fn=handle_gradio_chat_submit, inputs=chat_ins, outputs=chat_outs)
516
-
517
  view_rules_btn.click(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
518
  def save_edited_rules_action_fn(edited_rules_text: str, progress=gr.Progress()):
519
  if not edited_rules_text.strip(): return "No rules text to save."
@@ -531,18 +524,14 @@ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Agent v5.6
531
  progress((idx+1)/total)
532
  return f"Editor Save: Added: {added}, Skipped (duplicates): {skipped}, Errors/Invalid: {errors}."
533
  save_edited_rules_btn.click(fn=save_edited_rules_action_fn, inputs=[rules_disp_ta], outputs=[rules_stat_tb], show_progress="full").then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
534
-
535
  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)
536
  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)
537
-
538
- if MEMORY_STORAGE_BACKEND == "RAM" and 'save_faiss_sidebar_btn' in locals() and save_faiss_sidebar_btn is not None: # Check button in sidebar
539
- def save_faiss_action_with_feedback_sidebar_fn(): save_faiss_indices_to_disk(); gr.Info("Attempted to save FAISS indices to disk (Sidebar).")
540
  save_faiss_sidebar_btn.click(fn=save_faiss_action_with_feedback_sidebar_fn, inputs=None, outputs=None)
541
-
542
  view_mems_btn.click(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
543
  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)
544
  clear_mems_btn.click(fn=lambda: "All memories cleared." if clear_all_memory_data_backend() else "Error clearing memories.", outputs=mems_stat_tb).then(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
545
-
546
  def app_load_fn():
547
  initialize_memory_system()
548
  logger.info("App loaded. Memory system initialized.")
@@ -550,11 +539,10 @@ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Agent v5.6
550
  rules_on_load = ui_view_rules_action_fn()
551
  mems_on_load = ui_view_memories_action_fn()
552
  return backend_status, rules_on_load, mems_on_load
553
-
554
  demo.load(fn=app_load_fn, inputs=None, outputs=[agent_stat_tb, rules_disp_ta, mems_disp_json])
555
 
556
  if __name__ == "__main__":
557
- logger.info(f"Starting Gradio AI Research Mega Agent (v5.6 - UI Layout Fix, Memory: {MEMORY_STORAGE_BACKEND})...")
558
  app_port, app_server = int(os.getenv("GRADIO_PORT", 7860)), os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
559
  app_debug, app_share = os.getenv("GRADIO_DEBUG", "False").lower()=="true", os.getenv("GRADIO_SHARE", "False").lower()=="true"
560
  logger.info(f"Launching Gradio server: http://{app_server}:{app_port}. Debug: {app_debug}, Share: {app_share}")
 
395
  logger.info(msg); return msg
396
 
397
  # --- UI Definition ---
398
+ # Using the CSS from the "AI Code & Space Generator" example
399
  custom_theme = gr.themes.Base(
400
  primary_hue="teal",
401
  secondary_hue="purple",
402
  neutral_hue="zinc",
403
+ text_size="sm",
404
+ spacing_size="md",
405
  radius_size="sm",
406
+ font=["System UI", "sans-serif"] # Base font
407
  )
408
 
 
409
  custom_css = """
410
+ body, html { margin: 0 !important; padding: 0 !important; height: 100%; overflow-y: auto !important; /* Ensure body can scroll */ }
411
+ body { background: linear-gradient(to bottom right, #2c3e50, #34495e); color: #ecf0f1; font-family: 'System UI', sans-serif; }
412
+ .gradio-container { background: transparent !important; max-width: 100% !important; padding: 1em !important; /* Add some padding to the main container */ box-sizing: border-box; min-height: 100vh; display: flex; flex-direction: column;}
413
+ .gr-block.gr-group, .gr-tabs, .gr-accordion { background-color: rgba(44, 62, 80, 0.8) !important; border: 1px solid rgba(189, 195, 199, 0.2) !important; border-radius: 8px !important; padding: 1em; margin-bottom: 1em;}
414
+ .gr-tabitem { background-color: rgba(52, 73, 94, 0.75) !important; border-radius: 6px !important; padding: 1em !important; border: 1px solid rgba(189, 195, 199, 0.1) !important;}
415
+ .gr-textbox, .gr-dropdown, .gr-button, .gr-code, .gr-chat-message, .gr-json, .gr-file input[type="file"], .gr-file button { 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;}
416
+ .gr-textarea textarea, .gr-textbox input { color: #ecf0f1 !important; }
 
 
 
417
  .gr-button.gr-button-primary { background-color: #1abc9c !important; color: white !important; border-color: #16a085 !important; }
418
+ .gr-button.gr-button-secondary { background-color: #9b59b6 !important; color: white !important; border-color: #8e44ad !important;}
419
+ .gr-button.gr-button-stop { background-color: #e74c3c !important; color: white !important; border-color: #c0392b !important;}
420
+ .gr-markdown { padding: 10px; border-radius: 5px; /* Retain some original markdown styling if it's standalone */ }
421
+ .gr-group .gr-markdown { padding: 0px; background-color: transparent !important; } /* Markdown inside group is transparent */
422
+ .gr-markdown h1, .gr-markdown h2, .gr-markdown h3 { color: #ecf0f1 !important; border-bottom-color: rgba(189, 195, 199, 0.3) !important; margin-top: 0.5em; margin-bottom: 0.5em;}
423
+ .gr-markdown h1 {font-size: 1.5rem;} .gr-markdown h2 {font-size: 1.25rem;} .gr-markdown h3 {font-size: 1.1rem;}
424
+ .gr-markdown p, .gr-markdown li { color: #ecf0f1 !important; }
425
+ .gr-markdown pre code { background-color: rgba(52, 73, 94, 0.95) !important; border-color: rgba(189, 195, 199, 0.3) !important; }
426
+ .gr-chatbot { background-color: rgba(44, 62, 80, 0.7) !important; border-color: rgba(189, 195, 199, 0.2) !important; }
427
+ .gr-chatbot .message { background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; border-color: rgba(189, 195, 199, 0.3) !important; }
428
+ .gr-chatbot .message.user { background-color: rgba(46, 204, 113, 0.9) !important; color: black !important; }
429
+ .gr-input-label > .label-text, .gr-dropdown-label > .label-text { color: #bdc3c7 !important; }
430
+ .status-bar { padding: 0.5rem 1rem; border-radius: 6px; margin-bottom: 1rem; background-color: rgba(44, 62, 80, 0.8) !important; }
431
+ .tabnav button { background-color: rgba(52, 73, 94, 0.8) !important; color: #ecf0f1 !important; border-bottom: 2px solid transparent !important; border-top-left-radius: 6px !important; border-top-right-radius: 6px !important;}
432
+ .tabnav button.selected { background-color: rgba(44, 62, 80, 0.95) !important; color: #1abc9c !important; border-bottom: 2px solid #1abc9c !important;}
433
+ #app-title { text-align: center; color: #ecf0f1; font-size: 1.8rem; margin: 0.5em 0 0.2em 0;}
434
+ #app-subtitle { text-align: center; color: #bdc3c7; font-size: 0.9rem; margin-bottom: 1em;}
435
+ .sidebar { padding-right: 1em; } /* Add some spacing for sidebar */
436
+ .main-content { flex-grow: 1; display: flex; flex-direction: column; }
437
+ .chat-area { flex-grow: 1; display: flex; flex-direction: column; }
438
+ .chat-output-area { flex-grow: 1; }
439
  """
440
 
441
+ with gr.Blocks(theme=custom_theme, css=custom_css, title="AI Research Agent v5.7") as demo:
442
+ gr.Markdown("# πŸ€– AI Research Agent", elem_id="app-title") # Using elem_id for specific title styling
443
+ gr.Markdown("Configure settings, chat with AI for research, and manage its knowledge.", elem_id="app-subtitle")
444
+
445
+ avail_provs = get_available_providers()
446
+ def_prov = avail_provs[0] if avail_provs else None
447
+ def_models = get_model_display_names_for_provider(def_prov) if def_prov else []
448
+ def_model_disp = get_default_model_display_name_for_provider(def_prov) if def_prov else None
449
+
450
+ with gr.Row(elem_classes="status-bar"):
451
+ with gr.Column(scale=3): agent_stat_tb = gr.Textbox(label="Agent Status", interactive=False, value="Initializing...", lines=1)
452
+ with gr.Column(scale=1): memory_backend_info_tb = gr.Textbox(label="Memory Backend", value=f"{MEMORY_STORAGE_BACKEND}", interactive=False, lines=1)
453
+ # Conditional display for backend path info
454
+ sqlite_path_display = gr.Textbox(label="SQLite Path", value=f"{MEMORY_SQLITE_PATH}", interactive=False, visible=(MEMORY_STORAGE_BACKEND == "SQLITE"))
455
+ hf_repos_display = gr.Textbox(label="HF Repos", value=f"M: {MEMORY_HF_MEM_REPO}, R: {MEMORY_HF_RULES_REPO}", interactive=False, visible=(MEMORY_STORAGE_BACKEND == "HF_DATASET"))
 
 
 
 
456
 
457
+ with gr.Row(equal_height=False):
458
+ with gr.Column(scale=1, min_width=360, elem_classes="sidebar"): # This is the single sidebar
459
+ gr.Markdown("## βš™οΈ Configuration")
460
+ with gr.Group():
461
+ gr.Markdown("### API & Model Settings")
462
+ api_key_tb = gr.Textbox(label="AI Provider API Key (Override)", type="password", placeholder="Uses .env if blank")
463
+ prov_sel_dd = gr.Dropdown(label="AI Provider", choices=avail_provs, value=def_prov, interactive=True)
464
+ model_sel_dd = gr.Dropdown(label="AI Model", choices=def_models, value=def_model_disp, interactive=True)
465
+ with gr.Group():
466
+ gr.Markdown("### System Prompt")
467
+ sys_prompt_tb = gr.Textbox(label="System Prompt Base", lines=10, value=DEFAULT_SYSTEM_PROMPT, interactive=True)
468
+ if MEMORY_STORAGE_BACKEND == "RAM":
469
+ save_faiss_sidebar_btn = gr.Button("Save FAISS Indices", variant="secondary")
 
470
 
471
+ with gr.Column(scale=2, elem_classes="main-content"): # Main content area
472
+ with gr.Tabs():
473
+ with gr.TabItem("πŸ’¬ AI Chat & Research"):
474
+ with gr.Column(elem_classes="chat-area"): # Make chat area flexible
475
+ gr.Markdown("### AI Chat Interface")
476
+ main_chat_disp = gr.Chatbot(label="AI Research Chat", height=500, elem_classes="chat-output-area", 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)
477
  with gr.Row():
478
+ user_msg_tb = gr.Textbox(show_label=False, placeholder="Ask your research question...", scale=7, lines=1, max_lines=5, autofocus=True)
479
  send_btn = gr.Button("Send", variant="primary", scale=1, min_width=100)
480
+ with gr.Accordion("πŸ“ Full Response / Details", open=False):
481
+ fmt_report_tb = gr.Textbox(label="Full AI Response", lines=10, interactive=True, show_copy_button=True)
482
+ dl_report_btn = gr.DownloadButton(value="Download Report", interactive=False, visible=False)
483
+ detect_out_md = gr.Markdown()
484
 
485
+ with gr.TabItem("🧠 Knowledge Base"):
486
+ gr.Markdown("## Manage Stored Knowledge")
487
+ with gr.Row():
488
+ with gr.Column():
489
+ with gr.Group():
490
+ gr.Markdown("### πŸ“œ Rules (Insights)")
491
+ rules_disp_ta = gr.TextArea(label="View/Edit Rules", lines=15, interactive=True, placeholder="Load rules or type new ones...")
492
+ with gr.Row(): view_rules_btn = gr.Button("πŸ”„ Load"); save_edited_rules_btn = gr.Button("πŸ’Ύ Save Edits", variant="primary")
493
+ upload_rules_fobj = gr.File(label="Upload Rules File (.txt/.jsonl)", file_types=[".txt", ".jsonl"])
494
+ rules_stat_tb = gr.Textbox(label="Rules Status", interactive=False, lines=2)
495
+ clear_rules_btn = gr.Button("⚠️ Clear All Rules", variant="stop")
496
+ with gr.Column():
497
+ with gr.Group():
498
+ gr.Markdown("### πŸ“š Memories")
499
+ mems_disp_json = gr.JSON(label="View Memories")
500
+ view_mems_btn = gr.Button("πŸ”„ Load Memories")
501
+ upload_mems_fobj = gr.File(label="Upload Memories File (.jsonl)", file_types=[".jsonl"])
502
+ mems_stat_tb = gr.Textbox(label="Memories Status", interactive=False, lines=2)
503
+ clear_mems_btn = gr.Button("⚠️ Clear All Memories", variant="stop")
 
 
504
 
505
  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)
506
  prov_sel_dd.change(fn=dyn_upd_model_dd, inputs=prov_sel_dd, outputs=model_sel_dd)
507
  chat_ins = [user_msg_tb, main_chat_disp, prov_sel_dd, model_sel_dd, api_key_tb, sys_prompt_tb]
508
  chat_outs = [user_msg_tb, main_chat_disp, agent_stat_tb, detect_out_md, fmt_report_tb, dl_report_btn]
509
  send_btn.click(fn=handle_gradio_chat_submit, inputs=chat_ins, outputs=chat_outs); user_msg_tb.submit(fn=handle_gradio_chat_submit, inputs=chat_ins, outputs=chat_outs)
 
510
  view_rules_btn.click(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
511
  def save_edited_rules_action_fn(edited_rules_text: str, progress=gr.Progress()):
512
  if not edited_rules_text.strip(): return "No rules text to save."
 
524
  progress((idx+1)/total)
525
  return f"Editor Save: Added: {added}, Skipped (duplicates): {skipped}, Errors/Invalid: {errors}."
526
  save_edited_rules_btn.click(fn=save_edited_rules_action_fn, inputs=[rules_disp_ta], outputs=[rules_stat_tb], show_progress="full").then(fn=ui_view_rules_action_fn, outputs=rules_disp_ta)
 
527
  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)
528
  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)
529
+ if MEMORY_STORAGE_BACKEND == "RAM" and 'save_faiss_sidebar_btn' in locals() and save_faiss_sidebar_btn is not None:
530
+ def save_faiss_action_with_feedback_sidebar_fn(): save_faiss_indices_to_disk(); gr.Info("Attempted to save FAISS indices to disk.")
 
531
  save_faiss_sidebar_btn.click(fn=save_faiss_action_with_feedback_sidebar_fn, inputs=None, outputs=None)
 
532
  view_mems_btn.click(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
533
  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)
534
  clear_mems_btn.click(fn=lambda: "All memories cleared." if clear_all_memory_data_backend() else "Error clearing memories.", outputs=mems_stat_tb).then(fn=ui_view_memories_action_fn, outputs=mems_disp_json)
 
535
  def app_load_fn():
536
  initialize_memory_system()
537
  logger.info("App loaded. Memory system initialized.")
 
539
  rules_on_load = ui_view_rules_action_fn()
540
  mems_on_load = ui_view_memories_action_fn()
541
  return backend_status, rules_on_load, mems_on_load
 
542
  demo.load(fn=app_load_fn, inputs=None, outputs=[agent_stat_tb, rules_disp_ta, mems_disp_json])
543
 
544
  if __name__ == "__main__":
545
+ logger.info(f"Starting Gradio AI Research Mega Agent (v5.7 - UI Scroll Fix Attempt, Memory: {MEMORY_STORAGE_BACKEND})...")
546
  app_port, app_server = int(os.getenv("GRADIO_PORT", 7860)), os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
547
  app_debug, app_share = os.getenv("GRADIO_DEBUG", "False").lower()=="true", os.getenv("GRADIO_SHARE", "False").lower()=="true"
548
  logger.info(f"Launching Gradio server: http://{app_server}:{app_port}. Debug: {app_debug}, Share: {app_share}")