Spaces:
Sleeping
Sleeping
Оновлено модуль логування MAI-DX з виправленим парсером для надійнішого захоплення розмов агентів. Внесено зміни в обробку виводу, покращено форматування результатів та аналізу, а також додано нові функції для відображення активності агентів. Виправлено помилки в інтерфейсі та оновлено документацію.
Browse files- enhanced_mai_dx_logger.py +32 -39
- updated_mai_dx_interface.py +35 -51
enhanced_mai_dx_logger.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
Покращений модуль для повного логування діагностичних сесій MAI-DX
|
4 |
-
з детальним захопленням розмов між агентами.
|
5 |
"""
|
6 |
import os
|
7 |
import io
|
@@ -64,7 +64,8 @@ class EnhancedOutputCapture:
|
|
64 |
|
65 |
def write(self, text):
|
66 |
self.captured_output.write(text)
|
67 |
-
|
|
|
68 |
|
69 |
def flush(self):
|
70 |
self.original_stdout.flush()
|
@@ -95,6 +96,7 @@ class MAIDxConversationLogger:
|
|
95 |
|
96 |
def finalize_and_save_session(self, session: DiagnosisSession, result: Any, raw_output: str, duration: float) -> DiagnosisSession:
|
97 |
session.raw_output = raw_output
|
|
|
98 |
self._parse_captured_output(session, raw_output)
|
99 |
|
100 |
session.diagnosis = getattr(result, 'final_diagnosis', 'N/A')
|
@@ -110,6 +112,10 @@ class MAIDxConversationLogger:
|
|
110 |
return session
|
111 |
|
112 |
def _parse_captured_output(self, session: DiagnosisSession, captured_text: str):
|
|
|
|
|
|
|
|
|
113 |
lines = captured_text.split('\n')
|
114 |
current_round: Optional[AgentConversation] = None
|
115 |
current_agent: Optional[str] = None
|
@@ -119,67 +125,54 @@ class MAIDxConversationLogger:
|
|
119 |
|
120 |
for line in lines:
|
121 |
stripped_line = line.strip()
|
122 |
-
if not stripped_line: continue
|
123 |
-
|
124 |
-
if "Starting Diagnostic Loop" in line:
|
125 |
-
if current_round: current_round.end_time = datetime.now().isoformat()
|
126 |
-
round_match = re.search(r'Starting Diagnostic Loop (\d+)/\d+', line)
|
127 |
-
round_number = int(round_match.group(1)) if round_match else round_number + 1
|
128 |
-
current_round = AgentConversation(round_number=round_number, start_time=datetime.now().isoformat())
|
129 |
-
session.conversations.append(current_round)
|
130 |
-
continue
|
131 |
|
|
|
132 |
if "Agent Name" in line and ("╭" in line or "┌" in line):
|
133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
if agent_match:
|
135 |
current_agent = agent_match.group(1).strip()
|
136 |
in_agent_output = True
|
137 |
buffer = []
|
138 |
continue
|
139 |
|
|
|
140 |
if in_agent_output and ("╰" in line or "└" in line):
|
141 |
if buffer and current_agent and current_round:
|
142 |
self._add_agent_message(current_round, current_agent, '\n'.join(buffer))
|
143 |
in_agent_output, current_agent, buffer = False, None, []
|
144 |
continue
|
145 |
|
|
|
146 |
if in_agent_output:
|
|
|
147 |
clean_line = re.sub(r'^[│|]\s*|\s*[│|]\s*$', '', line)
|
148 |
-
|
149 |
continue
|
150 |
-
|
151 |
-
if " | INFO " in line and current_round:
|
152 |
-
info_match = re.search(r'mai_dx\.main:([^:]+):.*? - (.*)', line)
|
153 |
-
if info_match:
|
154 |
-
content = info_match.group(2).strip()
|
155 |
-
if "Panel decision:" in content:
|
156 |
-
decision_match = re.search(r'Panel decision: (\w+) -> (.*)', content)
|
157 |
-
if decision_match: current_round.decision = f"{decision_match.group(1)}: {decision_match.group(2)}"
|
158 |
-
elif "Current cost:" in content:
|
159 |
-
cost_match = re.search(r'Current cost: \$(\d+(?:\.\d+)?)', content)
|
160 |
-
if cost_match: current_round.cost_incurred = float(cost_match.group(1))
|
161 |
|
162 |
-
if current_round:
|
|
|
163 |
|
164 |
def _add_agent_message(self, conversation: AgentConversation, agent_name: str, content: str):
|
165 |
message_type = "output"
|
|
|
166 |
formatted_content = content.strip()
|
167 |
|
168 |
-
|
|
|
169 |
message_type = "function_call"
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
try:
|
176 |
-
args_data = json.loads(args_match.group(1))
|
177 |
-
formatted_content += f"```json\n{json.dumps(args_data, indent=2, ensure_ascii=False)}\n```"
|
178 |
-
except json.JSONDecodeError:
|
179 |
-
formatted_content += "Помилка парсингу JSON."
|
180 |
-
else:
|
181 |
-
formatted_content += "Аргументи не знайдено."
|
182 |
-
|
183 |
message = AgentMessage(
|
184 |
datetime.now().isoformat(), agent_name, message_type, formatted_content, {'raw_content': content}
|
185 |
)
|
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
Покращений модуль для повного логування діагностичних сесій MAI-DX
|
4 |
+
з детальним захопленням розмов між агентами. (ВЕРСІЯ З ВИПРАВЛЕНИМ ПАРСЕРОМ)
|
5 |
"""
|
6 |
import os
|
7 |
import io
|
|
|
64 |
|
65 |
def write(self, text):
|
66 |
self.captured_output.write(text)
|
67 |
+
# Уникаємо подвійного виводу в консоль, якщо Gradio робить це сам
|
68 |
+
# self.original_stdout.write(text)
|
69 |
|
70 |
def flush(self):
|
71 |
self.original_stdout.flush()
|
|
|
96 |
|
97 |
def finalize_and_save_session(self, session: DiagnosisSession, result: Any, raw_output: str, duration: float) -> DiagnosisSession:
|
98 |
session.raw_output = raw_output
|
99 |
+
# Головний виклик, що парсить лог
|
100 |
self._parse_captured_output(session, raw_output)
|
101 |
|
102 |
session.diagnosis = getattr(result, 'final_diagnosis', 'N/A')
|
|
|
112 |
return session
|
113 |
|
114 |
def _parse_captured_output(self, session: DiagnosisSession, captured_text: str):
|
115 |
+
"""
|
116 |
+
FIXED: Повністю перероблений, більш надійний парсер, який не залежить
|
117 |
+
від рядка "Starting Diagnostic Loop".
|
118 |
+
"""
|
119 |
lines = captured_text.split('\n')
|
120 |
current_round: Optional[AgentConversation] = None
|
121 |
current_agent: Optional[str] = None
|
|
|
125 |
|
126 |
for line in lines:
|
127 |
stripped_line = line.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
+
# Визначаємо початок блоку агента
|
130 |
if "Agent Name" in line and ("╭" in line or "┌" in line):
|
131 |
+
# Якщо це перший агент у раунді, створюємо новий раунд
|
132 |
+
if not current_round or in_agent_output: # in_agent_output check for nested blocks
|
133 |
+
round_number += 1
|
134 |
+
if current_round:
|
135 |
+
current_round.end_time = datetime.now().isoformat()
|
136 |
+
current_round = AgentConversation(round_number=round_number, start_time=datetime.now().isoformat())
|
137 |
+
session.conversations.append(current_round)
|
138 |
+
|
139 |
+
agent_match = re.search(r'Agent Name (.*?) (?:\[|\s)', line)
|
140 |
if agent_match:
|
141 |
current_agent = agent_match.group(1).strip()
|
142 |
in_agent_output = True
|
143 |
buffer = []
|
144 |
continue
|
145 |
|
146 |
+
# Визначаємо кінець блоку агента
|
147 |
if in_agent_output and ("╰" in line or "└" in line):
|
148 |
if buffer and current_agent and current_round:
|
149 |
self._add_agent_message(current_round, current_agent, '\n'.join(buffer))
|
150 |
in_agent_output, current_agent, buffer = False, None, []
|
151 |
continue
|
152 |
|
153 |
+
# Збираємо вміст блоку
|
154 |
if in_agent_output:
|
155 |
+
# Очищуємо рядки від символів рамок
|
156 |
clean_line = re.sub(r'^[│|]\s*|\s*[│|]\s*$', '', line)
|
157 |
+
buffer.append(clean_line)
|
158 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
+
if current_round:
|
161 |
+
current_round.end_time = datetime.now().isoformat()
|
162 |
|
163 |
def _add_agent_message(self, conversation: AgentConversation, agent_name: str, content: str):
|
164 |
message_type = "output"
|
165 |
+
# Видаляємо зайві порожні рядки на початку та в кінці
|
166 |
formatted_content = content.strip()
|
167 |
|
168 |
+
# Покращуємо визначення типу повідомлення
|
169 |
+
if "Structured Output - Attempting Function Call Execution" in formatted_content:
|
170 |
message_type = "function_call"
|
171 |
+
elif "Score:" in formatted_content and "Justification:" in formatted_content:
|
172 |
+
message_type = "judgement"
|
173 |
+
elif "No tests have been proposed" in formatted_content:
|
174 |
+
message_type = "status_update"
|
175 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
message = AgentMessage(
|
177 |
datetime.now().isoformat(), agent_name, message_type, formatted_content, {'raw_content': content}
|
178 |
)
|
updated_mai_dx_interface.py
CHANGED
@@ -31,13 +31,6 @@ except ImportError as e:
|
|
31 |
MAI_DX_AVAILABLE = False
|
32 |
IMPORT_ERROR = str(e)
|
33 |
|
34 |
-
try:
|
35 |
-
import plotly.graph_objects as go
|
36 |
-
import plotly.express as px
|
37 |
-
PLOTLY_AVAILABLE = True
|
38 |
-
except ImportError:
|
39 |
-
PLOTLY_AVAILABLE = False
|
40 |
-
|
41 |
class UpdatedMAIDXInterface:
|
42 |
def __init__(self):
|
43 |
self.conversation_logger = MAIDxConversationLogger("mai_dx_logs")
|
@@ -59,8 +52,8 @@ class UpdatedMAIDXInterface:
|
|
59 |
|
60 |
def diagnose_with_full_logging(
|
61 |
self, case_name: str, patient_info: str, mode: str, budget: int, max_iterations: int,
|
62 |
-
model_name: str, expected_diagnosis: str = "",
|
63 |
-
progress=gr.Progress()
|
64 |
):
|
65 |
if not MAI_DX_AVAILABLE: return self._format_error(f"❌ MAI-DX недоступний: {IMPORT_ERROR}")
|
66 |
if not patient_info.strip(): return self._format_error("❌ Введіть інформацію про пацієнта")
|
@@ -74,7 +67,6 @@ class UpdatedMAIDXInterface:
|
|
74 |
progress(0.3, desc="🔍 Запуск діагностики...")
|
75 |
start_time = time.time()
|
76 |
|
77 |
-
raw_output = ""
|
78 |
with EnhancedOutputCapture() as capture:
|
79 |
result = orchestrator.run(patient_info, patient_info, expected_diagnosis or "Unknown")
|
80 |
raw_output = capture.get_value()
|
@@ -90,11 +82,10 @@ class UpdatedMAIDXInterface:
|
|
90 |
main_result_str = self._format_main_result(session)
|
91 |
detailed_analysis_str = self._format_detailed_analysis(session)
|
92 |
recommendations_str = self._generate_enhanced_recommendations(result, expected_diagnosis)
|
93 |
-
|
94 |
-
raw_log_str = f"📝 Сесія: {session.case_id}\n\n" + raw_output
|
95 |
structured_conv_str = self._format_structured_conversations(session.conversations)
|
96 |
|
97 |
-
return main_result_str, detailed_analysis_str, recommendations_str,
|
98 |
|
99 |
except Exception as e:
|
100 |
import traceback
|
@@ -102,39 +93,39 @@ class UpdatedMAIDXInterface:
|
|
102 |
return self._format_error(error_msg)
|
103 |
|
104 |
def _format_structured_conversations(self, conversations: List[AgentConversation]) -> str:
|
105 |
-
if not conversations: return "
|
106 |
-
output = "
|
107 |
for conv in conversations:
|
108 |
-
output += f"
|
109 |
for msg in conv.messages:
|
110 |
-
output += f"
|
111 |
-
output += f"```\n{msg.content}\n```\n"
|
112 |
return output
|
113 |
|
114 |
-
def
|
115 |
-
if not
|
|
|
|
|
116 |
agent_activity = {}
|
117 |
for conv in conversations:
|
118 |
for msg in conv.messages:
|
119 |
agent_activity[msg.agent_name] = agent_activity.get(msg.agent_name, 0) + 1
|
120 |
-
|
|
|
|
|
121 |
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
except Exception as e:
|
130 |
-
print(f"Помилка візуалізації: {e}")
|
131 |
-
return None
|
132 |
|
133 |
def _format_main_result(self, session: DiagnosisSession) -> str:
|
134 |
efficiency = ((session.budget - session.cost) / session.budget * 100) if session.budget > 0 else 0
|
135 |
confidence_emoji = "🎯" if session.confidence >= 4.0 else "👍" if session.confidence >= 3.0 else "⚠️"
|
136 |
|
137 |
-
# ПОВЕРНУТО ПОВНИЙ ФОРМАТ РЕЗУЛЬТАТІВ
|
138 |
return f"""
|
139 |
## 🏥 Результати MAI-DX Діагностики
|
140 |
### 📋 Основна інформація
|
@@ -185,16 +176,13 @@ class UpdatedMAIDXInterface:
|
|
185 |
🔴 **Цей діагноз згенеровано ШІ і НЕ замінює професійну медичну консультацію.**
|
186 |
"""
|
187 |
|
188 |
-
def _format_error(self, msg: str) -> Tuple[str, str, str,
|
189 |
-
return (msg, "", "",
|
190 |
|
191 |
def load_sample_case(self, key: str) -> Tuple[str, str, str]:
|
192 |
case = self.sample_cases.get(key, {})
|
193 |
return case.get("info", ""), key, case.get("expected", "")
|
194 |
|
195 |
-
def get_session_details(self, case_id: str):
|
196 |
-
return f"Аналіз сесії {case_id} ще не реалізовано."
|
197 |
-
|
198 |
def create_updated_gradio_interface():
|
199 |
interface = UpdatedMAIDXInterface()
|
200 |
with gr.Blocks(title="🏥 MAI-DX Enhanced Platform", theme=gr.themes.Soft(primary_hue="blue")) as demo:
|
@@ -210,13 +198,10 @@ def create_updated_gradio_interface():
|
|
210 |
expected_diagnosis = gr.Textbox(label="🎯 Очікуваний діагноз (англ.)", lines=2)
|
211 |
with gr.Column(scale=1):
|
212 |
gr.Markdown("### ⚙️ Налаштування")
|
213 |
-
# ПОВЕРНУТО ПОВНИЙ СПИСОК РЕЖИМІВ
|
214 |
mode = gr.Radio(["instant", "question_only", "budgeted", "no_budget", "ensemble"], label="🔧 Режим", value="budgeted")
|
215 |
budget = gr.Slider(500, 10000, 3000, step=500, label="💵 Бюджет ($)")
|
216 |
max_iterations = gr.Slider(1, 15, 8, step=1, label="🔄 Макс. ітерацій")
|
217 |
-
# ПОВЕРНУТО ПОВНИЙ СПИСОК МОДЕЛЕЙ
|
218 |
model_name = gr.Dropdown(["gemini/gemini-2.5-flash", "gpt-4o", "claude-3-5-sonnet", "gpt-4", "gpt-4-turbo"], label="🤖 LLM Модель", value="gemini/gemini-2.5-flash")
|
219 |
-
enable_logging = gr.Checkbox(label="📝 Повне логування розмов", value=True)
|
220 |
diagnose_btn = gr.Button("🚀 Запустити діагностику", variant="primary", size="lg")
|
221 |
|
222 |
sample_selector.change(interface.load_sample_case, inputs=sample_selector, outputs=[patient_info, case_name, expected_diagnosis])
|
@@ -229,27 +214,26 @@ def create_updated_gradio_interface():
|
|
229 |
with gr.Column(scale=1):
|
230 |
recommendations = gr.Markdown()
|
231 |
|
232 |
-
|
233 |
-
with gr.Row():
|
234 |
-
metrics_plot = gr.Plot(label="📈 Метрики процесу")
|
235 |
-
agent_activity_plot = gr.Plot(label="🤖 Активність агентів")
|
236 |
-
|
237 |
with gr.Row():
|
238 |
-
|
239 |
-
|
|
|
|
|
240 |
|
241 |
diagnose_btn.click(
|
242 |
interface.diagnose_with_full_logging,
|
243 |
-
inputs=[case_name, patient_info, mode, budget, max_iterations, model_name, expected_diagnosis
|
244 |
-
outputs=[main_result, detailed_analysis, recommendations,
|
|
|
|
|
245 |
)
|
246 |
|
247 |
with gr.Tab("📊 Аналіз логів"):
|
248 |
gr.Markdown("### 🔍 Аналіз збережених діагностичних сесій")
|
249 |
-
# ... (код для аналізу логів) ...
|
250 |
|
251 |
return demo
|
252 |
|
253 |
if __name__ == "__main__":
|
254 |
demo = create_updated_gradio_interface()
|
255 |
-
demo.launch(server_name="0.0.0.0", server_port=7860, share=
|
|
|
31 |
MAI_DX_AVAILABLE = False
|
32 |
IMPORT_ERROR = str(e)
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
class UpdatedMAIDXInterface:
|
35 |
def __init__(self):
|
36 |
self.conversation_logger = MAIDxConversationLogger("mai_dx_logs")
|
|
|
52 |
|
53 |
def diagnose_with_full_logging(
|
54 |
self, case_name: str, patient_info: str, mode: str, budget: int, max_iterations: int,
|
55 |
+
model_name: str, expected_diagnosis: str = "",
|
56 |
+
progress=gr.Progress(track_tqdm=True) # Додаємо track_tqdm для кращої інтеграції
|
57 |
):
|
58 |
if not MAI_DX_AVAILABLE: return self._format_error(f"❌ MAI-DX недоступний: {IMPORT_ERROR}")
|
59 |
if not patient_info.strip(): return self._format_error("❌ Введіть інформацію про пацієнта")
|
|
|
67 |
progress(0.3, desc="🔍 Запуск діагностики...")
|
68 |
start_time = time.time()
|
69 |
|
|
|
70 |
with EnhancedOutputCapture() as capture:
|
71 |
result = orchestrator.run(patient_info, patient_info, expected_diagnosis or "Unknown")
|
72 |
raw_output = capture.get_value()
|
|
|
82 |
main_result_str = self._format_main_result(session)
|
83 |
detailed_analysis_str = self._format_detailed_analysis(session)
|
84 |
recommendations_str = self._generate_enhanced_recommendations(result, expected_diagnosis)
|
85 |
+
agent_report_str = self._create_agent_activity_report(session.conversations)
|
|
|
86 |
structured_conv_str = self._format_structured_conversations(session.conversations)
|
87 |
|
88 |
+
return main_result_str, detailed_analysis_str, recommendations_str, agent_report_str, structured_conv_str
|
89 |
|
90 |
except Exception as e:
|
91 |
import traceback
|
|
|
93 |
return self._format_error(error_msg)
|
94 |
|
95 |
def _format_structured_conversations(self, conversations: List[AgentConversation]) -> str:
|
96 |
+
if not conversations: return "### 🗣️ Розмови агентів\n\n*Розмови не знайдено в логах. Можливо, діагноз було поставлено миттєво.*"
|
97 |
+
output = "### 🗣️ Розмови агентів\n\n"
|
98 |
for conv in conversations:
|
99 |
+
output += f"#### 🔄 Раунд {conv.round_number}\n"
|
100 |
for msg in conv.messages:
|
101 |
+
output += f"<details><summary><strong>{msg.agent_name}</strong> <code>[{msg.message_type}]</code></summary>\n\n"
|
102 |
+
output += f"```\n{msg.content.strip()}\n```\n\n</details>\n"
|
103 |
return output
|
104 |
|
105 |
+
def _create_agent_activity_report(self, conversations: List[AgentConversation]) -> str:
|
106 |
+
if not conversations:
|
107 |
+
return "### 🤖 Активність агентів\n\n*Дані відсутні.*"
|
108 |
+
|
109 |
agent_activity = {}
|
110 |
for conv in conversations:
|
111 |
for msg in conv.messages:
|
112 |
agent_activity[msg.agent_name] = agent_activity.get(msg.agent_name, 0) + 1
|
113 |
+
|
114 |
+
if not agent_activity:
|
115 |
+
return "### 🤖 Активність агентів\n\n*Повідомлення від агентів не знайдено.*"
|
116 |
|
117 |
+
report_md = "### 🤖 Активність агентів\n\n"
|
118 |
+
sorted_activity = sorted(agent_activity.items(), key=lambda item: item[1], reverse=True)
|
119 |
+
|
120 |
+
for agent, count in sorted_activity:
|
121 |
+
report_md += f"- **{agent}**: {count} повідомлень\n"
|
122 |
+
|
123 |
+
return report_md
|
|
|
|
|
|
|
124 |
|
125 |
def _format_main_result(self, session: DiagnosisSession) -> str:
|
126 |
efficiency = ((session.budget - session.cost) / session.budget * 100) if session.budget > 0 else 0
|
127 |
confidence_emoji = "🎯" if session.confidence >= 4.0 else "👍" if session.confidence >= 3.0 else "⚠️"
|
128 |
|
|
|
129 |
return f"""
|
130 |
## 🏥 Результати MAI-DX Діагностики
|
131 |
### 📋 Основна інформація
|
|
|
176 |
🔴 **Цей діагноз згенеровано ШІ і НЕ замінює професійну медичну консультацію.**
|
177 |
"""
|
178 |
|
179 |
+
def _format_error(self, msg: str) -> Tuple[str, str, str, str, str]:
|
180 |
+
return (msg, "", "", "", "")
|
181 |
|
182 |
def load_sample_case(self, key: str) -> Tuple[str, str, str]:
|
183 |
case = self.sample_cases.get(key, {})
|
184 |
return case.get("info", ""), key, case.get("expected", "")
|
185 |
|
|
|
|
|
|
|
186 |
def create_updated_gradio_interface():
|
187 |
interface = UpdatedMAIDXInterface()
|
188 |
with gr.Blocks(title="🏥 MAI-DX Enhanced Platform", theme=gr.themes.Soft(primary_hue="blue")) as demo:
|
|
|
198 |
expected_diagnosis = gr.Textbox(label="🎯 Очікуваний діагноз (англ.)", lines=2)
|
199 |
with gr.Column(scale=1):
|
200 |
gr.Markdown("### ⚙️ Налаштування")
|
|
|
201 |
mode = gr.Radio(["instant", "question_only", "budgeted", "no_budget", "ensemble"], label="🔧 Режим", value="budgeted")
|
202 |
budget = gr.Slider(500, 10000, 3000, step=500, label="💵 Бюджет ($)")
|
203 |
max_iterations = gr.Slider(1, 15, 8, step=1, label="🔄 Макс. ітерацій")
|
|
|
204 |
model_name = gr.Dropdown(["gemini/gemini-2.5-flash", "gpt-4o", "claude-3-5-sonnet", "gpt-4", "gpt-4-turbo"], label="🤖 LLM Модель", value="gemini/gemini-2.5-flash")
|
|
|
205 |
diagnose_btn = gr.Button("🚀 Запустити діагностику", variant="primary", size="lg")
|
206 |
|
207 |
sample_selector.change(interface.load_sample_case, inputs=sample_selector, outputs=[patient_info, case_name, expected_diagnosis])
|
|
|
214 |
with gr.Column(scale=1):
|
215 |
recommendations = gr.Markdown()
|
216 |
|
217 |
+
gr.Markdown("---")
|
|
|
|
|
|
|
|
|
218 |
with gr.Row():
|
219 |
+
with gr.Column(scale=1):
|
220 |
+
agent_activity_report = gr.Markdown(label="🤖 Активність агентів")
|
221 |
+
with gr.Column(scale=2):
|
222 |
+
structured_conversations = gr.Markdown(label="🗣️ Структуровані розмови")
|
223 |
|
224 |
diagnose_btn.click(
|
225 |
interface.diagnose_with_full_logging,
|
226 |
+
inputs=[case_name, patient_info, mode, budget, max_iterations, model_name, expected_diagnosis],
|
227 |
+
outputs=[main_result, detailed_analysis, recommendations, agent_activity_report, structured_conversations],
|
228 |
+
# FIX: Додаємо параметр для відображення прогрес-бару
|
229 |
+
show_progress="full"
|
230 |
)
|
231 |
|
232 |
with gr.Tab("📊 Аналіз логів"):
|
233 |
gr.Markdown("### 🔍 Аналіз збережених діагностичних сесій")
|
|
|
234 |
|
235 |
return demo
|
236 |
|
237 |
if __name__ == "__main__":
|
238 |
demo = create_updated_gradio_interface()
|
239 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
|