#!/usr/bin/env python3
"""
Оновлений MAI-DX Gradio Interface з повним логуванням розмов агентів
(ВЕРСІЯ З ВИПРАВЛЕНИМ СТАТУС-БАРОМ І СТРУКТУРОЮ)
"""
import os
import sys
import json
import time
import uuid
import pandas as pd
import gradio as gr
from datetime import datetime
from typing import Dict, List, Tuple, Optional, Any
from dataclasses import dataclass, asdict
import warnings
# Налаштування середовища
os.environ.update({
"SWARMS_VERBOSITY": "ERROR", "RICH_TRACEBACK": "0",
"SWARMS_SHOW_PANEL": "true", "SWARMS_AUTO_PRINT": "true"
})
warnings.filterwarnings("ignore")
from dotenv import load_dotenv
load_dotenv()
try:
from mai_dx_wrapper import SafeMaiDxOrchestrator as MaiDxOrchestrator, MAI_DX_AVAILABLE
from enhanced_mai_dx_logger import MAIDxConversationLogger, DiagnosisSession, AgentConversation, EnhancedOutputCapture
except ImportError as e:
MAI_DX_AVAILABLE = False
IMPORT_ERROR = str(e)
class UpdatedMAIDXInterface:
"""
Клас, що інкапсулює логіку та побудову Gradio інтерфейсу.
Це запобігає дублюванню обробників подій.
"""
def __init__(self):
self.conversation_logger = MAIDxConversationLogger("mai_dx_logs")
self.sessions_history = []
self.sample_cases = {
"🫀 Кардіологічний (Гострий MI)": {
"info": "Пацієнт: 58-річний чоловік, менеджер, гіпертонія в анамнезі\nСкарги: Гострий роздираючий біль у грудях 3 години, іррадіація в ліву руку\nОгляд: Блідий, пітливий, АТ 160/90, ЧСС 95\nЕКГ: ST-підйоми у відведеннях II, III, aVF (нижня стінка)\nТропонін I: 8.5 нг/мл (норма <0.04)\nАнамнез: Куріння 30 років, дислипідемія, сімейний анамнез ІХС",
"expected": "Acute inferior wall myocardial infarction (STEMI)"
},
"🧠 Неврологічний (Гострий інсульт)": {
"info": "Пацієнтка: 67-річна жінка, раптові неврологічні симптоми\nПрезентація: Раптова слабкість правої сторони 2 години тому\nОгляд: Свідома, дезорієнтована у часі, правостороннє опущення обличчя\nНеврологія: Правостороння геміплегія, афазія, девіація очей вліво\nКТ голови: Гострого крововиливу немає, рання ішемія у лівій МСА\nNIHSS: 15 балів",
"expected": "Acute ischemic stroke in the left middle cerebral artery territory"
},
"🦠 Інфекційний (Сепсис)": {
"info": "Пацієнт: 45-річний чоловік з прогресуючою лихоманкою\nСкарги: Висока температура 39.5°C, озноб, загальна слабкість 3 дні\nОгляд: Гарячий, тахікардія 120/хв, гіпотензія 85/50\nЛабораторно: Лейкоцити 18000, С-реактивний білок 180, прокальцитонін 5.2\nПосів крові: Pending, lactate 4.2 ммоль/л\nАнамнез: Нещодавня стоматологічна процедура",
"expected": "Sepsis with a possible odontogenic source"
}
}
# Створюємо інтерфейс один раз при ініціалізації
self.demo = self.build_interface()
def diagnose_with_full_logging(
self, case_name: str, patient_info: str, mode: str, budget: int, max_iterations: int,
model_name: str, expected_diagnosis: str = "",
progress=gr.Progress(track_tqdm=True)
):
if not MAI_DX_AVAILABLE: return self._format_error(f"❌ MAI-DX недоступний: {IMPORT_ERROR}")
if not patient_info.strip(): return self._format_error("❌ Введіть інформацію про пацієнта")
session = self.conversation_logger.create_session(case_name, patient_info, mode, budget)
try:
progress(0.2, desc="🤖 Створення AI-панелі...")
orchestrator = MaiDxOrchestrator(model_name, max_iterations, budget, mode)
progress(0.3, desc="🔍 Запуск діагностики...")
start_time = time.time()
with EnhancedOutputCapture() as capture:
result = orchestrator.run(patient_info, patient_info, expected_diagnosis or "Unknown")
raw_output = capture.get_value()
duration = time.time() - start_time
progress(0.8, desc="📊 Обробка результатів...")
session = self.conversation_logger.finalize_and_save_session(session, result, raw_output, duration)
self.sessions_history.append(session)
progress(1.0, desc="✅ Готово!")
main_result_str = self._format_main_result(session)
detailed_analysis_str = self._format_detailed_analysis(session)
recommendations_str = self._generate_enhanced_recommendations(result, expected_diagnosis)
agent_report_str = self._create_agent_activity_report(session.conversations)
structured_conv_str = self._format_structured_conversations(session.conversations)
return main_result_str, detailed_analysis_str, recommendations_str, agent_report_str, structured_conv_str
except Exception as e:
import traceback
error_msg = f"❌ Критична помилка: {traceback.format_exc()}"
return self._format_error(error_msg)
def _format_structured_conversations(self, conversations: List[AgentConversation]) -> str:
if not conversations: return "### 🗣️ Розмови агентів\n\n*Розмови не знайдено в логах. Можливо, діагноз було поставлено миттєво.*"
output = "### 🗣️ Розмови агентів\n\n"
for conv in conversations:
output += f"#### 🔄 Раунд {conv.round_number}\n"
for msg in conv.messages:
output += f"{msg.agent_name}
\n\n"
output += f"```\n{msg.content.strip()}\n```\n\n[{msg.message_type}]