Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
e4c0a6a
1
Parent(s):
ab69c75
Enable MAC thought demo mode
Browse files
app.py
CHANGED
|
@@ -37,6 +37,42 @@ os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
| 37 |
# Set logging to INFO level for cleaner output
|
| 38 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 39 |
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
# Set MCP client logging to WARNING to reduce noise
|
| 41 |
mcp_client_logger = logging.getLogger("mcp.client")
|
| 42 |
mcp_client_logger.setLevel(logging.WARNING)
|
|
@@ -2159,12 +2195,21 @@ def stream_chat(
|
|
| 2159 |
medical_model: str,
|
| 2160 |
use_web_search: bool,
|
| 2161 |
disable_agentic_reasoning: bool,
|
|
|
|
| 2162 |
request: gr.Request
|
| 2163 |
):
|
| 2164 |
if not request:
|
| 2165 |
-
yield history + [{"role": "assistant", "content": "Session initialization failed. Please refresh the page."}]
|
| 2166 |
return
|
| 2167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2168 |
session_start = time.time()
|
| 2169 |
soft_timeout = 100
|
| 2170 |
hard_timeout = 118 # stop slightly before HF max duration (120s)
|
|
@@ -2287,7 +2332,8 @@ def stream_chat(
|
|
| 2287 |
{"role": "user", "content": original_message},
|
| 2288 |
{"role": "assistant", "content": ""}
|
| 2289 |
]
|
| 2290 |
-
|
|
|
|
| 2291 |
|
| 2292 |
for idx, sub_topic in enumerate(breakdown.get("sub_topics", []), 1):
|
| 2293 |
if elapsed() >= hard_timeout - 5:
|
|
@@ -2329,7 +2375,8 @@ def stream_chat(
|
|
| 2329 |
# Stream partial answer as we complete each task
|
| 2330 |
partial_final = "\n\n".join(medswin_answers)
|
| 2331 |
updated_history[-1]["content"] = partial_final
|
| 2332 |
-
|
|
|
|
| 2333 |
|
| 2334 |
except Exception as e:
|
| 2335 |
logger.error(f"[MEDSWIN] Task {idx} failed: {e}")
|
|
@@ -2449,7 +2496,12 @@ def stream_chat(
|
|
| 2449 |
|
| 2450 |
# Update history with final answer (ONLY final answer, no internal thoughts)
|
| 2451 |
updated_history[-1]["content"] = final_answer_with_metadata
|
| 2452 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2453 |
|
| 2454 |
# Log completion
|
| 2455 |
logger.info(f"[MAC] Final answer generated: {len(final_answer)} chars, {len(breakdown.get('sub_topics', []))} tasks completed")
|
|
@@ -2601,6 +2653,20 @@ def create_demo():
|
|
| 2601 |
label="Disable agentic reasoning",
|
| 2602 |
info="Use MedSwin model alone without agentic reasoning, RAG, or web search"
|
| 2603 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2604 |
with gr.Row():
|
| 2605 |
use_rag = gr.Checkbox(
|
| 2606 |
value=False,
|
|
@@ -2680,6 +2746,20 @@ def create_demo():
|
|
| 2680 |
label="Merge Threshold (lower = more merging)"
|
| 2681 |
)
|
| 2682 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2683 |
submit_button.click(
|
| 2684 |
fn=stream_chat,
|
| 2685 |
inputs=[
|
|
@@ -2696,9 +2776,10 @@ def create_demo():
|
|
| 2696 |
use_rag,
|
| 2697 |
medical_model,
|
| 2698 |
use_web_search,
|
| 2699 |
-
disable_agentic_reasoning
|
|
|
|
| 2700 |
],
|
| 2701 |
-
outputs=chatbot
|
| 2702 |
)
|
| 2703 |
|
| 2704 |
message_input.submit(
|
|
@@ -2717,9 +2798,10 @@ def create_demo():
|
|
| 2717 |
use_rag,
|
| 2718 |
medical_model,
|
| 2719 |
use_web_search,
|
| 2720 |
-
disable_agentic_reasoning
|
|
|
|
| 2721 |
],
|
| 2722 |
-
outputs=chatbot
|
| 2723 |
)
|
| 2724 |
|
| 2725 |
return demo
|
|
|
|
| 37 |
# Set logging to INFO level for cleaner output
|
| 38 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 39 |
logger = logging.getLogger(__name__)
|
| 40 |
+
|
| 41 |
+
# Custom logger handler to capture agentic thoughts
|
| 42 |
+
class ThoughtCaptureHandler(logging.Handler):
|
| 43 |
+
"""Custom handler to capture internal thoughts from MedSwin and supervisor"""
|
| 44 |
+
def __init__(self):
|
| 45 |
+
super().__init__()
|
| 46 |
+
self.thoughts = []
|
| 47 |
+
self.lock = threading.Lock()
|
| 48 |
+
|
| 49 |
+
def emit(self, record):
|
| 50 |
+
"""Capture log messages that contain agentic thoughts"""
|
| 51 |
+
try:
|
| 52 |
+
msg = self.format(record)
|
| 53 |
+
# Only capture messages from GEMINI SUPERVISOR or MEDSWIN
|
| 54 |
+
if "[GEMINI SUPERVISOR]" in msg or "[MEDSWIN]" in msg or "[MAC]" in msg:
|
| 55 |
+
# Remove timestamp and logger name for cleaner display
|
| 56 |
+
# Format: "timestamp - logger - level - message"
|
| 57 |
+
parts = msg.split(" - ", 3)
|
| 58 |
+
if len(parts) >= 4:
|
| 59 |
+
clean_msg = parts[-1] # Get the message part
|
| 60 |
+
else:
|
| 61 |
+
clean_msg = msg
|
| 62 |
+
with self.lock:
|
| 63 |
+
self.thoughts.append(clean_msg)
|
| 64 |
+
except Exception:
|
| 65 |
+
pass # Ignore formatting errors
|
| 66 |
+
|
| 67 |
+
def get_thoughts(self):
|
| 68 |
+
"""Get all captured thoughts as a formatted string"""
|
| 69 |
+
with self.lock:
|
| 70 |
+
return "\n".join(self.thoughts)
|
| 71 |
+
|
| 72 |
+
def clear(self):
|
| 73 |
+
"""Clear captured thoughts"""
|
| 74 |
+
with self.lock:
|
| 75 |
+
self.thoughts = []
|
| 76 |
# Set MCP client logging to WARNING to reduce noise
|
| 77 |
mcp_client_logger = logging.getLogger("mcp.client")
|
| 78 |
mcp_client_logger.setLevel(logging.WARNING)
|
|
|
|
| 2195 |
medical_model: str,
|
| 2196 |
use_web_search: bool,
|
| 2197 |
disable_agentic_reasoning: bool,
|
| 2198 |
+
show_thoughts: bool,
|
| 2199 |
request: gr.Request
|
| 2200 |
):
|
| 2201 |
if not request:
|
| 2202 |
+
yield history + [{"role": "assistant", "content": "Session initialization failed. Please refresh the page."}], ""
|
| 2203 |
return
|
| 2204 |
|
| 2205 |
+
# Set up thought capture handler if show_thoughts is enabled
|
| 2206 |
+
thought_handler = None
|
| 2207 |
+
if show_thoughts:
|
| 2208 |
+
thought_handler = ThoughtCaptureHandler()
|
| 2209 |
+
thought_handler.setLevel(logging.INFO)
|
| 2210 |
+
thought_handler.clear() # Start fresh
|
| 2211 |
+
logger.addHandler(thought_handler)
|
| 2212 |
+
|
| 2213 |
session_start = time.time()
|
| 2214 |
soft_timeout = 100
|
| 2215 |
hard_timeout = 118 # stop slightly before HF max duration (120s)
|
|
|
|
| 2332 |
{"role": "user", "content": original_message},
|
| 2333 |
{"role": "assistant", "content": ""}
|
| 2334 |
]
|
| 2335 |
+
thoughts_text = thought_handler.get_thoughts() if thought_handler else ""
|
| 2336 |
+
yield updated_history, thoughts_text
|
| 2337 |
|
| 2338 |
for idx, sub_topic in enumerate(breakdown.get("sub_topics", []), 1):
|
| 2339 |
if elapsed() >= hard_timeout - 5:
|
|
|
|
| 2375 |
# Stream partial answer as we complete each task
|
| 2376 |
partial_final = "\n\n".join(medswin_answers)
|
| 2377 |
updated_history[-1]["content"] = partial_final
|
| 2378 |
+
thoughts_text = thought_handler.get_thoughts() if thought_handler else ""
|
| 2379 |
+
yield updated_history, thoughts_text
|
| 2380 |
|
| 2381 |
except Exception as e:
|
| 2382 |
logger.error(f"[MEDSWIN] Task {idx} failed: {e}")
|
|
|
|
| 2496 |
|
| 2497 |
# Update history with final answer (ONLY final answer, no internal thoughts)
|
| 2498 |
updated_history[-1]["content"] = final_answer_with_metadata
|
| 2499 |
+
thoughts_text = thought_handler.get_thoughts() if thought_handler else ""
|
| 2500 |
+
yield updated_history, thoughts_text
|
| 2501 |
+
|
| 2502 |
+
# Clean up thought handler
|
| 2503 |
+
if thought_handler:
|
| 2504 |
+
logger.removeHandler(thought_handler)
|
| 2505 |
|
| 2506 |
# Log completion
|
| 2507 |
logger.info(f"[MAC] Final answer generated: {len(final_answer)} chars, {len(breakdown.get('sub_topics', []))} tasks completed")
|
|
|
|
| 2653 |
label="Disable agentic reasoning",
|
| 2654 |
info="Use MedSwin model alone without agentic reasoning, RAG, or web search"
|
| 2655 |
)
|
| 2656 |
+
show_agentic_thought = gr.Button(
|
| 2657 |
+
"Show agentic thought",
|
| 2658 |
+
size="sm"
|
| 2659 |
+
)
|
| 2660 |
+
# Scrollable textbox for agentic thoughts (initially hidden)
|
| 2661 |
+
agentic_thoughts_box = gr.Textbox(
|
| 2662 |
+
label="Agentic Thoughts",
|
| 2663 |
+
placeholder="Internal thoughts from MedSwin and supervisor will appear here...",
|
| 2664 |
+
lines=8,
|
| 2665 |
+
max_lines=15,
|
| 2666 |
+
interactive=False,
|
| 2667 |
+
visible=False,
|
| 2668 |
+
elem_classes="agentic-thoughts"
|
| 2669 |
+
)
|
| 2670 |
with gr.Row():
|
| 2671 |
use_rag = gr.Checkbox(
|
| 2672 |
value=False,
|
|
|
|
| 2746 |
label="Merge Threshold (lower = more merging)"
|
| 2747 |
)
|
| 2748 |
|
| 2749 |
+
# Toggle function for showing/hiding agentic thoughts
|
| 2750 |
+
show_thoughts_state = gr.State(value=False)
|
| 2751 |
+
|
| 2752 |
+
def toggle_thoughts_box(current_state):
|
| 2753 |
+
"""Toggle visibility of agentic thoughts box"""
|
| 2754 |
+
new_state = not current_state
|
| 2755 |
+
return gr.update(visible=new_state), new_state
|
| 2756 |
+
|
| 2757 |
+
show_agentic_thought.click(
|
| 2758 |
+
fn=toggle_thoughts_box,
|
| 2759 |
+
inputs=[show_thoughts_state],
|
| 2760 |
+
outputs=[agentic_thoughts_box, show_thoughts_state]
|
| 2761 |
+
)
|
| 2762 |
+
|
| 2763 |
submit_button.click(
|
| 2764 |
fn=stream_chat,
|
| 2765 |
inputs=[
|
|
|
|
| 2776 |
use_rag,
|
| 2777 |
medical_model,
|
| 2778 |
use_web_search,
|
| 2779 |
+
disable_agentic_reasoning,
|
| 2780 |
+
show_thoughts_state
|
| 2781 |
],
|
| 2782 |
+
outputs=[chatbot, agentic_thoughts_box]
|
| 2783 |
)
|
| 2784 |
|
| 2785 |
message_input.submit(
|
|
|
|
| 2798 |
use_rag,
|
| 2799 |
medical_model,
|
| 2800 |
use_web_search,
|
| 2801 |
+
disable_agentic_reasoning,
|
| 2802 |
+
show_thoughts_state
|
| 2803 |
],
|
| 2804 |
+
outputs=[chatbot, agentic_thoughts_box]
|
| 2805 |
)
|
| 2806 |
|
| 2807 |
return demo
|