broadfield-dev commited on
Commit
bde9819
·
verified ·
1 Parent(s): 46a1809

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -21
app.py CHANGED
@@ -169,7 +169,7 @@ def process_user_interaction_gradio(user_input: str, provider_name: str, model_d
169
  logger.debug(f"PUI_GRADIO [{request_id}]: Final LLM User Prompt Start: {final_user_prompt_content_str[:200]}...")
170
  streamed_response, time_before_llm = "", time.time()
171
  try:
172
- for chunk in call_model_stream(provider=provider_name, model_display_name=model_display_name, messages=final_llm_messages, api_key_override=ui_api_key_override, temperature=0.6, max_tokens=2500): # Increased max_tokens for main response
173
  if isinstance(chunk, str) and chunk.startswith("Error:"): streamed_response += f"\n{chunk}\n"; yield "response_chunk", f"\n{chunk}\n"; break
174
  streamed_response += chunk; yield "response_chunk", chunk
175
  except Exception as e: streamed_response += f"\n\n(Error: {str(e)[:150]})"; yield "response_chunk", f"\n\n(Error: {str(e)[:150]})"
@@ -184,7 +184,8 @@ def deferred_learning_and_memory_task(user_input: str, bot_response: str, provid
184
  try:
185
  metrics = generate_interaction_metrics(user_input, bot_response, provider, model_disp_name, api_key_override)
186
  logger.info(f"DEFERRED [{task_id}]: Metrics: {metrics}")
187
- add_memory_entry(user_input, metrics, bot_response)
 
188
  summary = f"User:\"{user_input}\"\nAI:\"{bot_response}\"\nMetrics(takeaway):{metrics.get('takeaway','N/A')},Success:{metrics.get('response_success_score','N/A')}"
189
  existing_rules_ctx = "\n".join([f"- \"{r}\"" for r in retrieve_rules_semantic(f"{summary}\n{user_input}", k=10)]) or "No existing rules context."
190
 
@@ -240,12 +241,10 @@ Combine all findings into a single, valid XML structure as specified in the syst
240
  if i_d_n: insight_prov, insight_model_disp = i_p, i_d_n
241
  logger.info(f"DEFERRED [{task_id}]: Generating insights with {insight_prov}/{insight_model_disp} (expecting XML)")
242
 
243
- # Increase max_tokens significantly for XML, as it can be more verbose than JSON
244
- raw_ops_xml_full = "".join(list(call_model_stream(provider=insight_prov, model_display_name=insight_model_disp, messages=insight_msgs, api_key_override=api_key_override, temperature=0.0, max_tokens=3500))).strip() # Increased max_tokens
245
 
246
  ops_data_list, processed_count = [], 0
247
 
248
- # Try to find XML block, possibly within markdown
249
  xml_match = re.search(r"```xml\s*(<operations_list>.*</operations_list>)\s*```", raw_ops_xml_full, re.DOTALL | re.IGNORECASE) or \
250
  re.search(r"(<operations_list>.*</operations_list>)", raw_ops_xml_full, re.DOTALL | re.IGNORECASE)
251
 
@@ -267,7 +266,7 @@ Combine all findings into a single, valid XML structure as specified in the syst
267
  ops_data_list.append({
268
  "action": action,
269
  "insight": insight_text,
270
- "old_insight_to_replace": old_insight_text # Can be None
271
  })
272
  else:
273
  logger.warning(f"DEFERRED [{task_id}]: Skipped XML operation due to missing action or insight text. Action: {action}, Insight: {insight_text}")
@@ -287,25 +286,24 @@ Combine all findings into a single, valid XML structure as specified in the syst
287
  insight_text = op_data["insight"]
288
  old_insight = op_data["old_insight_to_replace"]
289
 
290
- # Validation of insight_text format
291
  if not re.match(r"\[(CORE_RULE|RESPONSE_PRINCIPLE|BEHAVIORAL_ADJUSTMENT|GENERAL_LEARNING)\|([\d\.]+?)\]", insight_text, re.I|re.DOTALL):
292
  logger.warning(f"DEFERRED [{task_id}]: Op {op_idx}: Skipped op due to invalid insight_text format from XML: '{insight_text[:100]}...'")
293
  continue
294
 
295
  if action == "add":
296
- success, status_msg = add_rule_entry(insight_text)
297
  if success: processed_count +=1
298
  else: logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (add from XML): Failed to add rule '{insight_text[:50]}...'. Status: {status_msg}")
299
  elif action == "update":
300
  if old_insight:
301
  if old_insight != insight_text:
302
- remove_success = remove_rule_entry(old_insight)
303
  if not remove_success:
304
  logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Failed to remove old rule '{old_insight[:50]}...' before adding new.")
305
  else:
306
  logger.info(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Old insight is identical to new insight. Skipping removal.")
307
 
308
- success, status_msg = add_rule_entry(insight_text)
309
  if success: processed_count +=1
310
  else: logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Failed to add/update rule '{insight_text[:50]}...'. Status: {status_msg}")
311
  else:
@@ -318,15 +316,10 @@ Combine all findings into a single, valid XML structure as specified in the syst
318
  except Exception as e: logger.error(f"DEFERRED [{task_id}]: CRITICAL ERROR in deferred task: {e}", exc_info=True)
319
  logger.info(f"DEFERRED [{task_id}]: END. Total: {time.time() - start_time:.2f}s")
320
 
321
- # --- handle_gradio_chat_submit, UI functions, Gradio Layout ... ---
322
- # (The rest of the file: handle_gradio_chat_submit, all ui_... functions, and the
323
- # `with gr.Blocks(...) as demo:` section, and `if __name__ == "__main__":`
324
- # remain THE SAME as the previous fully correct version (v6.1) you provided.
325
- # No changes are needed in those sections for this XML switch.)
326
-
327
  def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_name: str, sel_model_disp_name: str, ui_api_key: str|None, cust_sys_prompt: str):
328
  global current_chat_session_history
329
  cleared_input, updated_gr_hist, status_txt = "", list(gr_hist_list), "Initializing..."
 
330
  def_detect_out_md = gr.Markdown(visible=False)
331
  def_fmt_out_txt = gr.Textbox(value="*Waiting...*", interactive=True)
332
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
@@ -402,7 +395,9 @@ def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_na
402
  if len(current_chat_session_history) > hist_len_check:
403
  current_chat_session_history = ([current_chat_session_history[0]] if current_chat_session_history[0]["role"] == "system" else []) + current_chat_session_history[-(MAX_HISTORY_TURNS * 2):]
404
 
405
- threading.Thread(target=deferred_learning_and_memory_task, args=(user_msg_txt, final_bot_resp_acc, sel_prov_name, sel_model_disp_name, insights_used_parsed, ui_api_key.strip() if ui_api_key else None), daemon=True).start()
 
 
406
  status_txt = "Response complete. Background learning initiated."
407
  else:
408
  status_txt = "Processing finished; no valid response or error occurred."
@@ -413,8 +408,19 @@ def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_na
413
  def_fmt_out_txt = gr.Textbox(value=final_bot_resp_acc, interactive=True)
414
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
415
 
 
416
  yield (cleared_input, updated_gr_hist, status_txt, def_detect_out_md, def_fmt_out_txt, def_dl_btn)
417
 
 
 
 
 
 
 
 
 
 
 
418
  if temp_dl_file_path and os.path.exists(temp_dl_file_path):
419
  try: os.unlink(temp_dl_file_path)
420
  except Exception as e_unlink: logger.error(f"Error deleting temp download file {temp_dl_file_path}: {e_unlink}")
@@ -456,7 +462,6 @@ def ui_upload_rules_action_fn(uploaded_file_obj, progress=gr.Progress()):
456
  line = line.strip()
457
  if line:
458
  try:
459
- # Expect each line to be a JSON string containing the rule text itself
460
  rule_text_in_json_string = json.loads(line)
461
  if isinstance(rule_text_in_json_string, str):
462
  potential_rules.append(rule_text_in_json_string)
@@ -713,15 +718,28 @@ with gr.Blocks(
713
  chat_ins = [user_msg_tb, main_chat_disp, prov_sel_dd, model_sel_dd, api_key_tb, sys_prompt_tb]
714
  chat_outs = [user_msg_tb, main_chat_disp, agent_stat_tb, detect_out_md, fmt_report_tb, dl_report_btn]
715
 
 
 
 
 
 
 
 
 
716
  chat_event_args = {"fn": handle_gradio_chat_submit, "inputs": chat_ins, "outputs": chat_outs}
717
 
 
718
  send_btn_click_event = send_btn.click(**chat_event_args)
719
  user_msg_submit_event = user_msg_tb.submit(**chat_event_args)
720
 
 
 
 
721
  for event in [send_btn_click_event, user_msg_submit_event]:
722
  event.then(fn=ui_refresh_rules_display_fn, inputs=None, outputs=rules_disp_ta, show_progress=False)
723
  event.then(fn=ui_refresh_memories_display_fn, inputs=None, outputs=mems_disp_json, show_progress=False)
724
 
 
725
  # Rules Management events
726
  dl_rules_btn.click(fn=ui_download_rules_action_fn, inputs=None, outputs=dl_rules_btn)
727
 
@@ -770,7 +788,7 @@ with gr.Blocks(
770
  clear_rules_btn.click(
771
  fn=lambda: ("All rules cleared." if clear_all_rules_data_backend() else "Error clearing rules."),
772
  outputs=rules_stat_tb,
773
- show_progress=False
774
  ).then(fn=ui_refresh_rules_display_fn, outputs=rules_disp_ta, show_progress=False)
775
 
776
  # Memories Management events
@@ -786,7 +804,7 @@ with gr.Blocks(
786
  clear_mems_btn.click(
787
  fn=lambda: ("All memories cleared." if clear_all_memory_data_backend() else "Error clearing memories."),
788
  outputs=mems_stat_tb,
789
- show_progress=False
790
  ).then(fn=ui_refresh_memories_display_fn, outputs=mems_disp_json, show_progress=False)
791
 
792
  if MEMORY_STORAGE_BACKEND == "RAM" and 'save_faiss_sidebar_btn' in locals():
@@ -822,7 +840,7 @@ with gr.Blocks(
822
 
823
 
824
  if __name__ == "__main__":
825
- logger.info(f"Starting Gradio AI Research Mega Agent (v6.2 - XML Insights & Max Tokens, Memory: {MEMORY_STORAGE_BACKEND})...")
826
  app_port = int(os.getenv("GRADIO_PORT", 7860))
827
  app_server = os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
828
  app_debug = os.getenv("GRADIO_DEBUG", "False").lower() == "true"
 
169
  logger.debug(f"PUI_GRADIO [{request_id}]: Final LLM User Prompt Start: {final_user_prompt_content_str[:200]}...")
170
  streamed_response, time_before_llm = "", time.time()
171
  try:
172
+ for chunk in call_model_stream(provider=provider_name, model_display_name=model_display_name, messages=final_llm_messages, api_key_override=ui_api_key_override, temperature=0.6, max_tokens=2500):
173
  if isinstance(chunk, str) and chunk.startswith("Error:"): streamed_response += f"\n{chunk}\n"; yield "response_chunk", f"\n{chunk}\n"; break
174
  streamed_response += chunk; yield "response_chunk", chunk
175
  except Exception as e: streamed_response += f"\n\n(Error: {str(e)[:150]})"; yield "response_chunk", f"\n\n(Error: {str(e)[:150]})"
 
184
  try:
185
  metrics = generate_interaction_metrics(user_input, bot_response, provider, model_disp_name, api_key_override)
186
  logger.info(f"DEFERRED [{task_id}]: Metrics: {metrics}")
187
+ add_memory_entry(user_input, metrics, bot_response) # This updates in-memory lists quickly
188
+
189
  summary = f"User:\"{user_input}\"\nAI:\"{bot_response}\"\nMetrics(takeaway):{metrics.get('takeaway','N/A')},Success:{metrics.get('response_success_score','N/A')}"
190
  existing_rules_ctx = "\n".join([f"- \"{r}\"" for r in retrieve_rules_semantic(f"{summary}\n{user_input}", k=10)]) or "No existing rules context."
191
 
 
241
  if i_d_n: insight_prov, insight_model_disp = i_p, i_d_n
242
  logger.info(f"DEFERRED [{task_id}]: Generating insights with {insight_prov}/{insight_model_disp} (expecting XML)")
243
 
244
+ raw_ops_xml_full = "".join(list(call_model_stream(provider=insight_prov, model_display_name=insight_model_disp, messages=insight_msgs, api_key_override=api_key_override, temperature=0.0, max_tokens=3500))).strip()
 
245
 
246
  ops_data_list, processed_count = [], 0
247
 
 
248
  xml_match = re.search(r"```xml\s*(<operations_list>.*</operations_list>)\s*```", raw_ops_xml_full, re.DOTALL | re.IGNORECASE) or \
249
  re.search(r"(<operations_list>.*</operations_list>)", raw_ops_xml_full, re.DOTALL | re.IGNORECASE)
250
 
 
266
  ops_data_list.append({
267
  "action": action,
268
  "insight": insight_text,
269
+ "old_insight_to_replace": old_insight_text
270
  })
271
  else:
272
  logger.warning(f"DEFERRED [{task_id}]: Skipped XML operation due to missing action or insight text. Action: {action}, Insight: {insight_text}")
 
286
  insight_text = op_data["insight"]
287
  old_insight = op_data["old_insight_to_replace"]
288
 
 
289
  if not re.match(r"\[(CORE_RULE|RESPONSE_PRINCIPLE|BEHAVIORAL_ADJUSTMENT|GENERAL_LEARNING)\|([\d\.]+?)\]", insight_text, re.I|re.DOTALL):
290
  logger.warning(f"DEFERRED [{task_id}]: Op {op_idx}: Skipped op due to invalid insight_text format from XML: '{insight_text[:100]}...'")
291
  continue
292
 
293
  if action == "add":
294
+ success, status_msg = add_rule_entry(insight_text) # This updates in-memory lists quickly
295
  if success: processed_count +=1
296
  else: logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (add from XML): Failed to add rule '{insight_text[:50]}...'. Status: {status_msg}")
297
  elif action == "update":
298
  if old_insight:
299
  if old_insight != insight_text:
300
+ remove_success = remove_rule_entry(old_insight) # This updates in-memory lists quickly
301
  if not remove_success:
302
  logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Failed to remove old rule '{old_insight[:50]}...' before adding new.")
303
  else:
304
  logger.info(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Old insight is identical to new insight. Skipping removal.")
305
 
306
+ success, status_msg = add_rule_entry(insight_text) # This updates in-memory lists quickly
307
  if success: processed_count +=1
308
  else: logger.warning(f"DEFERRED [{task_id}]: Op {op_idx} (update from XML): Failed to add/update rule '{insight_text[:50]}...'. Status: {status_msg}")
309
  else:
 
316
  except Exception as e: logger.error(f"DEFERRED [{task_id}]: CRITICAL ERROR in deferred task: {e}", exc_info=True)
317
  logger.info(f"DEFERRED [{task_id}]: END. Total: {time.time() - start_time:.2f}s")
318
 
 
 
 
 
 
 
319
  def handle_gradio_chat_submit(user_msg_txt: str, gr_hist_list: list, sel_prov_name: str, sel_model_disp_name: str, ui_api_key: str|None, cust_sys_prompt: str):
320
  global current_chat_session_history
321
  cleared_input, updated_gr_hist, status_txt = "", list(gr_hist_list), "Initializing..."
322
+ # Ensure these are initialized with their correct Gradio update types
323
  def_detect_out_md = gr.Markdown(visible=False)
324
  def_fmt_out_txt = gr.Textbox(value="*Waiting...*", interactive=True)
325
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
 
395
  if len(current_chat_session_history) > hist_len_check:
396
  current_chat_session_history = ([current_chat_session_history[0]] if current_chat_session_history[0]["role"] == "system" else []) + current_chat_session_history[-(MAX_HISTORY_TURNS * 2):]
397
 
398
+ # Start the deferred task
399
+ deferred_task_thread = threading.Thread(target=deferred_learning_and_memory_task, args=(user_msg_txt, final_bot_resp_acc, sel_prov_name, sel_model_disp_name, insights_used_parsed, ui_api_key.strip() if ui_api_key else None), daemon=True)
400
+ deferred_task_thread.start()
401
  status_txt = "Response complete. Background learning initiated."
402
  else:
403
  status_txt = "Processing finished; no valid response or error occurred."
 
408
  def_fmt_out_txt = gr.Textbox(value=final_bot_resp_acc, interactive=True)
409
  def_dl_btn = gr.DownloadButton(interactive=False, value=None, visible=False)
410
 
411
+ # Final yield for the main chat processing
412
  yield (cleared_input, updated_gr_hist, status_txt, def_detect_out_md, def_fmt_out_txt, def_dl_btn)
413
 
414
+ # After the main response is fully yielded, and the deferred task thread is started,
415
+ # we can add a small delay here before the .then() clauses trigger the UI refresh.
416
+ # This gives the deferred task's initial, fast in-memory updates (like add_memory_entry)
417
+ # a better chance to complete before the UI tries to read that data.
418
+ # The LLM-based rule generation within the deferred task will still take longer.
419
+ if 'deferred_task_thread' in locals() and deferred_task_thread.is_alive():
420
+ # Wait a very short period for synchronous parts of deferred task
421
+ # This is a heuristic. The value might need tuning.
422
+ time.sleep(0.2) # e.g., 200 milliseconds
423
+
424
  if temp_dl_file_path and os.path.exists(temp_dl_file_path):
425
  try: os.unlink(temp_dl_file_path)
426
  except Exception as e_unlink: logger.error(f"Error deleting temp download file {temp_dl_file_path}: {e_unlink}")
 
462
  line = line.strip()
463
  if line:
464
  try:
 
465
  rule_text_in_json_string = json.loads(line)
466
  if isinstance(rule_text_in_json_string, str):
467
  potential_rules.append(rule_text_in_json_string)
 
718
  chat_ins = [user_msg_tb, main_chat_disp, prov_sel_dd, model_sel_dd, api_key_tb, sys_prompt_tb]
719
  chat_outs = [user_msg_tb, main_chat_disp, agent_stat_tb, detect_out_md, fmt_report_tb, dl_report_btn]
720
 
721
+ # Define a dummy function to introduce a delay if needed for UI refresh.
722
+ # For now, we will try without an explicit Gradio-level delay here,
723
+ # relying on the small time.sleep in handle_gradio_chat_submit's final part.
724
+ # def delayed_refresh_trigger():
725
+ # time.sleep(0.2) # Small delay
726
+ # return True # Or any value, just to trigger the next .then()
727
+
728
+ # chat_event_args is a dictionary containing common arguments for click/submit
729
  chat_event_args = {"fn": handle_gradio_chat_submit, "inputs": chat_ins, "outputs": chat_outs}
730
 
731
+ # Setup events for chat submission
732
  send_btn_click_event = send_btn.click(**chat_event_args)
733
  user_msg_submit_event = user_msg_tb.submit(**chat_event_args)
734
 
735
+ # Chain UI refreshes to occur after the chat processing logic (including the small sleep)
736
+ # The `handle_gradio_chat_submit` now includes a small sleep before its final yield
737
+ # if a deferred task was started. This should be sufficient for the fast in-memory updates.
738
  for event in [send_btn_click_event, user_msg_submit_event]:
739
  event.then(fn=ui_refresh_rules_display_fn, inputs=None, outputs=rules_disp_ta, show_progress=False)
740
  event.then(fn=ui_refresh_memories_display_fn, inputs=None, outputs=mems_disp_json, show_progress=False)
741
 
742
+
743
  # Rules Management events
744
  dl_rules_btn.click(fn=ui_download_rules_action_fn, inputs=None, outputs=dl_rules_btn)
745
 
 
788
  clear_rules_btn.click(
789
  fn=lambda: ("All rules cleared." if clear_all_rules_data_backend() else "Error clearing rules."),
790
  outputs=rules_stat_tb,
791
+ show_progress=False # It's a quick operation
792
  ).then(fn=ui_refresh_rules_display_fn, outputs=rules_disp_ta, show_progress=False)
793
 
794
  # Memories Management events
 
804
  clear_mems_btn.click(
805
  fn=lambda: ("All memories cleared." if clear_all_memory_data_backend() else "Error clearing memories."),
806
  outputs=mems_stat_tb,
807
+ show_progress=False # Quick op
808
  ).then(fn=ui_refresh_memories_display_fn, outputs=mems_disp_json, show_progress=False)
809
 
810
  if MEMORY_STORAGE_BACKEND == "RAM" and 'save_faiss_sidebar_btn' in locals():
 
840
 
841
 
842
  if __name__ == "__main__":
843
+ logger.info(f"Starting Gradio AI Research Mega Agent (v6.3 - Delayed UI Refresh Attempt, Memory: {MEMORY_STORAGE_BACKEND})...")
844
  app_port = int(os.getenv("GRADIO_PORT", 7860))
845
  app_server = os.getenv("GRADIO_SERVER_NAME", "127.0.0.1")
846
  app_debug = os.getenv("GRADIO_DEBUG", "False").lower() == "true"