GUI_MAI-DxO / lmai_dx_interface_log.py
DocUA's picture
Оновлено очікувані результати в логіці діагностики на англійську мову, виправлено код для створення сесії, оновлено режим діагностики в інтерфейсі Gradio, а також змінено файл програми в документації на lmai_dx_interface_log.py.
0871c81
raw
history blame
43.8 kB
#!/usr/bin/env python3
"""
Виправлений MAI-DX Gradio Interface з сумісністю для нових версій Gradio
"""
import os
import sys
import json
import time
import pandas as pd
import gradio as gr
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass, asdict
import warnings
import threading
import queue
import io
from contextlib import redirect_stdout, redirect_stderr
# Налаштування середовища
os.environ.update({
"SWARMS_VERBOSITY": "ERROR",
"RICH_TRACEBACK": "0",
"SWARMS_SHOW_PANEL": "false",
"SWARMS_AUTO_PRINT": "false"
})
warnings.filterwarnings("ignore")
from dotenv import load_dotenv
load_dotenv()
# Патч Rich formatter
def patch_rich_formatter():
try:
import swarms.utils.formatter
def dummy_print_panel(*args, **kwargs):
pass
if hasattr(swarms.utils.formatter, 'Formatter'):
swarms.utils.formatter.Formatter._print_panel = dummy_print_panel
return True
except:
return False
patch_rich_formatter()
# Імпорт MAI-DX
try:
from mai_dx import MaiDxOrchestrator
MAI_DX_AVAILABLE = True
except ImportError as e:
MAI_DX_AVAILABLE = False
IMPORT_ERROR = str(e)
# Перевірка доступності Plotly
try:
import plotly.graph_objects as go
import plotly.express as px
PLOTLY_AVAILABLE = True
except ImportError:
PLOTLY_AVAILABLE = False
print("⚠️ Plotly не встановлено, візуалізації будуть недоступні")
# Імпорт логгера (створюємо заглушку якщо немає)
try:
from agent_conversation_logger import AgentConversationLogger, DiagnosisSession
LOGGER_AVAILABLE = True
except ImportError:
LOGGER_AVAILABLE = False
@dataclass
class DiagnosisSession:
timestamp: str
case_name: str
patient_info: str
mode: str
budget: int
diagnosis: str
confidence: float
cost: float
iterations: int
duration: float
status: str
reasoning: str
class AgentConversationLogger:
def __init__(self, *args, **kwargs):
self.conversations = []
def start_conversation(self, *args):
return f"mock_{len(self.conversations)}"
def log_agent_message(self, *args, **kwargs):
pass
def end_conversation(self, *args):
return f"saved_{len(self.conversations)}"
def list_conversations(self):
return self.conversations
def get_conversation_summary(self):
return {"total_conversations": 0, "average_accuracy": 0, "average_cost": 0, "mode_distribution": {}}
def export_conversation_report(self, case_id, format):
return f"report_{case_id}.{format}"
def export_analytics_csv(self):
return "analytics.csv"
class RealTimeMetrics:
"""Метрики в реальному часі"""
def __init__(self):
self.reset()
def reset(self):
self.start_time = time.time()
self.agents_activity = {
'Dr. Hypothesis': 0,
'Dr. Test-Chooser': 0,
'Dr. Challenger': 0,
'Dr. Stewardship': 0,
'Dr. Checklist': 0,
'Consensus Coordinator': 0,
'Gatekeeper': 0,
'Judge': 0
}
self.cost_progression = []
self.confidence_progression = []
self.decision_timeline = []
def update_agent_activity(self, agent_name: str):
if agent_name in self.agents_activity:
self.agents_activity[agent_name] += 1
def add_cost_point(self, cost: float):
self.cost_progression.append({
'time': time.time() - self.start_time,
'cost': cost
})
def add_confidence_point(self, confidence: float):
self.confidence_progression.append({
'time': time.time() - self.start_time,
'confidence': confidence
})
class EnhancedMAIDXInterface:
"""Покращений інтерфейс з сумісністю для Gradio"""
def __init__(self):
self.sessions_history = []
self.conversation_logger = AgentConversationLogger("mai_dx_logs")
self.current_metrics = RealTimeMetrics()
# Розширені тестові кейси
self.sample_cases = {
"🫀 Кардіологічний (Гострий MI)": {
"info": """Пацієнт: 58-річний чоловік, менеджер, гіпертонія в анамнезі
Скарги: Гострий роздираючий біль у грудях 3 години, іррадіація в ліву руку
Огляд: Блідий, пітливий, АТ 160/90, ЧСС 95
ЕКГ: ST-підйоми у відведеннях II, III, aVF (нижня стінка)
Тропонін I: 8.5 нг/мл (норма <0.04)
Анамнез: Куріння 30 років, дислипідемія, сімейний анамнез ІХС""",
"expected": "Acute inferior myocardial infarction (STEMI)"
},
"🧠 Неврологічний (Гострий інсульт)": {
"info": """Пацієнтка: 67-річна жінка, раптові неврологічні симптоми
Презентація: Раптова слабкість правої сторони 2 години тому
Огляд: Свідома, дезорієнтована у часі, правостороннє опущення обличчя
Неврологія: Правостороння геміплегія, афазія, девіація очей вліво
КТ голови: Гострого крововиливу немає, рання ішемія у лівій МСА
NIHSS: 15 балів""",
"expected": "Acute ischemic stroke in the left middle cerebral artery basin"
},
"🦠 Інфекційний (Сепсис)": {
"info": """Пацієнт: 45-річний чоловік з прогресуючою лихоманкою
Скарги: Висока температура 39.5°C, озноб, загальна слабкість 3 дні
Огляд: Гарячий, тахікардія 120/хв, гіпотензія 85/50
Лабораторно: Лейкоцити 18000, С-реактивний білок 180, прокальцитонін 5.2
Посів крові: Pending, lactate 4.2 ммоль/л
Анамнез: Нещодавна стоматологічна процедура""",
"expected": "Sepsis with a possible odontogenic source"
}
}
def diagnose_with_enhanced_tracking(
self,
case_name: str,
patient_info: str,
mode: str,
budget: int,
max_iterations: int,
model_name: str,
expected_diagnosis: str = "",
enable_logging: bool = True,
progress=gr.Progress()
) -> Tuple[str, str, str, Optional[object], Optional[object], str]:
"""Діагностика з покращеним відстеженням - ВИПРАВЛЕНА ВЕРСІЯ"""
if not MAI_DX_AVAILABLE:
return self._format_error(f"❌ MAI-DX недоступний: {IMPORT_ERROR}")
if not patient_info.strip():
return self._format_error("❌ Введіть інформацію про пацієнта")
# Скидання метрик
self.current_metrics.reset()
conversation_log = ""
case_id = None
try:
progress(0.1, desc="🚀 Ініціалізація системи...")
# Логування початку
if enable_logging:
case_id = self.conversation_logger.start_conversation(
case_name or f"Case_{datetime.now().strftime('%H%M%S')}",
patient_info,
mode
)
conversation_log += f"📝 Розпочато логування: {case_id}\n\n"
progress(0.2, desc="🤖 Створення AI-панелі лікарів...")
# Створення оркестратора
orchestrator = MaiDxOrchestrator(
model_name=model_name,
max_iterations=max_iterations,
initial_budget=budget,
mode=mode if mode != "ensemble" else "budgeted"
)
progress(0.3, desc="🔍 Запуск діагностичного процесу...")
start_time = time.time()
# Симуляція прогресу з реальними етапами
diagnostic_stages = [
"🧠 Dr. Hypothesis аналізує симптоми...",
"🔬 Dr. Test-Chooser обирає тести...",
"🤔 Dr. Challenger перевіряє гіпотези...",
"💰 Dr. Stewardship оцінює вартість...",
"✅ Dr. Checklist контролює якість...",
"🤝 Consensus Coordinator формує рішення..."
]
for i, stage in enumerate(diagnostic_stages):
progress(0.3 + (i * 0.1), desc=stage)
time.sleep(0.3) # Короткша затримка
progress(0.8, desc="🎯 Формування діагнозу...")
# Запуск діагностики з перехопленням виводу
with io.StringIO() as captured_output:
try:
original_stdout = sys.stdout
sys.stdout = captured_output
if mode == "ensemble":
try:
result = orchestrator.run_ensemble(
initial_case_info=patient_info,
full_case_details=patient_info,
ground_truth_diagnosis=expected_diagnosis or "Unknown",
num_runs=2
)
except AttributeError:
result = orchestrator.run(
initial_case_info=patient_info,
full_case_details=patient_info,
ground_truth_diagnosis=expected_diagnosis or "Unknown"
)
else:
result = orchestrator.run(
initial_case_info=patient_info,
full_case_details=patient_info,
ground_truth_diagnosis=expected_diagnosis or "Unknown"
)
finally:
sys.stdout = original_stdout
captured_text = captured_output.getvalue()
duration = time.time() - start_time
progress(0.9, desc="📊 Обробка результатів...")
# Парсинг логів
if enable_logging and captured_text:
conversation_log += "🤖 Захоплені логи агентів:\n"
conversation_log += "=" * 60 + "\n"
conversation_log += captured_text + "\n"
conversation_log += "=" * 60 + "\n\n"
# Оновлення метрик
self._parse_logs_for_metrics(captured_text)
# Логування результату
if enable_logging:
self.conversation_logger.log_agent_message(
"Judge",
"final_evaluation",
result.final_diagnosis,
getattr(result, 'accuracy_reasoning', 'Фінальна оцінка'),
result.accuracy_score / 5.0,
result.total_cost,
max_iterations
)
saved_case_id = self.conversation_logger.end_conversation(
result.final_diagnosis,
result.accuracy_score,
result.total_cost
)
conversation_log += f"💾 Збережено як: {saved_case_id}\n"
# Створення сесії
# Виправлений код
session = DiagnosisSession(
case_id=case_id, # <--- ДОДАЙТЕ ЦЕЙ РЯДОК
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
case_name=case_name or f"Case_{len(self.sessions_history) + 1}",
patient_info=patient_info[:200] + "..." if len(patient_info) > 200 else patient_info,
mode=mode,
budget=budget,
diagnosis=result.final_diagnosis,
confidence=result.accuracy_score,
cost=result.total_cost,
iterations=getattr(result, 'iterations', max_iterations),
duration=duration,
status="✅ Успішно" if result.accuracy_score >= 3.0 else "⚠️ Потребує перегляду",
reasoning=getattr(result, 'accuracy_reasoning', 'Недоступно')[:300] + "..."
)
self.sessions_history.append(session)
progress(1.0, desc="✅ Готово!")
# Генерація візуалізацій (безпечно)
metrics_plot = self._create_metrics_visualization_safe()
agent_plot = self._create_agent_activity_chart_safe()
# Генерація всіх результатів
return (
self._format_main_result(session, result),
self._format_detailed_analysis(session, result),
self._generate_enhanced_recommendations(result, expected_diagnosis),
metrics_plot,
agent_plot,
conversation_log
)
except Exception as e:
error_msg = f"❌ Помилка діагностики: {str(e)}"
if case_id:
error_msg += f"\n🗂️ Case ID: {case_id}"
return self._format_error(error_msg)
def _create_metrics_visualization_safe(self):
"""Безпечне створення візуалізації метрик"""
try:
if not PLOTLY_AVAILABLE:
return None
if not self.current_metrics.cost_progression:
# Створюємо демо-графік
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[0, 1, 2, 3],
y=[0, 300, 600, 900],
mode='lines+markers',
name='Демо-дані',
line=dict(color='#1f77b4', width=3)
))
fig.update_layout(
title='📈 Прогресія вартості (демо)',
xaxis_title='Час (секунди)',
yaxis_title='Вартість ($)',
template='plotly_white',
height=400
)
return fig
# Реальні дані
times = [point['time'] for point in self.current_metrics.cost_progression]
costs = [point['cost'] for point in self.current_metrics.cost_progression]
fig = go.Figure()
fig.add_trace(go.Scatter(
x=times,
y=costs,
mode='lines+markers',
name='Накопичена вартість',
line=dict(color='#1f77b4', width=3)
))
fig.update_layout(
title='📈 Прогресія вартості діагностики',
xaxis_title='Час (секунди)',
yaxis_title='Вартість ($)',
template='plotly_white',
height=400
)
return fig
except Exception as e:
print(f"Помилка візуалізації метрик: {e}")
return None
def _create_agent_activity_chart_safe(self):
"""Безпечне створення діаграми активності агентів"""
try:
if not PLOTLY_AVAILABLE:
return None
# Підготовка даних
agents = list(self.current_metrics.agents_activity.keys())
activities = list(self.current_metrics.agents_activity.values())
# Якщо немає активності, створюємо демо
if all(activity == 0 for activity in activities):
activities = [1, 2, 1, 1, 1, 2, 3, 1] # Демо-дані
# Кольори для агентів
colors = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4',
'#FECA57', '#FF9FF3', '#54A0FF', '#5F27CD'
]
fig = go.Figure(data=[
go.Bar(
x=agents,
y=activities,
marker_color=colors[:len(agents)],
text=activities,
textposition='auto'
)
])
fig.update_layout(
title='🤖 Активність ШІ-агентів лікарів',
xaxis_title='Агенти',
yaxis_title='Кількість взаємодій',
template='plotly_white',
height=400,
showlegend=False
)
fig.update_xaxes(tickangle=45)
return fig
except Exception as e:
print(f"Помилка графіку агентів: {e}")
return None
def _parse_logs_for_metrics(self, captured_text: str):
"""Парсинг логів для оновлення метрик"""
lines = captured_text.split('\n')
for line in lines:
line = line.strip()
if not line:
continue
# Пошук активності агентів
for agent in self.current_metrics.agents_activity.keys():
if agent.lower().replace(" ", "").replace(".", "") in line.lower():
self.current_metrics.update_agent_activity(agent)
break
# Пошук вартості
import re
cost_match = re.search(r'\$(\d+(?:\.\d+)?)', line)
if cost_match:
self.current_metrics.add_cost_point(float(cost_match.group(1)))
def _format_main_result(self, session, result):
"""Форматування основного результату"""
confidence_emoji = "🎯" if session.confidence >= 4.0 else "👍" if session.confidence >= 3.0 else "⚠️"
efficiency = ((session.budget - session.cost) / session.budget * 100)
return f"""
## 🏥 Результати MAI-DX Діагностики
### 📋 Основна інформація
- **🗂️ Випадок**: {session.case_name}
- **⏰ Час**: {session.timestamp}
- **🔧 Режим**: {session.mode}
- **🤖 Модель**: AI Multi-Agent
### {confidence_emoji} Діагностичний висновок
**{session.diagnosis}**
### 📊 Показники якості
- **Точність**: {session.confidence:.1f}/5.0 ⭐
- **Статус**: {session.status}
- **Ітерації**: {session.iterations} циклів
### 💰 Економічні показники
- **Витрачено**: ${session.cost:,.2f}
- **Бюджет**: ${session.budget:,}
- **Ефективність**: {efficiency:.1f}% бюджету збережено
- **Швидкість**: {session.duration:.1f} секунд
### 🎖️ Загальна оцінка
{self._get_overall_rating(session)}
"""
def _get_overall_rating(self, session):
"""Загальна оцінка ефективності"""
efficiency = ((session.budget - session.cost) / session.budget * 100)
if session.confidence >= 4.0 and efficiency >= 50:
return "🏆 **ВІДМІННО** - Високоточний та економічний діагноз"
elif session.confidence >= 3.0 and efficiency >= 30:
return "🥈 **ДОБРЕ** - Надійний діагноз з прийнятною вартістю"
elif session.confidence >= 2.0:
return "🥉 **ЗАДОВІЛЬНО** - Потребує додаткової верифікації"
else:
return "❌ **ПОТРЕБУЄ ПЕРЕГЛЯДУ** - Низька впевненість"
def _format_detailed_analysis(self, session, result):
"""Детальний аналіз"""
return f"""
## 🔬 Детальний клінічний аналіз
### 💭 Медичне обґрунтування
{session.reasoning}
### 📈 Аналіз ефективності
- **⚡ Швидкість діагностики**: {session.duration:.1f} сек
- **💸 Економічна ефективність**: {((session.budget - session.cost) / session.budget * 100):.1f}%
- **🔄 Ітеративна конвергенція**: {session.iterations} циклів
- **🎯 Клінічна точність**: {(session.confidence / 5.0 * 100):.1f}%
### 🤖 Процес прийняття рішень
Система MAI-DX використала **{session.iterations} ітерацій** для досягнення консенсусу між **8 ШІ-агентами лікарів**.
### 📊 Порівняння з бенчмарками
- **Людські лікарі**: ~20% точність на NEJM CPC
- **GPT-4**: ~49% точність
- **MAI-DX**: ~85.5% точність ✨
"""
def _generate_enhanced_recommendations(self, result, expected_diagnosis):
"""Покращені рекомендації"""
comparison = ""
if expected_diagnosis:
comparison = f"""
### 🎯 Порівняння з очікуваним діагнозом
**Очікувався**: {expected_diagnosis}
**Отримано**: {result.final_diagnosis}
**Збіг**: {'✅ Так' if expected_diagnosis.lower() in result.final_diagnosis.lower() else '❌ Ні'}
"""
return f"""
## 💡 Клінічні рекомендації
### 🏥 Негайні дії
- 🔍 **Верифікація діагнозу** з лікарем-спеціалістом
- 📋 **Додаткові дослідження** при необхідності
- 👨‍⚕️ **Консультація експерта** для підтвердження
### 🔬 Дослідницький потенціал
- **📊 Аналіз логів**: Вивчіть деталі роботи агентів
- **📈 Валідація**: Перевірте на додаткових випадках
- **🤖 Тюнінг моделі**: Оптимізуйте параметри
{comparison}
### ⚠️ Важливе застереження
🔴 **Цей діагноз згенеровано ШІ для дослідницьких цілей та НЕ замінює професійну медичну консультацію.**
"""
def _format_error(self, error_msg):
"""Форматування помилки"""
return (error_msg, "", "", None, None, "")
def load_sample_case(self, sample_key):
"""Завантаження зразкового випадку"""
if sample_key and sample_key in self.sample_cases:
case_data = self.sample_cases[sample_key]
return (
case_data["info"],
sample_key,
case_data["expected"]
)
return "", "", ""
def get_enhanced_analytics(self):
"""Розширена аналітика - ВИПРАВЛЕНА ВЕРСІЯ"""
try:
conversations = self.conversation_logger.list_conversations()
if not conversations:
empty_df = pd.DataFrame()
return empty_df, "📊 Немає даних для аналізу", []
# Створення DataFrame
df = pd.DataFrame(conversations)
# Статистика
total_cases = len(conversations)
avg_accuracy = df['accuracy'].mean() if 'accuracy' in df.columns else 0
avg_cost = df['cost'].mean() if 'cost' in df.columns else 0
summary = f"""
## 📊 Розширена аналітика MAI-DX
### 🎯 Загальна статистика
- **Всього випадків**: {total_cases}
- **Середня точність**: {avg_accuracy:.2f}/5.0 ⭐
- **Середня вартість**: ${avg_cost:,.2f}
- **Загальна економія**: ${(3000 - avg_cost) * total_cases:,.2f}
"""
# Створення списку для dropdown
case_choices = []
if not df.empty and 'case_name' in df.columns:
case_choices = [(f"{row['case_name']} ({row.get('case_id', 'N/A')})",
row.get('case_id', f"case_{i}"))
for i, (_, row) in enumerate(df.iterrows())]
return df, summary, case_choices
except Exception as e:
return pd.DataFrame(), f"❌ Помилка аналітики: {e}", []
def create_enhanced_gradio_interface():
"""Створення виправленого Gradio інтерфейсу"""
interface = EnhancedMAIDXInterface()
# Сучасний CSS
custom_css = """
.gradio-container {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
}
.main-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 2rem;
border-radius: 15px;
margin-bottom: 2rem;
text-align: center;
}
.conversation-log {
font-family: 'Fira Code', monospace;
background: #2d3748;
color: #e2e8f0;
border-radius: 8px;
padding: 1rem;
max-height: 500px;
overflow-y: auto;
white-space: pre-wrap;
}
"""
with gr.Blocks(
title="🏥 MAI-DX Enhanced Research Platform",
theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="purple",
neutral_hue="slate"
),
css=custom_css
) as demo:
# Заголовок
gr.HTML("""
<div class="main-header">
<h1>🏥 MAI-DX Enhanced Research Platform</h1>
<p>🤖 Платформа для дослідження ШІ-діагностики з детальним логуванням взаємодії агентів</p>
<p>📊 Базується на дослідженні Microsoft Research "Sequential Diagnosis with Language Models"</p>
</div>
""")
with gr.Tabs() as tabs:
# Основна вкладка діагностики
with gr.Tab("🩺 Діагностика з ШІ-агентами", elem_id="diagnosis-tab"):
with gr.Row():
# Ліва колонка - введення даних
with gr.Column(scale=1):
gr.Markdown("### 📝 Клінічний випадок")
case_name = gr.Textbox(
label="🏷️ Назва випадку",
placeholder="Наприклад: Кардіологічний випадок №1",
lines=1
)
sample_selector = gr.Dropdown(
choices=list(interface.sample_cases.keys()),
label="🎯 Готові тестові випадки",
value=None,
interactive=True
)
patient_info = gr.Textbox(
label="👤 Детальна інформація про пацієнта",
lines=12,
placeholder="Введіть повний опис клінічного випадку:\n- Демографія пацієнта\n- Скарги та анамнез\n- Фізикальне обстеження\n- Лабораторні дані\n- Інструментальні дослідження",
interactive=True
)
expected_diagnosis = gr.Textbox(
label="🎯 Очікуваний діагноз (для порівняння)",
placeholder="Опціонально: введіть правильний діагноз для оцінки точності",
lines=2
)
# Права колонка - налаштування
with gr.Column(scale=1):
gr.Markdown("### ⚙️ Налаштування діагностики")
mode_choices_map = {
"⚡ Миттєвий (найшвидший, базовий аналіз)": "instant",
"❓ Тільки питання (швидко, без тестів)": "question_only",
"💰 З бюджетом (збалансовано)": "budgeted",
"🔓 Без обмежень (повний аналіз)": "no_budget",
"👥 Консенсус (найточніший, повільний)": "ensemble"
}
# Новий, виправлений код
mode = gr.Radio(
choices=[
"instant",
"question_only",
"budgeted",
"no_budget",
"ensemble"
],
label="🔧 Режим діагностики",
value="budgeted",
interactive=True
)
budget = gr.Slider(
minimum=500,
maximum=10000,
step=500,
value=3000,
label="💵 Бюджет діагностики ($)",
interactive=True
)
max_iterations = gr.Slider(
minimum=1,
maximum=15,
step=1,
value=8,
label="🔄 Максимум ітерацій агентів",
interactive=True
)
model_name = gr.Dropdown(
choices=[
"gemini/gemini-2.5-flash",
"gpt-4",
"gpt-4-turbo",
"claude-3-5-sonnet",
"grok-beta"
],
label="🤖 LLM Модель",
value="gemini/gemini-2.5-flash",
interactive=True
)
enable_logging = gr.Checkbox(
label="📝 Детальне логування взаємодії агентів",
value=True,
interactive=True
)
gr.Markdown("---")
diagnose_btn = gr.Button(
"🚀 Запустити діагностику",
variant="primary",
size="lg",
interactive=True
)
# Завантаження зразків
sample_selector.change(
interface.load_sample_case,
inputs=[sample_selector],
outputs=[patient_info, case_name, expected_diagnosis]
)
# Результати діагностики
gr.Markdown("---")
gr.Markdown("## 📊 Результати діагностики")
with gr.Row():
with gr.Column(scale=2):
main_result = gr.Markdown(label="🎯 Основний результат")
detailed_analysis = gr.Markdown(label="🔬 Детальний аналіз")
with gr.Column(scale=1):
recommendations = gr.Markdown(label="💡 Рекомендації")
# Візуалізації (якщо Plotly доступний)
if PLOTLY_AVAILABLE:
with gr.Row():
with gr.Column():
metrics_plot = gr.Plot(label="📈 Метрики діагностики")
with gr.Column():
agent_activity_plot = gr.Plot(label="🤖 Активність агентів")
else:
gr.Markdown("ℹ️ Візуалізації недоступні (Plotly не встановлено)")
metrics_plot = gr.Textbox(visible=False)
agent_activity_plot = gr.Textbox(visible=False)
# Логи бесіди
gr.Markdown("### 💬 Логи взаємодії ШІ-агентів")
conversation_logs = gr.Textbox(
label="Детальні логи бесід між агентами",
lines=12,
elem_classes=["conversation-log"],
interactive=False,
show_copy_button=True
)
# Запуск діагностики
diagnose_btn.click(
interface.diagnose_with_enhanced_tracking,
inputs=[
case_name, patient_info, mode, budget, max_iterations,
model_name, expected_diagnosis, enable_logging
],
outputs=[
main_result, detailed_analysis, recommendations,
metrics_plot, agent_activity_plot, conversation_logs
]
)
# Вкладка аналітики
with gr.Tab("📊 Розширена аналітика", elem_id="analytics-tab"):
gr.Markdown("### 🔍 Аналіз збережених діагностичних сесій")
with gr.Row():
refresh_analytics_btn = gr.Button("🔄 Оновити дані", variant="secondary")
export_data_btn = gr.Button("📤 Експортувати аналітику", variant="secondary")
with gr.Row():
with gr.Column(scale=2):
analytics_table = gr.Dataframe(
label="📋 Історія діагностичних сесій",
interactive=False,
wrap=True
)
with gr.Column(scale=1):
analytics_summary = gr.Markdown(label="📊 Статистичний звіт")
# Детальний аналіз окремих випадків
gr.Markdown("### 🔬 Поглиблений аналіз випадків")
with gr.Row():
case_selector = gr.Dropdown(
label="🗂️ Оберіть випадок для детального аналізу",
choices=[],
interactive=True
)
analyze_case_btn = gr.Button("📋 Створити детальний звіт")
analysis_status = gr.Markdown()
# Функції аналітики - ВИПРАВЛЕНІ
def refresh_analytics():
df, summary, case_choices = interface.get_enhanced_analytics()
return df, summary, gr.Dropdown(choices=case_choices)
def export_analytics():
try:
filename = interface.conversation_logger.export_analytics_csv()
return f"✅ Дані експортовано: {filename}"
except Exception as e:
return f"❌ Помилка експорту: {e}"
def analyze_case(case_id):
if not case_id:
return "⚠️ Оберіть випадок для аналізу"
try:
report = interface.conversation_logger.export_conversation_report(case_id, 'html')
return f"✅ Детальний звіт створено: {report}"
except Exception as e:
return f"❌ Помилка аналізу: {e}"
# Зв'язування функцій
refresh_analytics_btn.click(
refresh_analytics,
outputs=[analytics_table, analytics_summary, case_selector]
)
export_data_btn.click(
export_analytics,
outputs=[analysis_status]
)
analyze_case_btn.click(
analyze_case,
inputs=[case_selector],
outputs=[analysis_status]
)
# Автооновлення при завантаженні
demo.load(refresh_analytics, outputs=[analytics_table, analytics_summary, case_selector])
# Вкладка документації
with gr.Tab("📚 Документація та статус", elem_id="docs-tab"):
# Статус системи
gr.Markdown("### 🔧 Статус системи")
status_info = f"""
**MAI-DX доступність**: {'✅ Доступний' if MAI_DX_AVAILABLE else '❌ Недоступний'}
**Logger доступність**: {'✅ Доступний' if LOGGER_AVAILABLE else '⚠️ Заглушка'}
**Plotly візуалізації**: {'✅ Доступні' if PLOTLY_AVAILABLE else '❌ Недоступні'}
**Gradio версія**: {gr.__version__}
"""
gr.Markdown(status_info)
if not MAI_DX_AVAILABLE:
gr.Markdown(f"**Помилка MAI-DX**: {IMPORT_ERROR}")
# Документація
gr.Markdown("""
### 📖 Короткий гайд
#### 🚀 Швидкий старт:
1. Оберіть готовий тестовий випадок або введіть свій
2. Налаштуйте режим діагностики (рекомендується "З бюджетом")
3. Натисніть "Запустити діагностику"
4. Дочекайтеся результатів та аналізуйте логи
#### 🔧 Режими роботи:
- **⚡ Миттєвий**: Швидкий базовий аналіз (~5 сек)
- **❓ Тільки питання**: Без тестів, тільки опитування
- **💰 З бюджетом**: Збалансований підхід (рекомендується)
- **🔓 Без обмежень**: Максимальна точність
- **👥 Консенсус**: Найвища точність, але повільно
#### 📊 Аналітика:
- Переглядайте історію діагнозів у вкладці "Аналітика"
- Експортуйте дані для подальшого аналізу
- Створюйте детальні звіти по окремих випадках
#### ⚠️ Важливо:
- Система призначена для дослідницьких цілей
- Не замінює професійну медичну консультацію
- При проблемах перевірте статус системи вище
""")
return demo
if __name__ == "__main__":
print("🚀 Запуск виправленого MAI-DX Enhanced Research Platform...")
print(f"🤖 MAI-DX доступність: {'✅' if MAI_DX_AVAILABLE else '❌'}")
print(f"📊 Plotly візуалізації: {'✅' if PLOTLY_AVAILABLE else '❌'}")
print(f"📝 Logger: {'✅' if LOGGER_AVAILABLE else '⚠️ заглушка'}")
print("🔍 Логи зберігаються у: mai_dx_logs/")
demo = create_enhanced_gradio_interface()
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=False, # Відключаємо debug для стабільності
show_error=True,
favicon_path=None,
ssl_verify=False
)