Spaces:
Sleeping
Sleeping
#!/usr/bin/env python3 | |
""" | |
MAI-DX Gradio Research Interface | |
Зручний веб-інтерфейс для дослідження медичної діагностики з ШІ | |
""" | |
import os | |
import sys | |
import json | |
import time | |
import pandas as pd | |
import gradio as gr | |
from datetime import datetime | |
from typing import Dict, List, Tuple, Optional | |
from dataclasses import dataclass, asdict | |
import warnings | |
# Налаштування для запобігання помилок | |
os.environ["SWARMS_VERBOSITY"] = "ERROR" | |
os.environ["RICH_TRACEBACK"] = "0" | |
os.environ["SWARMS_SHOW_PANEL"] = "false" | |
os.environ["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) | |
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 MAIDXGradioInterface: | |
"""Gradio інтерфейс для MAI-DX""" | |
def __init__(self): | |
self.sessions_history = [] | |
self.current_session = None | |
# Перевірка доступності MAI-DX | |
if not MAI_DX_AVAILABLE: | |
print(f"❌ MAI-DX не доступний: {IMPORT_ERROR}") | |
print("📋 Інструкції установки:") | |
print(" pip install mai-dx python-dotenv") | |
print(" Створіть .env файл з API ключами") | |
# Предвизначені тестові кейси | |
self.sample_cases = { | |
"Кардіологічний (Інфаркт)": """ | |
Пацієнт: 58-річний чоловік, менеджер | |
Скарги: Гострий біль у грудях протягом 3 годин | |
Анамнез: | |
- Біль почався під час підйому по сходах | |
- Сильний, здавлюючий, іррадіює в ліву руку та щелепу | |
- Супроводжується потовиділенням, нудотою, задишкою | |
- Не зменшується у спокої | |
Фактори ризику: | |
- Цукровий діабет 2 типу | |
- Артеріальна гіпертензія | |
- Куріння 2 пачки на день протягом 30 років | |
- Сімейний анамнез: батько помер від ІМ у 52 роки | |
Огляд: | |
- Дискомфорт, потовиділення | |
- АТ 180/110, ЧСС 105, ЧД 24 | |
- Серце: S4 галоп, шумів немає | |
- Легені: ясні з обох сторін | |
ЕКГ: ST-підйоми у відведеннях II, III, aVF | |
Тропонін I: 8.5 нг/мл (норма <0.04) | |
""", | |
"Неврологічний (Інсульт)": """ | |
Пацієнтка: 67-річна жінка з раптовими неврологічними симптомами | |
Презентація: | |
- Раптова слабкість правої сторони 2 години тому | |
- Утруднення мови (невиразна мова) | |
- Опущення правої сторони обличчя | |
- Без втрати свідомості | |
Анамнез: | |
- Фібриляція передсердь (не приймає антикоагулянти) | |
- Артеріальна гіпертензія | |
- Попередня ТІА 6 місяців тому | |
Огляд: | |
- У свідомості, але плутається | |
- Правостороннє опущення обличчя | |
- Дрейф правої руки | |
- Дизартрія | |
- NIHSS балів: 8 | |
КТ голови: Гострого крововиливу немає | |
Час від початку: 2 години 15 хвилин | |
""", | |
"Педіатричний (Отит)": """ | |
Пацієнт: 3-річний хлопчик, привели батьки через лихоманку | |
Анамнез: | |
- Лихоманка до 39.5°C протягом 2 днів | |
- Зменшення апетиту та активності | |
- Тягне за праве вухо | |
- Плаче більше звичайного, особливо лежачи | |
- Без кашлю, нежиті або блювання | |
Анамнез життя: | |
- Доношена вагітність, нормальний розвиток | |
- Щеплення за календарем | |
- Алергії невідомі | |
Огляд: | |
- Температура: 39.2°C, ЧСС: 130, ЧД: 28 | |
- Загалом дратівливий, але заспокоюється | |
- ЛОР: права барабанна перетинка еритематозна і випнута | |
- Шия: м'яка, лімфаденопатії немає | |
- Груди: ясні з обох сторін | |
- Живіт: м'який, безболісний | |
""", | |
"Ендокринологічний (Гіпертиреоз)": """ | |
Пацієнтка: 45-річна жінка з прогресуючою втомою | |
Скарги: "Постійно втомлююся і худну, хоча їм" | |
Анамнез захворювання: | |
- 6-місячна історія прогресуючої втоми | |
- Ненавмисне схуднення на 7 кг | |
- Непереносимість спеки та надмірне потовиділення | |
- Серцебиття та тривожність | |
- Порушення сну | |
- Тремор рук | |
Огляд систем: | |
- Часті випорожнення (3-4 рази на день) | |
- Випадіння волосся | |
- Порушення менструального циклу | |
Огляд: | |
- АТ 150/85, ЧСС 110, ЧД 16, Т 37.1°C | |
- Худорлява, тривожна жінка | |
- Очі: легкий екзофтальм, симптом запізнення повік | |
- Щитовидна залоза: дифузно збільшена | |
- Серце: тахікардія, шумів немає | |
- Тремор витягнутих рук | |
- Шкіра: тепла та волога | |
""" | |
} | |
def check_api_keys(self) -> Tuple[str, str]: | |
"""Перевірка наявності API ключів""" | |
required_keys = ["OPENAI_API_KEY", "GEMINI_API_KEY", "ANTHROPIC_API_KEY"] | |
missing_keys = [] | |
available_keys = [] | |
for key in required_keys: | |
if os.getenv(key): | |
available_keys.append(key) | |
else: | |
missing_keys.append(key) | |
if available_keys: | |
status = f"✅ Доступні ключі: {', '.join(available_keys)}" | |
color = "green" | |
else: | |
status = f"❌ Відсутні всі API ключі: {', '.join(missing_keys)}" | |
color = "red" | |
if missing_keys: | |
status += f"\n⚠️ Відсутні: {', '.join(missing_keys)}" | |
return status, color | |
def diagnose_case( | |
self, | |
case_name: str, | |
patient_info: str, | |
mode: str, | |
budget: int, | |
max_iterations: int, | |
model_name: str, | |
expected_diagnosis: str = "", | |
progress=gr.Progress() | |
) -> Tuple[str, str, str, pd.DataFrame]: | |
"""Основна функція діагностики""" | |
if not MAI_DX_AVAILABLE: | |
return ( | |
f"❌ MAI-DX не доступний: {IMPORT_ERROR}", | |
"", | |
"", | |
pd.DataFrame() | |
) | |
if not patient_info.strip(): | |
return ( | |
"❌ Будь ласка, введіть інформацію про пацієнта", | |
"", | |
"", | |
pd.DataFrame() | |
) | |
# Початок діагностики | |
progress(0.1, desc="Ініціалізація MAI-DX...") | |
start_time = time.time() | |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
try: | |
# Створення оркестратора | |
progress(0.2, desc="Створення діагностичного оркестратора...") | |
orchestrator = MaiDxOrchestrator( | |
model_name=model_name, | |
max_iterations=max_iterations, | |
initial_budget=budget, | |
mode=mode if mode != "ensemble" else "budgeted" # Ensemble використовує базовий режим | |
) | |
progress(0.3, desc="Початок аналізу медичного випадку...") | |
# Запуск діагностики | |
if mode == "ensemble": | |
# Для ensemble режиму використовуємо run_ensemble якщо доступний | |
progress(0.4, desc="Запуск 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: | |
# Якщо run_ensemble недоступний, використовуємо звичайний run | |
progress(0.4, desc="Ensemble недоступний, використовуємо стандартний режим...") | |
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" | |
) | |
progress(0.8, desc="Обробка результатів...") | |
duration = time.time() - start_time | |
# Створення сесії | |
session = DiagnosisSession( | |
timestamp=timestamp, | |
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=result.iterations, | |
duration=duration, | |
status="Успішно" if result.accuracy_score >= 2.0 else "Потребує перегляду", | |
reasoning=getattr(result, 'accuracy_reasoning', 'Недоступно')[:300] + "..." | |
) | |
self.sessions_history.append(session) | |
self.current_session = session | |
progress(1.0, desc="Готово!") | |
# Форматування результатів | |
main_result = self._format_main_result(session, result) | |
detailed_analysis = self._format_detailed_analysis(session, result) | |
recommendations = self._generate_recommendations(result) | |
history_df = self._get_history_dataframe() | |
return main_result, detailed_analysis, recommendations, history_df | |
except Exception as e: | |
error_msg = f"❌ Помилка діагностики: {str(e)}" | |
return error_msg, "", "", pd.DataFrame() | |
def _format_main_result(self, session: DiagnosisSession, result) -> str: | |
"""Форматування основного результату""" | |
# Визначення рівня довіри | |
if session.confidence >= 4.0: | |
confidence_level = "🎉 ВИСОКИЙ" | |
confidence_color = "green" | |
elif session.confidence >= 3.0: | |
confidence_level = "👍 СЕРЕДНІЙ" | |
confidence_color = "orange" | |
elif session.confidence >= 2.0: | |
confidence_level = "⚠️ НИЗЬКИЙ" | |
confidence_color = "orange" | |
else: | |
confidence_level = "❌ ДУЖЕ НИЗЬКИЙ" | |
confidence_color = "red" | |
main_result = f""" | |
# 🏥 Результати MAI-DX Діагностики | |
## 📋 Основна інформація | |
- **Випадок**: {session.case_name} | |
- **Час**: {session.timestamp} | |
- **Режим**: {session.mode} | |
## 🎯 Діагноз | |
**{session.diagnosis}** | |
## 📊 Оцінка якості | |
- **Рівень довіри**: {confidence_level} | |
- **Бал точності**: {session.confidence}/5.0 | |
- **Статус**: {session.status} | |
## 💰 Ресурси | |
- **Загальна вартість**: ${session.cost:,.2f} | |
- **Бюджет**: ${session.budget:,} | |
- **Ітерації**: {session.iterations} | |
- **Тривалість**: {session.duration:.1f} сек | |
""" | |
return main_result | |
def _format_detailed_analysis(self, session: DiagnosisSession, result) -> str: | |
"""Детальний аналіз результатів""" | |
analysis = f""" | |
# 🔬 Детальний Аналіз | |
## 💭 Медичне обґрунтування | |
{session.reasoning} | |
## 📈 Показники ефективності | |
- **Швидкість діагностики**: {session.duration:.1f} секунд | |
- **Економічна ефективність**: {((session.budget - session.cost) / session.budget * 100):.1f}% бюджету залишилось | |
- **Ітеративна ефективність**: {session.iterations} циклів аналізу | |
## 🔄 Процес діагностики | |
1. **Початковий аналіз** пацієнтських даних | |
2. **Диференційна діагностика** з {session.iterations} ітераціями | |
3. **Консенсус панелі** 8 ШІ-лікарів | |
4. **Фінальна оцінка** та верифікація | |
## 📊 Порівняння з попередніми випадками | |
""" | |
if len(self.sessions_history) > 1: | |
avg_confidence = sum(s.confidence for s in self.sessions_history[:-1]) / len(self.sessions_history[:-1]) | |
avg_cost = sum(s.cost for s in self.sessions_history[:-1]) / len(self.sessions_history[:-1]) | |
analysis += f""" | |
- **Середня точність** попередніх випадків: {avg_confidence:.1f}/5.0 | |
- **Середня вартість** попередніх випадків: ${avg_cost:,.2f} | |
- **Поточний випадок**: {"Вище середнього" if session.confidence > avg_confidence else "Нижче середнього"} за точністю | |
""" | |
else: | |
analysis += "\n- Це ваш перший діагностичний випадок" | |
return analysis | |
def _generate_recommendations(self, result) -> str: | |
"""Генерація рекомендацій""" | |
recommendations = """ | |
# 💡 Рекомендації | |
## 🏥 Клінічні рекомендації | |
""" | |
diagnosis = result.final_diagnosis.lower() | |
# Базові рекомендації залежно від діагнозу | |
if any(word in diagnosis for word in ["emergency", "acute", "urgent", "infarction", "stroke"]): | |
recommendations += """ | |
- 🚨 **НЕВІДКЛАДНА МЕДИЧНА ДОПОМОГА** | |
- Негайна госпіталізація | |
- Моніторинг життєво важливих функцій | |
- Консультація спеціаліста протягом години | |
""" | |
elif any(word in diagnosis for word in ["infection", "bacterial", "viral"]): | |
recommendations += """ | |
- 💊 Розгляньте антибактеріальну терапію | |
- 🌡️ Моніторинг температури тіла | |
- 🔬 Додаткові лабораторні дослідження | |
- 📅 Контрольний огляд через 48-72 години | |
""" | |
elif any(word in diagnosis for word in ["chronic", "management", "control"]): | |
recommendations += """ | |
- 📋 Розробка довготривалого плану лікування | |
- 🗓️ Регулярні контрольні огляди | |
- 👨⚕️ Консультація профільних спеціалістів | |
- 📚 Навчання пацієнта самоконтролю | |
""" | |
else: | |
recommendations += """ | |
- 🔍 Подальше спостереження та моніторинг | |
- 📋 Розгляньте додаткові діагностичні тести | |
- 👨⚕️ Консультація з лікарем для верифікації | |
- 📝 Документування симптомів та їх динаміки | |
""" | |
recommendations += f""" | |
## 🔬 Дослідницькі рекомендації | |
- **Валідація ШІ-діагнозу**: Порівняйте з експертною оцінкою | |
- **Документування**: Збережіть результат для дослідження | |
- **Аналіз точності**: Оцініть відповідність реальному діагнозу | |
- **Поліпшення**: Використайте результат для налаштування параметрів | |
## ⚠️ Важливі застереження | |
- Цей діагноз згенеровано ШІ для дослідницьких цілей | |
- НЕ замінює професійну медичну консультацію | |
- Завжди консультуйтеся з кваліфікованими медичними працівниками | |
- Використовуйте лише як допоміжний інструмент для навчання | |
## 📈 Поліпшення точності | |
- Додайте більше клінічних деталей до опису випадку | |
- Використайте режим "no_budget" для складних випадків | |
- Розгляньте ensemble діагностику для критичних випадків | |
""" | |
return recommendations | |
def _get_history_dataframe(self) -> pd.DataFrame: | |
"""Отримання історії у вигляді DataFrame""" | |
if not self.sessions_history: | |
return pd.DataFrame() | |
data = [] | |
for session in self.sessions_history: | |
data.append({ | |
"Час": session.timestamp, | |
"Випадок": session.case_name, | |
"Режим": session.mode, | |
"Діагноз": session.diagnosis[:50] + "..." if len(session.diagnosis) > 50 else session.diagnosis, | |
"Точність": f"{session.confidence:.1f}/5.0", | |
"Вартість": f"${session.cost:.2f}", | |
"Ітерації": session.iterations, | |
"Тривалість": f"{session.duration:.1f}с", | |
"Статус": session.status | |
}) | |
return pd.DataFrame(data) | |
def export_results(self) -> str: | |
"""Експорт результатів дослідження""" | |
if not self.sessions_history: | |
return "Немає даних для експорту" | |
# Підготовка даних для експорту | |
export_data = { | |
"metadata": { | |
"export_date": datetime.now().isoformat(), | |
"total_sessions": len(self.sessions_history), | |
"software_version": "MAI-DX Gradio Interface v1.0" | |
}, | |
"sessions": [asdict(session) for session in self.sessions_history], | |
"statistics": self._calculate_statistics() | |
} | |
# Збереження у файл | |
filename = f"mai_dx_research_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" | |
try: | |
with open(filename, 'w', encoding='utf-8') as f: | |
json.dump(export_data, f, indent=2, ensure_ascii=False) | |
return f"✅ Дані експортовано у файл: {filename}" | |
except Exception as e: | |
return f"❌ Помилка експорту: {e}" | |
def _calculate_statistics(self) -> Dict: | |
"""Розрахунок статистики досліджень""" | |
if not self.sessions_history: | |
return {} | |
sessions = self.sessions_history | |
stats = { | |
"total_cases": len(sessions), | |
"average_confidence": sum(s.confidence for s in sessions) / len(sessions), | |
"average_cost": sum(s.cost for s in sessions) / len(sessions), | |
"average_duration": sum(s.duration for s in sessions) / len(sessions), | |
"mode_distribution": {}, | |
"confidence_distribution": { | |
"high": len([s for s in sessions if s.confidence >= 4.0]), | |
"medium": len([s for s in sessions if 2.0 <= s.confidence < 4.0]), | |
"low": len([s for s in sessions if s.confidence < 2.0]) | |
}, | |
"success_rate": len([s for s in sessions if s.confidence >= 2.0]) / len(sessions) | |
} | |
# Розподіл по режимах | |
for session in sessions: | |
mode = session.mode | |
stats["mode_distribution"][mode] = stats["mode_distribution"].get(mode, 0) + 1 | |
return stats | |
def create_gradio_interface(): | |
"""Створення Gradio інтерфейсу""" | |
interface = MAIDXGradioInterface() | |
with gr.Blocks( | |
title="MAI-DX Research Interface", | |
theme=gr.themes.Soft(), | |
css=""" | |
.main-header { text-align: center; color: #2c3e50; } | |
.status-good { color: green; font-weight: bold; } | |
.status-bad { color: red; font-weight: bold; } | |
.case-input { font-family: monospace; } | |
""" | |
) as demo: | |
# Заголовок | |
gr.Markdown(""" | |
# 🏥 MAI-DX Research Interface | |
## Дослідницький інтерфейс для медичної діагностики з ШІ | |
Цей інтерфейс дозволяє проводити дослідження діагностичних можливостей MAI-DX системи з 8 ШІ-агентами лікарів. | |
""", elem_classes=["main-header"]) | |
# Статус системи | |
with gr.Row(): | |
status_display = gr.Markdown() | |
# Оновлення статусу при завантаженні | |
def update_status(): | |
status, color = interface.check_api_keys() | |
return f"**Статус системи**: {status}" | |
demo.load(update_status, outputs=[status_display]) | |
# Основний інтерфейс | |
with gr.Tabs(): | |
# Вкладка діагностики | |
with gr.Tab("🩺 Діагностика"): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("### 📝 Введення медичного випадку") | |
case_name = gr.Textbox( | |
label="Назва випадку", | |
placeholder="Наприклад: Кардіологічний випадок №1", | |
value="" | |
) | |
# Dropdown з прикладами | |
sample_selector = gr.Dropdown( | |
choices=list(interface.sample_cases.keys()), | |
label="Приклади випадків", | |
value=None | |
) | |
patient_info = gr.Textbox( | |
label="Інформація про пацієнта", | |
lines=15, | |
placeholder="Введіть детальний опис медичного випадку...", | |
elem_classes=["case-input"] | |
) | |
# Завантаження прикладу | |
def load_sample(sample_name): | |
if sample_name: | |
return interface.sample_cases[sample_name], sample_name | |
return "", "" | |
sample_selector.change( | |
load_sample, | |
inputs=[sample_selector], | |
outputs=[patient_info, case_name] | |
) | |
expected_diagnosis = gr.Textbox( | |
label="Очікуваний діагноз (опціонально)", | |
placeholder="Для оцінки точності...", | |
value="" | |
) | |
with gr.Column(scale=1): | |
gr.Markdown("### ⚙️ Налаштування діагностики") | |
mode = gr.Radio( | |
choices=[ | |
("instant", "Миттєвий (найшвидший)"), | |
("question_only", "Тільки питання (швидко)"), | |
("budgeted", "З бюджетом (збалансовано)"), | |
("no_budget", "Без обмежень (повний аналіз)"), | |
("ensemble", "Консенсус (найточніший)") | |
], | |
label="Режим діагностики", | |
value="budgeted" | |
) | |
budget = gr.Slider( | |
minimum=500, | |
maximum=10000, | |
step=500, | |
value=3000, | |
label="Бюджет ($)" | |
) | |
max_iterations = gr.Slider( | |
minimum=1, | |
maximum=10, | |
step=1, | |
value=5, | |
label="Максимум ітерацій" | |
) | |
model_name = gr.Dropdown( | |
choices=[ | |
"gemini/gemini-2.5-flash", | |
"gpt-4", | |
"gpt-3.5-turbo", | |
"claude-3-5-sonnet", | |
"grok-beta", | |
"deepseek-chat", | |
"llama-3.1-405b" | |
], | |
label="LLM Модель", | |
value="gemini/gemini-2.5-flash" | |
) | |
diagnose_btn = gr.Button( | |
"🚀 Запустити діагностику", | |
variant="primary", | |
size="lg" | |
) | |
# Результати | |
gr.Markdown("### 📊 Результати діагностики") | |
with gr.Row(): | |
with gr.Column(): | |
main_result = gr.Markdown(label="Основний результат") | |
with gr.Row(): | |
with gr.Column(): | |
detailed_analysis = gr.Markdown(label="Детальний аналіз") | |
with gr.Column(): | |
recommendations = gr.Markdown(label="Рекомендації") | |
# Запуск діагностики | |
diagnose_btn.click( | |
interface.diagnose_case, | |
inputs=[ | |
case_name, patient_info, mode, budget, | |
max_iterations, model_name, expected_diagnosis | |
], | |
outputs=[main_result, detailed_analysis, recommendations, gr.State()] | |
) | |
# Вкладка історії | |
with gr.Tab("📈 Історія та Статистика"): | |
gr.Markdown("### 📋 Історія діагностичних сесій") | |
with gr.Row(): | |
refresh_btn = gr.Button("🔄 Оновити", variant="secondary") | |
export_btn = gr.Button("💾 Експортувати результати", variant="primary") | |
history_table = gr.Dataframe( | |
label="Історія діагнозів", | |
interactive=False | |
) | |
export_status = gr.Markdown() | |
# Функції для оновлення | |
def refresh_history(): | |
return interface._get_history_dataframe() | |
def export_data(): | |
return interface.export_results() | |
refresh_btn.click(refresh_history, outputs=[history_table]) | |
export_btn.click(export_data, outputs=[export_status]) | |
# Статистика | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("### 📊 Статистика досліджень") | |
stats_display = gr.Markdown() | |
def update_stats(): | |
if not interface.sessions_history: | |
return "Поки що немає даних для статистики" | |
stats = interface._calculate_statistics() | |
return f""" | |
**Загальна статистика:** | |
- Всього випадків: {stats['total_cases']} | |
- Середня точність: {stats['average_confidence']:.2f}/5.0 | |
- Середня вартість: ${stats['average_cost']:.2f} | |
- Середня тривалість: {stats['average_duration']:.1f}с | |
- Рівень успішності: {stats['success_rate']:.1%} | |
**Розподіл по режимах:** | |
{chr(10).join([f"- {mode}: {count}" for mode, count in stats['mode_distribution'].items()])} | |
**Розподіл по точності:** | |
- Висока (≥4.0): {stats['confidence_distribution']['high']} | |
- Середня (2.0-3.9): {stats['confidence_distribution']['medium']} | |
- Низька (<2.0): {stats['confidence_distribution']['low']} | |
""" | |
refresh_stats_btn = gr.Button("🔄 Оновити статистику") | |
refresh_stats_btn.click(update_stats, outputs=[stats_display]) | |
# Вкладка налаштувань | |
with gr.Tab("⚙️ Налаштування"): | |
gr.Markdown("### 🔧 Конфігурація системи") | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown(""" | |
#### 📋 Інструкції з установки | |
**Для pip (ваша конфігурація):** | |
```bash | |
# 1. Встановлення залежностей | |
pip install mai-dx python-dotenv gradio pandas | |
# 2. Створення .env файлу | |
echo "OPENAI_API_KEY=your-key-here" > .env | |
echo "GEMINI_API_KEY=your-key-here" >> .env | |
echo "ANTHROPIC_API_KEY=your-key-here" >> .env | |
# 3. Запуск інтерфейсу | |
python mai_dx_gradio_interface.py | |
``` | |
#### 🔑 Необхідні API ключі: | |
- **OpenAI**: для GPT моделей | |
- **Google AI**: для Gemini моделей | |
- **Anthropic**: для Claude моделей | |
Отримайте ключі на відповідних платформах та додайте їх у .env файл. | |
""") | |
with gr.Column(): | |
gr.Markdown(""" | |
#### 🛠️ Troubleshooting | |
**Часті проблеми:** | |
1. **MAI-DX не імпортується** | |
- Встановіть: `pip install mai-dx` | |
- Перевірте віртуальне середовище | |
2. **API ключі не працюють** | |
- Перевірте .env файл | |
- Переконайтеся що файл у тій же папці | |
3. **Rich console помилки** | |
- Це нормально, можна ігнорувати | |
- Система працює попри помилки | |
4. **Повільна робота** | |
- Використовуйте швидші моделі | |
- Зменшіть кількість ітерацій | |
- Оберіть режим "question_only" | |
#### 📞 Підтримка: | |
- GitHub: [MAI-DX Repository](https://github.com/The-Swarm-Corporation/Open-MAI-Dx-Orchestrator) | |
- Документація: включена у репозиторій | |
""") | |
# Тестування підключення | |
with gr.Row(): | |
test_connection_btn = gr.Button("🔍 Тест підключення", variant="secondary") | |
connection_status = gr.Markdown() | |
def test_system(): | |
if not MAI_DX_AVAILABLE: | |
return f"❌ MAI-DX недоступний: {IMPORT_ERROR}" | |
api_status, _ = interface.check_api_keys() | |
return f""" | |
**Результати тестування:** | |
📦 **MAI-DX статус**: ✅ Доступний | |
🔑 **API ключі**: {api_status} | |
🐍 **Python**: {sys.version.split()[0]} | |
📍 **Робоча директорія**: {os.getcwd()} | |
**Готовність до роботи**: {"✅ Готово" if MAI_DX_AVAILABLE else "❌ Потребує налаштування"} | |
""" | |
test_connection_btn.click(test_system, outputs=[connection_status]) | |
return demo | |
if __name__ == "__main__": | |
# Створення та запуск інтерфейсу | |
demo = create_gradio_interface() | |
print("🚀 Запуск MAI-DX Research Interface...") | |
print("📱 Інтерфейс буде доступний у браузері") | |
print("🔧 Переконайтеся що .env файл з API ключами у поточній директорії") | |
demo.launch( | |
server_name="0.0.0.0", # Доступ з мережі | |
server_port=7860, # Порт | |
share=False, # Встановіть True для публічного доступу | |
debug=True, # Режим налагодження | |
show_error=True # Показувати помилки | |
) |