Spaces:
Sleeping
Sleeping
Commit
·
3abb514
0
Parent(s):
Initial commit: Lifestyle clinical application with Gradio interface
Browse files- Add main application files (app.py, app_config.py)
- Include system architecture diagrams and documentation
- Add lifestyle profile and clinical background data
- Setup requirements and configuration files
- .gitignore +61 -0
- .gradio/certificate.pem +31 -0
- README.md +94 -0
- README_local.md +97 -0
- app.py +478 -0
- app_config.py +32 -0
- clinical_background.json +123 -0
- diagram/complete-flow-diagram.mermaid +82 -0
- diagram/lifestyle-activation-logic.mermaid +72 -0
- diagram/lifestyle-activation-logic.txt +72 -0
- diagram/lifestyle-architecture.mermaid +45 -0
- diagram/profile-lifecycle.mermaid +75 -0
- diagram/system-sequence.mermaid +44 -0
- lifestyle_profile.json +27 -0
- requirements.txt +10 -0
.gitignore
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment variables
|
| 2 |
+
.env
|
| 3 |
+
.env.local
|
| 4 |
+
.env.development.local
|
| 5 |
+
.env.test.local
|
| 6 |
+
.env.production.local
|
| 7 |
+
|
| 8 |
+
# Python
|
| 9 |
+
__pycache__/
|
| 10 |
+
*.py[cod]
|
| 11 |
+
*$py.class
|
| 12 |
+
*.so
|
| 13 |
+
.Python
|
| 14 |
+
build/
|
| 15 |
+
develop-eggs/
|
| 16 |
+
dist/
|
| 17 |
+
downloads/
|
| 18 |
+
eggs/
|
| 19 |
+
.eggs/
|
| 20 |
+
lib/
|
| 21 |
+
lib64/
|
| 22 |
+
parts/
|
| 23 |
+
sdist/
|
| 24 |
+
var/
|
| 25 |
+
wheels/
|
| 26 |
+
pip-wheel-metadata/
|
| 27 |
+
share/python-wheels/
|
| 28 |
+
*.egg-info/
|
| 29 |
+
.installed.cfg
|
| 30 |
+
*.egg
|
| 31 |
+
MANIFEST
|
| 32 |
+
|
| 33 |
+
# Virtual environments
|
| 34 |
+
venv/
|
| 35 |
+
env/
|
| 36 |
+
ENV/
|
| 37 |
+
env.bak/
|
| 38 |
+
venv.bak/
|
| 39 |
+
|
| 40 |
+
# IDEs
|
| 41 |
+
.vscode/
|
| 42 |
+
.idea/
|
| 43 |
+
*.swp
|
| 44 |
+
*.swo
|
| 45 |
+
*~
|
| 46 |
+
|
| 47 |
+
# OS
|
| 48 |
+
.DS_Store
|
| 49 |
+
.DS_Store?
|
| 50 |
+
._*
|
| 51 |
+
.Spotlight-V100
|
| 52 |
+
.Trashes
|
| 53 |
+
ehthumbs.db
|
| 54 |
+
Thumbs.db
|
| 55 |
+
|
| 56 |
+
# Gradio
|
| 57 |
+
gradio_cached_examples/
|
| 58 |
+
flagged/
|
| 59 |
+
|
| 60 |
+
# Logs
|
| 61 |
+
*.log
|
.gradio/certificate.pem
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN CERTIFICATE-----
|
| 2 |
+
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
| 3 |
+
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
| 4 |
+
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
| 5 |
+
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
| 6 |
+
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
| 7 |
+
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
| 8 |
+
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
| 9 |
+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
| 10 |
+
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
| 11 |
+
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
| 12 |
+
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
| 13 |
+
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
| 14 |
+
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
| 15 |
+
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
| 16 |
+
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
| 17 |
+
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
| 18 |
+
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
| 19 |
+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
| 20 |
+
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
| 21 |
+
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
| 22 |
+
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
| 23 |
+
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
| 24 |
+
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
| 25 |
+
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
| 26 |
+
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
| 27 |
+
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
| 28 |
+
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
| 29 |
+
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
| 30 |
+
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
| 31 |
+
-----END CERTIFICATE-----
|
README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Lifestyle Journey MVP
|
| 3 |
+
emoji: 🏥
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 4.0.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# 🏥 Lifestyle Journey MVP
|
| 14 |
+
|
| 15 |
+
Тестовий чат-бот з медичним асистентом та lifestyle коучингом на базі Gemini API.
|
| 16 |
+
|
| 17 |
+
## ⚡ Швидкий старт
|
| 18 |
+
|
| 19 |
+
1. **Налаштуйте API ключ** в розділі Settings → Variables and secrets
|
| 20 |
+
- Додайте змінну `GEMINI_API_KEY` з вашим Gemini API ключем
|
| 21 |
+
|
| 22 |
+
2. **Почніть тестування:**
|
| 23 |
+
- Медичні питання: "У мене болить груди"
|
| 24 |
+
- Lifestyle: "Хочу почати займатися спортом"
|
| 25 |
+
|
| 26 |
+
## 🎯 Функціонал
|
| 27 |
+
|
| 28 |
+
### Session Controller
|
| 29 |
+
- **Автоматичне визначення режиму** (medical/lifestyle)
|
| 30 |
+
- **Red flags детекція** для ургентних станів
|
| 31 |
+
- **JSON-based рішення** для прозорості логіки
|
| 32 |
+
|
| 33 |
+
### Medical Assistant
|
| 34 |
+
- Медичні консультації з урахуванням хронічних станів
|
| 35 |
+
- Безпечні рекомендації та тріаж
|
| 36 |
+
- Направлення до лікарів при необхідності
|
| 37 |
+
|
| 38 |
+
### Lifestyle Coach
|
| 39 |
+
- Персоналізовані поради по фізактивності
|
| 40 |
+
- Рекомендації з харчування
|
| 41 |
+
- Прогресія з урахуванням медичних обмежень
|
| 42 |
+
- Автоматичне оновлення профілю пацієнта
|
| 43 |
+
|
| 44 |
+
## 🧪 Тестові сценарії
|
| 45 |
+
|
| 46 |
+
```
|
| 47 |
+
🚨 Медичні ургентні стани:
|
| 48 |
+
- "У мене сильний біль у грудях"
|
| 49 |
+
- "Тиск 190/110, що робити?"
|
| 50 |
+
- "Втрачаю свідомість"
|
| 51 |
+
|
| 52 |
+
💚 Lifestyle коучинг:
|
| 53 |
+
- "Хочу схуднути безпечно"
|
| 54 |
+
- "Які вправи можна при діабеті?"
|
| 55 |
+
- "Допоможіть скласти план харчування"
|
| 56 |
+
|
| 57 |
+
🔄 Змішані запити:
|
| 58 |
+
- "Чи можна бігати з гіпертонією?"
|
| 59 |
+
- "Болить спина після тренувань"
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
## 📊 Архітектура
|
| 63 |
+
|
| 64 |
+
```mermaid
|
| 65 |
+
graph TD
|
| 66 |
+
A[Повідомлення пацієнта] --> B[Session Controller]
|
| 67 |
+
B --> C{JSON рішення}
|
| 68 |
+
C -->|medical| D[Medical Assistant]
|
| 69 |
+
C -->|lifestyle| E[Lifestyle Assistant]
|
| 70 |
+
D --> F[Відповідь + Clinical Context]
|
| 71 |
+
E --> G[Відповідь + Updated Profile]
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## ⚠️ Важлива інформація
|
| 75 |
+
|
| 76 |
+
- **Тільки для тестування** - не замінює медичну допомогу
|
| 77 |
+
- При серйозних симптомах - звертайтесь до лікаря
|
| 78 |
+
- API ключ зберігається безпечно в HuggingFace Spaces
|
| 79 |
+
|
| 80 |
+
## 🔧 Для розробників
|
| 81 |
+
|
| 82 |
+
Якщо хочете запустити локально:
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
git clone <this-repo>
|
| 86 |
+
pip install -r requirements.txt
|
| 87 |
+
cp .env.example .env
|
| 88 |
+
# Додайте ваш GEMINI_API_KEY в .env
|
| 89 |
+
python app.py
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
Made with ❤️ for healthcare innovation
|
README_local.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🏥 Lifestyle Journey MVP
|
| 2 |
+
|
| 3 |
+
Тестовий чат-бот з медичним асистентом та lifestyle коучингом на базі Gemini API.
|
| 4 |
+
|
| 5 |
+
## 🚀 Локальний запуск
|
| 6 |
+
|
| 7 |
+
### 1. Встановлення залежностей
|
| 8 |
+
```bash
|
| 9 |
+
pip install -r requirements.txt
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
### 2. Налаштування API ключа
|
| 13 |
+
1. Скопіюйте `.env.example` в `.env`:
|
| 14 |
+
```bash
|
| 15 |
+
cp .env.example .env
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
2. Відредагуйте `.env` файл та додайте ваш Gemini API ключ:
|
| 19 |
+
```
|
| 20 |
+
GEMINI_API_KEY=your_actual_api_key_here
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
### 3. Запуск
|
| 24 |
+
```bash
|
| 25 |
+
python app.py
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
Застосунок запуститься на `http://localhost:7860`
|
| 29 |
+
|
| 30 |
+
## 🤗 Деплоймент на HuggingFace Spaces
|
| 31 |
+
|
| 32 |
+
### 1. Створення Space
|
| 33 |
+
1. Перейдіть на [HuggingFace Spaces](https://huggingface.co/spaces)
|
| 34 |
+
2. Натисніть "Create new Space"
|
| 35 |
+
3. Оберіть **Gradio** як SDK
|
| 36 |
+
4. Завантажте файли проекту
|
| 37 |
+
|
| 38 |
+
### 2. Налаштування змінних оточення
|
| 39 |
+
1. В налаштуваннях Space перейдіть в розділ **Variables and secrets**
|
| 40 |
+
2. Додайте змінну `GEMINI_API_KEY` з вашим API ключем
|
| 41 |
+
|
| 42 |
+
### 3. Файлова структура для HuggingFace
|
| 43 |
+
```
|
| 44 |
+
your-space/
|
| 45 |
+
├── app.py
|
| 46 |
+
├── requirements.txt
|
| 47 |
+
├── .env.example
|
| 48 |
+
└── README.md
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
## 🧪 Тестування
|
| 52 |
+
|
| 53 |
+
### Медичний режим
|
| 54 |
+
Спробуйте повідомлення:
|
| 55 |
+
- "У мене болить груди та важко дихати"
|
| 56 |
+
- "Високий тиск 180/100, що робити?"
|
| 57 |
+
- "Піднялася температура до 39"
|
| 58 |
+
|
| 59 |
+
### Lifestyle режим
|
| 60 |
+
Спробуйте повідомлення:
|
| 61 |
+
- "Хочу почати займатися спортом"
|
| 62 |
+
- "Як правильно харчуватися при діабеті?"
|
| 63 |
+
- "Допоможіть скласти план тренувань"
|
| 64 |
+
|
| 65 |
+
### Змішані запити
|
| 66 |
+
- "Чи можна мені бігати з моїм серцем?"
|
| 67 |
+
- "Які вправи безпечні при гіпертонії?"
|
| 68 |
+
|
| 69 |
+
## 📋 Архітектура
|
| 70 |
+
|
| 71 |
+
### Компоненти
|
| 72 |
+
- **SessionController** - оркестратор режимів (JSON рішення)
|
| 73 |
+
- **MedicalAssistant** - медичні консультації та тріаж
|
| 74 |
+
- **LifestyleAssistant** - coaching з оновленням профілю
|
| 75 |
+
- **GradioInterface** - візуальний інтерфейс
|
| 76 |
+
|
| 77 |
+
### Потік даних
|
| 78 |
+
```
|
| 79 |
+
Повідомлення → SessionController → Medical/Lifestyle Assistant → Відповідь + Профіль
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
## ⚠️ Важливо
|
| 83 |
+
|
| 84 |
+
- Це **тестовий MVP**, не для реального медичного використання
|
| 85 |
+
- Завжди консультуйтесь з лікарем при серйозних симптомах
|
| 86 |
+
- API ключ тримайте в безпеці
|
| 87 |
+
|
| 88 |
+
## 🔧 Налагодження
|
| 89 |
+
|
| 90 |
+
Якщо виникають проблеми:
|
| 91 |
+
1. Перевірте наявність `GEMINI_API_KEY` в .env файлі
|
| 92 |
+
2. Переконайтесь що всі залежності встановлені
|
| 93 |
+
3. Перегляньте логи в консолі
|
| 94 |
+
|
| 95 |
+
## 📞 Підтримка
|
| 96 |
+
|
| 97 |
+
При виникненні питань створюйте issue в репозиторії проекту.
|
app.py
ADDED
|
@@ -0,0 +1,478 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import gradio as gr
|
| 4 |
+
from datetime import datetime
|
| 5 |
+
from dataclasses import dataclass, asdict
|
| 6 |
+
from typing import List, Dict, Optional
|
| 7 |
+
from google import genai
|
| 8 |
+
from google.genai import types
|
| 9 |
+
from dotenv import load_dotenv
|
| 10 |
+
|
| 11 |
+
from dotenv import load_dotenv
|
| 12 |
+
try:
|
| 13 |
+
from app_config import GRADIO_CONFIG, API_CONFIG
|
| 14 |
+
except ImportError:
|
| 15 |
+
# Fallback конфігурація якщо файл відсутній
|
| 16 |
+
GRADIO_CONFIG = {"theme": "soft", "show_api": False}
|
| 17 |
+
API_CONFIG = {"gemini_model": "gemini-2.5-flash", "temperature": 0.3}
|
| 18 |
+
|
| 19 |
+
# Завантаження змінних оточення з .env файлу
|
| 20 |
+
load_dotenv()
|
| 21 |
+
|
| 22 |
+
@dataclass
|
| 23 |
+
class ClinicalBackground:
|
| 24 |
+
patient_id: str
|
| 25 |
+
conditions: List[str]
|
| 26 |
+
medications: List[str]
|
| 27 |
+
allergies: List[str]
|
| 28 |
+
current_symptoms: List[str]
|
| 29 |
+
vital_signs: Dict[str, str]
|
| 30 |
+
|
| 31 |
+
@dataclass
|
| 32 |
+
class LifestyleProfile:
|
| 33 |
+
exercise_preferences: List[str]
|
| 34 |
+
limitations: List[str]
|
| 35 |
+
dietary_notes: List[str]
|
| 36 |
+
goals: List[str]
|
| 37 |
+
journey_summary: str
|
| 38 |
+
last_session_summary: str
|
| 39 |
+
progress_metrics: Dict[str, str]
|
| 40 |
+
|
| 41 |
+
@dataclass
|
| 42 |
+
class ChatMessage:
|
| 43 |
+
timestamp: str
|
| 44 |
+
role: str # "user" or "assistant"
|
| 45 |
+
message: str
|
| 46 |
+
mode: str # "medical", "lifestyle", or "controller"
|
| 47 |
+
metadata: Dict = None
|
| 48 |
+
|
| 49 |
+
@dataclass
|
| 50 |
+
class SessionState:
|
| 51 |
+
current_mode: str # "medical", "lifestyle", "none"
|
| 52 |
+
is_active_session: bool
|
| 53 |
+
session_start_time: Optional[str]
|
| 54 |
+
last_controller_decision: Dict
|
| 55 |
+
|
| 56 |
+
class GeminiAPI:
|
| 57 |
+
def __init__(self):
|
| 58 |
+
self.client = genai.Client(
|
| 59 |
+
api_key=os.environ.get("GEMINI_API_KEY"),
|
| 60 |
+
)
|
| 61 |
+
self.model = os.getenv("GEMINI_MODEL", API_CONFIG.get("gemini_model", "gemini-2.5-flash"))
|
| 62 |
+
|
| 63 |
+
def generate_response(self, system_prompt: str, user_prompt: str, temperature: float = None) -> str:
|
| 64 |
+
"""Генерує відповідь від Gemini"""
|
| 65 |
+
if temperature is None:
|
| 66 |
+
temperature = API_CONFIG.get("temperature", 0.3)
|
| 67 |
+
|
| 68 |
+
try:
|
| 69 |
+
contents = [
|
| 70 |
+
types.Content(
|
| 71 |
+
role="user",
|
| 72 |
+
parts=[types.Part.from_text(text=user_prompt)],
|
| 73 |
+
),
|
| 74 |
+
]
|
| 75 |
+
|
| 76 |
+
config = types.GenerateContentConfig(
|
| 77 |
+
temperature=temperature,
|
| 78 |
+
system_instruction=[
|
| 79 |
+
types.Part.from_text(text=system_prompt),
|
| 80 |
+
],
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
response = ""
|
| 84 |
+
for chunk in self.client.models.generate_content_stream(
|
| 85 |
+
model=self.model,
|
| 86 |
+
contents=contents,
|
| 87 |
+
config=config,
|
| 88 |
+
):
|
| 89 |
+
response += chunk.text
|
| 90 |
+
|
| 91 |
+
return response.strip()
|
| 92 |
+
except Exception as e:
|
| 93 |
+
return f"Помилка API: {str(e)}"
|
| 94 |
+
|
| 95 |
+
class SessionController:
|
| 96 |
+
def __init__(self, api: GeminiAPI):
|
| 97 |
+
self.api = api
|
| 98 |
+
|
| 99 |
+
def make_decision(self, user_message: str, chat_history: List[ChatMessage],
|
| 100 |
+
clinical_background: ClinicalBackground, current_state: SessionState) -> Dict:
|
| 101 |
+
"""Приймає рішення про режим сесії"""
|
| 102 |
+
|
| 103 |
+
system_prompt = """Ти - Session Controller для медичного додатку з lifestyle coaching.
|
| 104 |
+
|
| 105 |
+
ТВОЄ ЗАВДАННЯ: Проаналізувати повідомлення пацієнта і прийняти рішення про режим роботи.
|
| 106 |
+
|
| 107 |
+
РЕЖИМИ:
|
| 108 |
+
- medical: медичні симптоми, скарги, ургентні стани
|
| 109 |
+
- lifestyle: фізична активність, харчування, спосіб життя, мотивація
|
| 110 |
+
- none: завершення сесії або неясний контекст
|
| 111 |
+
|
| 112 |
+
RED FLAGS (завжди -> medical):
|
| 113 |
+
- біль у грудях, задишка у спокої
|
| 114 |
+
- високий АТ (>180/120), низький (<80/50)
|
| 115 |
+
- синкопе, запаморочення
|
| 116 |
+
- різкий набряк, набір ваги
|
| 117 |
+
- симптомна гіпо/гіперглікемія
|
| 118 |
+
|
| 119 |
+
ВІДПОВІДАЙ ЛИШЕ У ФОРМАТІ JSON:
|
| 120 |
+
{
|
| 121 |
+
"action": "start_medical|start_lifestyle|continue_current|end_session",
|
| 122 |
+
"mode": "medical|lifestyle|none",
|
| 123 |
+
"reasoning": "коротке пояснення українською",
|
| 124 |
+
"escalation_needed": true/false
|
| 125 |
+
}"""
|
| 126 |
+
|
| 127 |
+
# Формуємо контекст
|
| 128 |
+
history_text = "\n".join([f"{msg.role}: {msg.message}" for msg in chat_history[-5:]])
|
| 129 |
+
clinical_text = f"Стани: {', '.join(clinical_background.conditions)}"
|
| 130 |
+
|
| 131 |
+
user_prompt = f"""
|
| 132 |
+
КЛІНІЧНИЙ КОНТЕКСТ: {clinical_text}
|
| 133 |
+
|
| 134 |
+
ПОТОЧНИЙ СТАН СЕСІЇ: режим={current_state.current_mode}, активна={current_state.is_active_session}
|
| 135 |
+
|
| 136 |
+
ІСТОРІЯ ЧАТУ:
|
| 137 |
+
{history_text}
|
| 138 |
+
|
| 139 |
+
НОВЕ ПОВІДОМЛЕННЯ ПАЦІЄНТА: {user_message}
|
| 140 |
+
|
| 141 |
+
Прийми рішення про режим роботи:"""
|
| 142 |
+
|
| 143 |
+
response = self.api.generate_response(system_prompt, user_prompt, temperature=0.1)
|
| 144 |
+
|
| 145 |
+
try:
|
| 146 |
+
# Очищуємо відповідь від markdown
|
| 147 |
+
clean_response = response.replace("```json", "").replace("```", "").strip()
|
| 148 |
+
decision = json.loads(clean_response)
|
| 149 |
+
return decision
|
| 150 |
+
except:
|
| 151 |
+
# Fallback рішення
|
| 152 |
+
return {
|
| 153 |
+
"action": "start_medical",
|
| 154 |
+
"mode": "medical",
|
| 155 |
+
"reasoning": "Помилка парсингу - перенаправлення до медичного режиму для безпеки",
|
| 156 |
+
"escalation_needed": True
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
class MedicalAssistant:
|
| 160 |
+
def __init__(self, api: GeminiAPI):
|
| 161 |
+
self.api = api
|
| 162 |
+
|
| 163 |
+
def generate_response(self, user_message: str, chat_history: List[ChatMessage],
|
| 164 |
+
clinical_background: ClinicalBackground) -> str:
|
| 165 |
+
"""Генерує медичну відповідь"""
|
| 166 |
+
|
| 167 |
+
system_prompt = """Ти - досвідчений медичний асистент для пацієнтів з хронічними захворюваннями.
|
| 168 |
+
|
| 169 |
+
ПРИНЦИПИ:
|
| 170 |
+
- Безпека пацієнта - головний пріоритет
|
| 171 |
+
- Не ставиш діагнози, не призначаєш лікування
|
| 172 |
+
- Рекомендуєш звернення до лікаря при червоних прапорцях
|
| 173 |
+
- Даєш загальні поради з управління хронічними станами
|
| 174 |
+
- Відповідаєш українською мовою
|
| 175 |
+
|
| 176 |
+
При УРГЕНТНИХ симптомах - рекомендуй негайне звернення до медзакладу."""
|
| 177 |
+
|
| 178 |
+
# Контекст
|
| 179 |
+
conditions = ", ".join(clinical_background.conditions)
|
| 180 |
+
medications = ", ".join(clinical_background.medications) if clinical_background.medications else "не вказані"
|
| 181 |
+
history_text = "\n".join([f"{msg.role}: {msg.message}" for msg in chat_history[-3:]])
|
| 182 |
+
|
| 183 |
+
user_prompt = f"""
|
| 184 |
+
МЕДИЧНИЙ ПРОФІЛЬ ПАЦІЄНТА:
|
| 185 |
+
- Захворювання: {conditions}
|
| 186 |
+
- Медикаменти: {medications}
|
| 187 |
+
- Алергії: {", ".join(clinical_background.allergies) if clinical_background.allergies else "немає"}
|
| 188 |
+
|
| 189 |
+
ІСТОРІЯ РОЗМОВИ:
|
| 190 |
+
{history_text}
|
| 191 |
+
|
| 192 |
+
ПИТАННЯ ПАЦІЄНТА: {user_message}
|
| 193 |
+
|
| 194 |
+
Надай медичну консультацію:"""
|
| 195 |
+
|
| 196 |
+
return self.api.generate_response(system_prompt, user_prompt)
|
| 197 |
+
|
| 198 |
+
class LifestyleAssistant:
|
| 199 |
+
def __init__(self, api: GeminiAPI):
|
| 200 |
+
self.api = api
|
| 201 |
+
|
| 202 |
+
def generate_response(self, user_message: str, chat_history: List[ChatMessage],
|
| 203 |
+
clinical_background: ClinicalBackground, lifestyle_profile: LifestyleProfile) -> tuple[str, LifestyleProfile]:
|
| 204 |
+
"""Генерує lifestyle відповідь та оновлює профіль"""
|
| 205 |
+
|
| 206 |
+
system_prompt = """Ти - lifestyle coach для пацієнтів з хронічними захворюваннями.
|
| 207 |
+
|
| 208 |
+
ПРИНЦИПИ:
|
| 209 |
+
- Безпечні, поступові зміни з урахуванням медичних обмежень
|
| 210 |
+
- Персоналізація на основі профілю пацієнта
|
| 211 |
+
- Позитивне підкріплення та реалістичні цілі
|
| 212 |
+
- Мотивація через малі кроки прогресу
|
| 213 |
+
- Відповідаєш українською мовою
|
| 214 |
+
|
| 215 |
+
УВАГА до медичних обмежень:
|
| 216 |
+
- ХСН: уникай інтенсивних навантажень
|
| 217 |
+
- АГ: контроль солі, стрес-менеджмент
|
| 218 |
+
- ЦД2: контроль вуглеводів, регулярність
|
| 219 |
+
|
| 220 |
+
В кінці кожної сесії пропонуй конкретний план дій та час наступної зустрічі."""
|
| 221 |
+
|
| 222 |
+
# Контекст
|
| 223 |
+
conditions = ", ".join(clinical_background.conditions)
|
| 224 |
+
goals = ", ".join(lifestyle_profile.goals) if lifestyle_profile.goals else "не визначені"
|
| 225 |
+
limitations = ", ".join(lifestyle_profile.limitations) if lifestyle_profile.limitations else "немає"
|
| 226 |
+
|
| 227 |
+
history_text = "\n".join([f"{msg.role}: {msg.message}" for msg in chat_history[-3:]])
|
| 228 |
+
|
| 229 |
+
user_prompt = f"""
|
| 230 |
+
МЕДИЧНИЙ КОНТЕКСТ: {conditions}
|
| 231 |
+
|
| 232 |
+
LIFESTYLE ПРОФІЛЬ:
|
| 233 |
+
- Цілі: {goals}
|
| 234 |
+
- Обмеження: {limitations}
|
| 235 |
+
- Уподобання: {", ".join(lifestyle_profile.exercise_preferences) if lifestyle_profile.exercise_preferences else "не вказані"}
|
| 236 |
+
- Попередня сесія: {lifestyle_profile.last_session_summary}
|
| 237 |
+
|
| 238 |
+
ІСТОРІЯ РОЗМОВИ:
|
| 239 |
+
{history_text}
|
| 240 |
+
|
| 241 |
+
ПОВІДОМЛЕННЯ ПАЦІЄНТА: {user_message}
|
| 242 |
+
|
| 243 |
+
Проведи lifestyle коучинг:"""
|
| 244 |
+
|
| 245 |
+
response = self.api.generate_response(system_prompt, user_prompt)
|
| 246 |
+
|
| 247 |
+
# Простий update профілю - додаємо до journey summary
|
| 248 |
+
updated_profile = lifestyle_profile
|
| 249 |
+
if user_message and response:
|
| 250 |
+
updated_profile.last_session_summary = f"Обговорили: {user_message[:100]}..."
|
| 251 |
+
updated_profile.journey_summary += f" Сесія {datetime.now().strftime('%d.%m')}: {user_message[:50]}..."
|
| 252 |
+
|
| 253 |
+
return response, updated_profile
|
| 254 |
+
|
| 255 |
+
class LifestyleJourneyApp:
|
| 256 |
+
def __init__(self):
|
| 257 |
+
self.api = GeminiAPI()
|
| 258 |
+
self.controller = SessionController(self.api)
|
| 259 |
+
self.medical_assistant = MedicalAssistant(self.api)
|
| 260 |
+
self.lifestyle_assistant = LifestyleAssistant(self.api)
|
| 261 |
+
|
| 262 |
+
# Ініціалізація даних пацієнта
|
| 263 |
+
self.clinical_background = ClinicalBackground(
|
| 264 |
+
patient_id="test_001",
|
| 265 |
+
conditions=["Хронічна серцева недостатність", "Артеріальна гіпертензія", "Цукровий діабет 2 типу"],
|
| 266 |
+
medications=["Еналаприл 10мг", "Метформін 500мг"],
|
| 267 |
+
allergies=["Пеніцилін"],
|
| 268 |
+
current_symptoms=[],
|
| 269 |
+
vital_signs={"АТ": "140/90", "ЧСС": "72", "Глюкоза": "8.2"}
|
| 270 |
+
)
|
| 271 |
+
|
| 272 |
+
self.lifestyle_profile = LifestyleProfile(
|
| 273 |
+
exercise_preferences=["ходьба на свіжому повітрі"],
|
| 274 |
+
limitations=["уникати високоінтенсивних навантажень через ХСН"],
|
| 275 |
+
dietary_notes=["низькосольова дієта", "контроль вуглеводів"],
|
| 276 |
+
goals=["покращити витривалість", "контролювати АТ та цукор"],
|
| 277 |
+
journey_summary="Початок lifestyle journey",
|
| 278 |
+
last_session_summary="",
|
| 279 |
+
progress_metrics={}
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
self.chat_history: List[ChatMessage] = []
|
| 283 |
+
self.session_state = SessionState(
|
| 284 |
+
current_mode="none",
|
| 285 |
+
is_active_session=False,
|
| 286 |
+
session_start_time=None,
|
| 287 |
+
last_controller_decision={}
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
def process_message(self, message: str, history):
|
| 291 |
+
"""Основна логіка обробки повідомлень"""
|
| 292 |
+
if not message.strip():
|
| 293 |
+
return history, self._get_status_info()
|
| 294 |
+
|
| 295 |
+
# 1. Controller приймає рішення
|
| 296 |
+
decision = self.controller.make_decision(
|
| 297 |
+
message, self.chat_history, self.clinical_background, self.session_state
|
| 298 |
+
)
|
| 299 |
+
|
| 300 |
+
self.session_state.last_controller_decision = decision
|
| 301 |
+
|
| 302 |
+
# 2. Додаємо повідомлення користувача до історії
|
| 303 |
+
user_msg = ChatMessage(
|
| 304 |
+
timestamp=datetime.now().strftime("%H:%M"),
|
| 305 |
+
role="user",
|
| 306 |
+
message=message,
|
| 307 |
+
mode=decision.get("mode", "unknown")
|
| 308 |
+
)
|
| 309 |
+
self.chat_history.append(user_msg)
|
| 310 |
+
|
| 311 |
+
# 3. Генеруємо відповідь залежно від режиму
|
| 312 |
+
if decision["mode"] == "medical":
|
| 313 |
+
self.session_state.current_mode = "medical"
|
| 314 |
+
self.session_state.is_active_session = True
|
| 315 |
+
|
| 316 |
+
response = self.medical_assistant.generate_response(
|
| 317 |
+
message, self.chat_history, self.clinical_background
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
elif decision["mode"] == "lifestyle":
|
| 321 |
+
self.session_state.current_mode = "lifestyle"
|
| 322 |
+
self.session_state.is_active_session = True
|
| 323 |
+
|
| 324 |
+
response, self.lifestyle_profile = self.lifestyle_assistant.generate_response(
|
| 325 |
+
message, self.chat_history, self.clinical_background, self.lifestyle_profile
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
else:
|
| 329 |
+
self.session_state.current_mode = "none"
|
| 330 |
+
self.session_state.is_active_session = False
|
| 331 |
+
response = "Будь ласка, уточніть ваше питання. Я можу допомогти з медичними питаннями або питаннями способу життя."
|
| 332 |
+
|
| 333 |
+
# 4. Додаємо відповідь асистента
|
| 334 |
+
assistant_msg = ChatMessage(
|
| 335 |
+
timestamp=datetime.now().strftime("%H:%M"),
|
| 336 |
+
role="assistant",
|
| 337 |
+
message=response,
|
| 338 |
+
mode=self.session_state.current_mode
|
| 339 |
+
)
|
| 340 |
+
self.chat_history.append(assistant_msg)
|
| 341 |
+
|
| 342 |
+
# 5. Оновлюємо Gradio історію
|
| 343 |
+
history.append([message, response])
|
| 344 |
+
|
| 345 |
+
return history, self._get_status_info()
|
| 346 |
+
|
| 347 |
+
def _get_status_info(self) -> str:
|
| 348 |
+
"""Повертає інформацію про стан сесії"""
|
| 349 |
+
decision = self.session_state.last_controller_decision
|
| 350 |
+
|
| 351 |
+
status = f"""
|
| 352 |
+
📊 **СТАН СЕСІЇ**
|
| 353 |
+
• Режим: {self.session_state.current_mode.upper()}
|
| 354 |
+
• Активна: {'✅' if self.session_state.is_active_session else '❌'}
|
| 355 |
+
|
| 356 |
+
🧠 **ОСТАННЄ РІШЕННЯ CONTROLLER:**
|
| 357 |
+
• Дія: {decision.get('action', 'N/A')}
|
| 358 |
+
• Обґрунтування: {decision.get('reasoning', 'N/A')}
|
| 359 |
+
• Ескалація: {'🚨' if decision.get('escalation_needed') else '✅'}
|
| 360 |
+
|
| 361 |
+
👤 **ПАЦІЄНТ:**
|
| 362 |
+
• Стани: {', '.join(self.clinical_background.conditions)}
|
| 363 |
+
• Lifestyle цілі: {', '.join(self.lifestyle_profile.goals) if self.lifestyle_profile.goals else 'Не встановлені'}
|
| 364 |
+
"""
|
| 365 |
+
return status
|
| 366 |
+
|
| 367 |
+
def reset_session(self):
|
| 368 |
+
"""Скидання сесії"""
|
| 369 |
+
self.chat_history = []
|
| 370 |
+
self.session_state = SessionState(
|
| 371 |
+
current_mode="none",
|
| 372 |
+
is_active_session=False,
|
| 373 |
+
session_start_time=None,
|
| 374 |
+
last_controller_decision={}
|
| 375 |
+
)
|
| 376 |
+
return [], self._get_status_info()
|
| 377 |
+
|
| 378 |
+
# Створення Gradio інтерфейсу
|
| 379 |
+
def create_app():
|
| 380 |
+
app = LifestyleJourneyApp()
|
| 381 |
+
|
| 382 |
+
# Використовуємо конфігурацію для Gradio
|
| 383 |
+
theme_name = GRADIO_CONFIG.get("theme", "soft")
|
| 384 |
+
if theme_name.lower() == "soft":
|
| 385 |
+
theme = gr.themes.Soft()
|
| 386 |
+
elif theme_name.lower() == "default":
|
| 387 |
+
theme = gr.themes.Default()
|
| 388 |
+
else:
|
| 389 |
+
theme = gr.themes.Soft() # fallback
|
| 390 |
+
|
| 391 |
+
with gr.Blocks(
|
| 392 |
+
title=GRADIO_CONFIG.get("title", "Lifestyle Journey MVP"),
|
| 393 |
+
theme=theme,
|
| 394 |
+
analytics_enabled=False
|
| 395 |
+
) as demo:
|
| 396 |
+
gr.Markdown("# 🏥 Lifestyle Journey MVP")
|
| 397 |
+
gr.Markdown("Тестовий чат-бот з медичним асистентом та lifestyle коучингом")
|
| 398 |
+
|
| 399 |
+
with gr.Row():
|
| 400 |
+
with gr.Column(scale=2):
|
| 401 |
+
chatbot = gr.Chatbot(
|
| 402 |
+
label="💬 Розмова з асистентом",
|
| 403 |
+
height=400,
|
| 404 |
+
show_copy_button=True
|
| 405 |
+
)
|
| 406 |
+
|
| 407 |
+
with gr.Row():
|
| 408 |
+
msg = gr.Textbox(
|
| 409 |
+
label="Ваше повідомлення",
|
| 410 |
+
placeholder="Напишіть своє питання...",
|
| 411 |
+
scale=4
|
| 412 |
+
)
|
| 413 |
+
send_btn = gr.Button("📤 Надіслати", scale=1)
|
| 414 |
+
|
| 415 |
+
clear_btn = gr.Button("🗑️ Очистити чат")
|
| 416 |
+
|
| 417 |
+
with gr.Column(scale=1):
|
| 418 |
+
status_box = gr.Markdown(
|
| 419 |
+
value=app._get_status_info(),
|
| 420 |
+
label="📊 Статус системи"
|
| 421 |
+
)
|
| 422 |
+
|
| 423 |
+
# Обробники подій
|
| 424 |
+
def handle_message(message, history):
|
| 425 |
+
return app.process_message(message, history)
|
| 426 |
+
|
| 427 |
+
def handle_clear():
|
| 428 |
+
return app.reset_session()
|
| 429 |
+
|
| 430 |
+
send_btn.click(
|
| 431 |
+
handle_message,
|
| 432 |
+
inputs=[msg, chatbot],
|
| 433 |
+
outputs=[chatbot, status_box]
|
| 434 |
+
).then(
|
| 435 |
+
lambda: "",
|
| 436 |
+
outputs=[msg]
|
| 437 |
+
)
|
| 438 |
+
|
| 439 |
+
msg.submit(
|
| 440 |
+
handle_message,
|
| 441 |
+
inputs=[msg, chatbot],
|
| 442 |
+
outputs=[chatbot, status_box]
|
| 443 |
+
).then(
|
| 444 |
+
lambda: "",
|
| 445 |
+
outputs=[msg]
|
| 446 |
+
)
|
| 447 |
+
|
| 448 |
+
clear_btn.click(
|
| 449 |
+
handle_clear,
|
| 450 |
+
outputs=[chatbot, status_box]
|
| 451 |
+
)
|
| 452 |
+
|
| 453 |
+
return demo
|
| 454 |
+
|
| 455 |
+
if __name__ == "__main__":
|
| 456 |
+
# API ключ завантажується з .env файлу
|
| 457 |
+
# Створіть файл .env з: GEMINI_API_KEY=your_api_key_here
|
| 458 |
+
|
| 459 |
+
if not os.getenv("GEMINI_API_KEY"):
|
| 460 |
+
print("⚠️ GEMINI_API_KEY не знайдено в змінних оточення!")
|
| 461 |
+
print("Для локального запуску створіть .env файл з API ключем")
|
| 462 |
+
|
| 463 |
+
demo = create_app()
|
| 464 |
+
|
| 465 |
+
# Параметри для HuggingFace Spaces
|
| 466 |
+
is_hf_space = os.getenv("SPACE_ID") is not None
|
| 467 |
+
|
| 468 |
+
if is_hf_space:
|
| 469 |
+
# Конфігурація для HuggingFace Spaces
|
| 470 |
+
demo.launch(
|
| 471 |
+
server_name="0.0.0.0",
|
| 472 |
+
server_port=7860,
|
| 473 |
+
show_api=False,
|
| 474 |
+
show_error=True
|
| 475 |
+
)
|
| 476 |
+
else:
|
| 477 |
+
# Локальний запуск
|
| 478 |
+
demo.launch(share=True, debug=True)
|
app_config.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Конфігурація для HuggingFace Spaces деплойменту
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
# HuggingFace Spaces метадані
|
| 6 |
+
SPACE_CONFIG = {
|
| 7 |
+
"title": "🏥 Lifestyle Journey MVP",
|
| 8 |
+
"emoji": "🏥",
|
| 9 |
+
"colorFrom": "blue",
|
| 10 |
+
"colorTo": "green",
|
| 11 |
+
"sdk": "gradio",
|
| 12 |
+
"sdk_version": "4.0.0",
|
| 13 |
+
"app_file": "app.py",
|
| 14 |
+
"pinned": False,
|
| 15 |
+
"license": "mit"
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
# Gradio конфігурація
|
| 19 |
+
GRADIO_CONFIG = {
|
| 20 |
+
"theme": "soft",
|
| 21 |
+
"show_api": False,
|
| 22 |
+
"show_error": True,
|
| 23 |
+
"height": 600,
|
| 24 |
+
"title": "Lifestyle Journey MVP"
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
# API конфігурація
|
| 28 |
+
API_CONFIG = {
|
| 29 |
+
"gemini_model": "gemini-2.5-flash",
|
| 30 |
+
"temperature": 0.3,
|
| 31 |
+
"max_tokens": 2048
|
| 32 |
+
}
|
clinical_background.json
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"patient_summary": {
|
| 3 |
+
"active_problems": [
|
| 4 |
+
"Nausea (01/02/2025)",
|
| 5 |
+
"Hypokalemia (01/07/2025)",
|
| 6 |
+
"Type 2 diabetes mellitus with other diabetic neurological complication (01/07/2025)",
|
| 7 |
+
"Right leg stump pain (06/17/2024)",
|
| 8 |
+
"Foot ulcerations (10/07/2024)",
|
| 9 |
+
"Chest pain (12/22/2024)",
|
| 10 |
+
"Muscle cramps (08/19/2024)",
|
| 11 |
+
"GERD (gastroesophageal reflux disease) (08/19/2024)"
|
| 12 |
+
],
|
| 13 |
+
"past_medical_history": [
|
| 14 |
+
"Type 2 diabetes w diabetic peripheral angiopath w/o gangrene",
|
| 15 |
+
"Essential (primary) hypertension",
|
| 16 |
+
"Hyperlipidemia, unspecified",
|
| 17 |
+
"Bipolar disorder, unspecified",
|
| 18 |
+
"Attention-deficit hyperactivity disorder, unspecified type",
|
| 19 |
+
"Gastro-esophageal reflux disease without esophagitis",
|
| 20 |
+
"PVD",
|
| 21 |
+
"Osteomyelitis",
|
| 22 |
+
"OSA",
|
| 23 |
+
"Diabetic neuropathy",
|
| 24 |
+
"Personality disorder in adult (06/28/2016)",
|
| 25 |
+
"Bipolar disorder in remission (CMS/HCC) (02/04/2016)",
|
| 26 |
+
"GAD (generalized anxiety disorder) (10/30/2015)",
|
| 27 |
+
"OCD (obsessive compulsive disorder) (10/30/2015)",
|
| 28 |
+
"Reflux esophagitis (10/30/2015)",
|
| 29 |
+
"Gastritis (10/30/2015)",
|
| 30 |
+
"Dysphagia (10/30/2015)",
|
| 31 |
+
"ADHD (attention deficit hyperactivity disorder), inattentive type (10/30/2015)",
|
| 32 |
+
"Diabetic ulcer with osteomyelitis (08/21/2020)",
|
| 33 |
+
"Low back pain, MVA (10/10/2012)",
|
| 34 |
+
"Muscle spasm of back",
|
| 35 |
+
"Diabetic foot ulcer associated with type 2 diabetes mellitus",
|
| 36 |
+
"Right below knee amputation (10/04/2022)",
|
| 37 |
+
"Knee, arthroscopic, Rt (2009)",
|
| 38 |
+
"Umbilical herniorrhaphy (2009)",
|
| 39 |
+
"Tonsillectomy",
|
| 40 |
+
"Hernia repair (09/22/2020)",
|
| 41 |
+
"Foot surgery (09/22/2020)"
|
| 42 |
+
],
|
| 43 |
+
"current_medications": [
|
| 44 |
+
"Amlodipine - 5 mg - tablet - Once a day",
|
| 45 |
+
"Acetaminophen - 325 MG - Tablet - as needed Orally every 4 hrs",
|
| 46 |
+
"busPIRone HCl - 30 MG - Tablet - 2 times a day",
|
| 47 |
+
"CPAP Machine - Machine - as directed nightly",
|
| 48 |
+
"Cyclobenzaprine HCl - 10 MG - Tablet - 3 times a day prn",
|
| 49 |
+
"Dexcom G6 Receiver - Device - as directed",
|
| 50 |
+
"Dexcom G6 Sensor - Device - as directed",
|
| 51 |
+
"Dexcom G6 Transmitter - Miscellaneous - as directed",
|
| 52 |
+
"EPINEPHrine - 0.3 MG/0.3ML - Solution Auto-injector - as directed Injection once",
|
| 53 |
+
"Famotidine - 40 MG - Tablet - 1 tablet at bedtime Orally Once a day",
|
| 54 |
+
"Ferrous Sulfate - 325 (65 Fe) MG - Tablet - 1 tablet Orally Once a day",
|
| 55 |
+
"hydrOXYzine Pamoate - 50 MG - Capsule - 1 cap(s) orally qhs",
|
| 56 |
+
"LaMICtal - 200 MG - Tablet - 1 tab orally Once a day",
|
| 57 |
+
"Magnesium Oxide - 500 MG - Tablet - as directed Orally",
|
| 58 |
+
"Montelukast Sodium - 10 MG - Tablet - 1 tablet Orally Once a day",
|
| 59 |
+
"NovoLOG - 100 UNIT/ML - Solution - as directed Injection",
|
| 60 |
+
"Omeprazole - 40 MG - Capsule Delayed Release - 1 capsule 30 minutes before morning meal Orally Once a day",
|
| 61 |
+
"Ondansetron HCl - 8 MG - Tablet - 1 tablet as needed Orally three times a day As needed",
|
| 62 |
+
"Ozempic - 2 MG/DOSE - Solution Pen-injector - INJECT 2 MG SUBCUTANEOUSLY EVERY 7 DAYS Subcutaneous",
|
| 63 |
+
"Pen Needles - 31G X 5 MM - Miscellaneous - 1 SQ bid",
|
| 64 |
+
"Potassium Chloride ER - 10 MEQ - Capsule Extended Release - 1 capsule with food Orally Twice a day (Started 01/07/2025, replacing tablet form)",
|
| 65 |
+
"Ritalin - 20 MG - Tablet - 2 times a day",
|
| 66 |
+
"Rosuvastatin Calcium - 20 MG - Tablet - 1 tab(s) orally once a day",
|
| 67 |
+
"Spironolactone - 100 MG - Tablet - 1 tablet Orally Once a day",
|
| 68 |
+
"Fluticasone Propionate - 50 MCG/ACT - Suspension - 1 spray in each nostril Nasally bid prn",
|
| 69 |
+
"Metoclopramide HCl - 10 MG - Tablet - 1 tablet before meals, Orally, Twice a day (Started 01/07/2025)"
|
| 70 |
+
],
|
| 71 |
+
"allergies": "Clindamycin: sob - Allergy. No known allergies"
|
| 72 |
+
},
|
| 73 |
+
"vital_signs_and_measurements": [
|
| 74 |
+
"Blood Pressure: 148/98 (01/07/2025)",
|
| 75 |
+
"Blood Pressure Other: 154/106 (01/07/2025)",
|
| 76 |
+
"Height: 1.805 m (71.1\") (01/07/2025)",
|
| 77 |
+
"Weight: 109.8 kg (242 lb) (01/07/2025)",
|
| 78 |
+
"BMI: 33.65 kg/m² (01/07/2025)",
|
| 79 |
+
"Temperature: 97.3 (01/07/2025)",
|
| 80 |
+
"Heart Rate: 92 (01/07/2025)",
|
| 81 |
+
"Respiratory Rate: 16 (01/07/2025)"
|
| 82 |
+
],
|
| 83 |
+
"laboratory_results": [
|
| 84 |
+
"POTASSIUM - 3.3 mmol/L (12/22/2024)"
|
| 85 |
+
],
|
| 86 |
+
"imaging_studies_and_diagnostic_procedures": [
|
| 87 |
+
"XR chest 1 view: No acute cardiopulmonary process. - 12/22/2024",
|
| 88 |
+
"ECG 12 lead EKG: sinus rhythm with left axis deviation with no ST elevation or abnormal T wave inversion. Similar compared to prior EKG from 8/11/2023. - 12/22/2024",
|
| 89 |
+
"ECG 12 lead EKG: sinus rhythm with left axis deviation with no ST elevation. Artifact in lead II. No significant changes compared to EKG earlier in the day. - 12/22/2024",
|
| 90 |
+
"ECG 12 Lead: Sinus rhythm, left axis deviation, RSR' in V1 or V2, right VCD or RVH, Baseline wander in lead(s) V3 (12/22/2024)",
|
| 91 |
+
"ECG: Sinus rhythm at 82 bpm. First-degree AV block. Axis -62 degrees. No ST elevations or depressions. (12/20/24)",
|
| 92 |
+
"ECG 12 lead: Sinus rhythm, RSR' in V1 or V2, right VCD or RVH, Inferior infarct, old, Lateral leads are also involved (12/22/24)",
|
| 93 |
+
"ECG 12 lead: Sinus rhythm, Left axis deviation, RSR'in V1 or V2, right VCD or RVH, Baseline wander in lead(s) V3 (12/22/24)"
|
| 94 |
+
],
|
| 95 |
+
"assessment_and_plan": "On 01/07/2025, Jeremy presented for an ER follow-up due to vomiting on 12/20/24 and chest pain on 12/22/24. He continues to experience shaking, cramping, and nausea. His potassium level was low at 3.3 on 12/20/24. The plan includes stopping Potassium Chloride ER Tablet Extended Release and starting Potassium Chloride ER Capsule Extended Release, 10 MEQ, twice a day. A potassium serum lab is ordered. Metoclopramide HCl 10 MG tablet twice a day before meals was started for nausea. Ondansetron HCl 8 MG tablet three times a day as needed was refilled. Follow up is scheduled as needed for acute issues.",
|
| 96 |
+
"critical_alerts": [
|
| 97 |
+
"Life endangering medical noncompliance (03/06/2023)"
|
| 98 |
+
],
|
| 99 |
+
"social_history": {
|
| 100 |
+
"smoking_status": "Never",
|
| 101 |
+
"alcohol_use": "Yes, 2-3 times a week",
|
| 102 |
+
"caffeine_use": {
|
| 103 |
+
"soda": "2-3 per day",
|
| 104 |
+
"energy_drinks": "1 per day"
|
| 105 |
+
}
|
| 106 |
+
},
|
| 107 |
+
"care_management": [
|
| 108 |
+
"Nephrology continues to follow for AKI.",
|
| 109 |
+
"Patient from home independent with family and follows at wound care center outpatient.",
|
| 110 |
+
"Jessica Lea Falvo Lang, MD is the patient's PCP.",
|
| 111 |
+
"Dishon Kamwesa, APRN.CNP of Hartville Family Physicians is the patient's PCP.",
|
| 112 |
+
"May be good candidate for Care Management.",
|
| 113 |
+
"Kathy Fox is the CHCI Care Manager, Date care manager notified: 05/09/2022."
|
| 114 |
+
],
|
| 115 |
+
"recent_clinical_events_and_encounters": [
|
| 116 |
+
"2025-01-07: ER follow-up with Dishon Kamwesa, NP-C for vomiting on 12/20/24 and chest pain on 12/22/24. Potassium Chloride ER Tablet was stopped and Potassium Chloride ER Capsule was started. Metoclopramide was started for nausea and Ondansetron was refilled.",
|
| 117 |
+
"2025-01-02: Telephone encounter with Weiss Clinical Phone Triage LPN, Samantha. Patient reports nausea and vomiting and requests medication. ER follow up scheduled for 2025-01-07. Ondansetron 8 mg tablet TID prn prescribed.",
|
| 118 |
+
"2024-12-25: University Hospitals encounter. Follow-up with Jessica Lee Falvo Lang, MD scheduled as soon as possible for a visit in 3 days.",
|
| 119 |
+
"2024-12-23: Telephone encounter with Turkall ED Transition of Care Coordinator, Sharon A for ER TOC UH 12/22/24 Chest pain. Reports scanned in. Provider: Falvo Lang, Jessica L. LM to see how pt. is doing and if needs a F/U appt. WEB message sent.",
|
| 120 |
+
"2024-12-22: Emergency department visit for chest pain and shortness of breath. Discharged home with referral to outpatient stress test.",
|
| 121 |
+
"2024-12-20: Emergency department visit at Aultman Hospital for vomiting. Discharged home with prescriptions for ondansetron, promethazine, and metoclopramide. Follow up with Jessica Falvo-Lang, MD in 2-4 days."
|
| 122 |
+
]
|
| 123 |
+
}
|
diagram/complete-flow-diagram.mermaid
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flowchart TB
|
| 2 |
+
%% Стилізація
|
| 3 |
+
classDef new fill:#fff3e0,stroke:#ff9800,stroke-width:3px
|
| 4 |
+
classDef existing fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
|
| 5 |
+
classDef critical fill:#ffebee,stroke:#f44336,stroke-width:3px
|
| 6 |
+
classDef success fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
|
| 7 |
+
|
| 8 |
+
Start([Повідомлення пацієнта])
|
| 9 |
+
Start --> L0_Check
|
| 10 |
+
Start --> L1_Medical
|
| 11 |
+
Start --> MRE
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
%% MRE
|
| 15 |
+
MRE["MRE"]:::existing
|
| 16 |
+
MRE --> |"MRE Response"|Medical_Flow
|
| 17 |
+
%% Level 0 Decision Block
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
L0_Check["LLM Lifestyle Detector"]:::new
|
| 21 |
+
|
| 22 |
+
%% L0_Check -->|"❌ NO<br/>Medical/Undefined"| L1_Medical
|
| 23 |
+
L0_Check -->|"✅ YES/ ❌ NO<br/>Lifestyle Trigger"| Post_Check
|
| 24 |
+
%% L0_Check -->|"⚠️ MIXED<br/>Symptoms + Lifestyle"| L1_Mixed
|
| 25 |
+
|
| 26 |
+
%% %% Safety Pre-check for Lifestyle
|
| 27 |
+
%% Safety_Pre{"Quick Safety<br/>Check"}:::critical
|
| 28 |
+
%% Safety_Pre -->|"Red flags"| L1_Medical
|
| 29 |
+
%% Safety_Pre -->|"Safe"| Lifestyle_Mode
|
| 30 |
+
|
| 31 |
+
%% Medical Path (Level 1)
|
| 32 |
+
L1_Medical["LLM First prompt <br/>(Suggested message + Escalation)"]:::existing
|
| 33 |
+
L1_Medical -->|"Suggested message"| Medical_Flow
|
| 34 |
+
L1_Medical -->|"🚨 ESCALATION=TRUE/FALSE"| Post_Check
|
| 35 |
+
|
| 36 |
+
%% Mixed Path (Level 1)
|
| 37 |
+
%% L1_Mixed{"Level 1<br/>Symptom Assessment<br/>[EXISTING]"}:::existing
|
| 38 |
+
%% L1_Mixed -->|"🚨 URGENT"| Provider_Alert
|
| 39 |
+
%% L1_Mixed -->|"✅ NON-URGENT"| Lifestyle_After_Clear
|
| 40 |
+
|
| 41 |
+
%% Provider Escalation
|
| 42 |
+
%% Provider_Alert["🚨 PROVIDER ALERT<br/>Urgent Response"]:::critical
|
| 43 |
+
%% Provider_Alert --> End_Medical
|
| 44 |
+
|
| 45 |
+
%% Post Level 1 Check
|
| 46 |
+
Post_Check{"Lifestyle<br/>Need and Possible?"}:::new
|
| 47 |
+
Post_Check -->|"NO"| Medical_Flow
|
| 48 |
+
Post_Check -->|"YES"| Lifestyle_Mode
|
| 49 |
+
|
| 50 |
+
%% Medical Flow
|
| 51 |
+
Medical_Flow["LLM Second Prompt<br/>Recheck MRE"]:::existing
|
| 52 |
+
Medical_Flow --> End_Medical
|
| 53 |
+
|
| 54 |
+
%% Lifestyle After Medical Clearance
|
| 55 |
+
%% Lifestyle_After_Clear["✅ Medical Cleared<br/>Safe for Lifestyle"]:::success
|
| 56 |
+
%% Lifestyle_After_Clear --> Lifestyle_Mode
|
| 57 |
+
|
| 58 |
+
%% Lifestyle Mode Activation
|
| 59 |
+
Lifestyle_Mode["🌟 LIFESTYLE MODE ACTIVE"]:::new
|
| 60 |
+
Lifestyle_Mode --> Load_Profile
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
Load_Profile["📊 Load Full<br/>Patient Profile"]:::new
|
| 64 |
+
Load_Profile --> Lifestyle_LLM
|
| 65 |
+
|
| 66 |
+
Lifestyle_LLM["💚 Lifestyle LLM<br/>Coaching Response"]:::new
|
| 67 |
+
Lifestyle_LLM --> Update_Profile
|
| 68 |
+
|
| 69 |
+
Update_Profile["🔄 Update Profile<br/>Track Progress"]:::new
|
| 70 |
+
Update_Profile --> Session_Check
|
| 71 |
+
|
| 72 |
+
Session_Check{"Continue<br/>Session?"}:::new
|
| 73 |
+
Session_Check -->|"YES"| Lifestyle_LLM
|
| 74 |
+
Session_Check -->|"NO"| End_Session
|
| 75 |
+
|
| 76 |
+
End_Session["Session End<br/>✅ CE Re-enabled"]:::new
|
| 77 |
+
End_Session --> End_Lifestyle
|
| 78 |
+
|
| 79 |
+
%% End Points
|
| 80 |
+
End_Medical[["LLM Response<br/>to Patient"]]:::existing
|
| 81 |
+
End_Lifestyle[["Lifestyle Response<br/>to Patient"]]:::success
|
| 82 |
+
|
diagram/lifestyle-activation-logic.mermaid
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flowchart TD
|
| 2 |
+
%% Стилізація
|
| 3 |
+
classDef trigger fill:#e8f5e9,stroke:#4caf50,stroke-width:3px
|
| 4 |
+
classDef classifier fill:#fff3e0,stroke:#ff9800,stroke-width:2px
|
| 5 |
+
classDef prompt fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
|
| 6 |
+
classDef decision fill:#ffebee,stroke:#f44336,stroke-width:2px
|
| 7 |
+
classDef lifestyle fill:#f3e5f5,stroke:#9c27b0,stroke-width:3px
|
| 8 |
+
|
| 9 |
+
%% Три способи активації
|
| 10 |
+
Start([Start])
|
| 11 |
+
Start --> CheckTriggers
|
| 12 |
+
|
| 13 |
+
CheckTriggers{Checking triggers}
|
| 14 |
+
|
| 15 |
+
%% ТРИГЕР 1: Scheduled
|
| 16 |
+
CheckTriggers -->|"📅 Scheduled"| Trigger1["1️⃣ MRE Scheduled Basis<br/>(e.g., once per week)"]:::trigger
|
| 17 |
+
Trigger1 --> LifestylePromptDirect1[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 18 |
+
|
| 19 |
+
%% ТРИГЕР 2: Follow-up
|
| 20 |
+
CheckTriggers -->|"🔄 Follow-up"| Trigger2["2️⃣ LLM requested follow-up<br/>in previous session"]:::trigger
|
| 21 |
+
Trigger2 --> LifestylePromptDirect2[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 22 |
+
|
| 23 |
+
%% ТРИГЕР 3: Patient Initiated
|
| 24 |
+
CheckTriggers -->|"💬 Message"| Trigger3["3️⃣ Patient message"]:::trigger
|
| 25 |
+
|
| 26 |
+
%% Детальна логіка для patient-initiated
|
| 27 |
+
Trigger3 --> Step3_1["3.1 Check Lifestyle Trigger<br/>(keywords, patterns)"]:::classifier
|
| 28 |
+
|
| 29 |
+
Step3_1 -->|"NO lifestyle markers"| RegularFlow["Regular Medical Flow"]
|
| 30 |
+
Step3_1 -->|"YES lifestyle markers"| Step3_2
|
| 31 |
+
|
| 32 |
+
Step3_2["3.2 Gemini Classifier<br/>(type of MRE/CE message)"]:::classifier
|
| 33 |
+
Step3_2 --> Step3_3
|
| 34 |
+
|
| 35 |
+
Step3_3["3.3 FIRST PROMPT<br/>Generate: Suggested message + Escalation flag"]:::prompt
|
| 36 |
+
Step3_3 --> EscalationCheck
|
| 37 |
+
|
| 38 |
+
EscalationCheck{"3.4 Check Escalation Flag"}:::decision
|
| 39 |
+
|
| 40 |
+
%% Path 4.1: Escalation = TRUE
|
| 41 |
+
EscalationCheck -->|"🚨 Escalation = TRUE"| Path4_1["4.1 Regular Medical Prompts<br/>+ Triage"]:::prompt
|
| 42 |
+
Path4_1 --> AfterTriage
|
| 43 |
+
|
| 44 |
+
AfterTriage{"After Triage:<br/>Is lifestyle still relevant?"}:::decision
|
| 45 |
+
AfterTriage -->|"YES"| SetCheckIn["Set next check-in time<br/>OR activate immediately"]
|
| 46 |
+
AfterTriage -->|"NO"| EndMedical["Continue Medical Flow"]
|
| 47 |
+
|
| 48 |
+
SetCheckIn -.->|"Schedule next<br/>lifestyle session"| Trigger2
|
| 49 |
+
SetCheckIn -->|"Immediate"| LifestylePromptAfterTriage[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
%% Path 4.2: Escalation = FALSE + Lifestyle = TRUE
|
| 53 |
+
EscalationCheck -->|"✅ No Escalation +<br/>Lifestyle Trigger"| Path4_2["4.2 Direct to Lifestyle"]
|
| 54 |
+
Path4_2 --> LifestylePromptDirect3[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 55 |
+
|
| 56 |
+
%% Lifestyle Prompt Logic
|
| 57 |
+
LifestylePromptDirect1 --> ProfileCheck
|
| 58 |
+
LifestylePromptDirect2 --> ProfileCheck
|
| 59 |
+
LifestylePromptDirect3 --> ProfileCheck
|
| 60 |
+
LifestylePromptAfterTriage --> ProfileCheck
|
| 61 |
+
|
| 62 |
+
ProfileCheck{"Patient Profile<br/>Exists?"}:::decision
|
| 63 |
+
|
| 64 |
+
ProfileCheck -->|"❌ NO Profile"| GatherInfo["📋 GATHER INFORMATION<br/>• Limitations<br/>• Preferences<br/>• Goals<br/>• Medical conditions"]:::prompt
|
| 65 |
+
ProfileCheck -->|"✅ HAS Profile"| LifestyleCoaching["💚 LIFESTYLE COACHING<br/>Based on existing profile"]:::lifestyle
|
| 66 |
+
|
| 67 |
+
GatherInfo --> CreateProfile["Create Initial<br/>Patient Profile"]
|
| 68 |
+
CreateProfile --> LifestyleCoaching
|
| 69 |
+
|
| 70 |
+
LifestyleCoaching --> UpdateProfile["🔄 Update Profile<br/>with session data"]
|
| 71 |
+
UpdateProfile --> SessionEnd["Session Complete"]
|
| 72 |
+
|
diagram/lifestyle-activation-logic.txt
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flowchart TD
|
| 2 |
+
%% Стилізація
|
| 3 |
+
classDef trigger fill:#e8f5e9,stroke:#4caf50,stroke-width:3px
|
| 4 |
+
classDef classifier fill:#fff3e0,stroke:#ff9800,stroke-width:2px
|
| 5 |
+
classDef prompt fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
|
| 6 |
+
classDef decision fill:#ffebee,stroke:#f44336,stroke-width:2px
|
| 7 |
+
classDef lifestyle fill:#f3e5f5,stroke:#9c27b0,stroke-width:3px
|
| 8 |
+
|
| 9 |
+
%% Три способи активації
|
| 10 |
+
Start([Start])
|
| 11 |
+
Start --> CheckTriggers
|
| 12 |
+
|
| 13 |
+
CheckTriggers{Checking triggers}
|
| 14 |
+
|
| 15 |
+
%% ТРИГЕР 1: Scheduled
|
| 16 |
+
CheckTriggers -->|"📅 Scheduled"| Trigger1["1️⃣ MRE Scheduled Basis<br/>(e.g., once per week)"]:::trigger
|
| 17 |
+
Trigger1 --> LifestylePromptDirect1[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 18 |
+
|
| 19 |
+
%% ТРИГЕР 2: Follow-up
|
| 20 |
+
CheckTriggers -->|"🔄 Follow-up"| Trigger2["2️⃣ LLM requested follow-up<br/>in previous session"]:::trigger
|
| 21 |
+
Trigger2 --> LifestylePromptDirect2[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 22 |
+
|
| 23 |
+
%% ТРИГЕР 3: Patient Initiated
|
| 24 |
+
CheckTriggers -->|"💬 Message"| Trigger3["3️⃣ Patient message"]:::trigger
|
| 25 |
+
|
| 26 |
+
%% Детальна логіка для patient-initiated
|
| 27 |
+
Trigger3 --> Step3_1["3.1 Check Lifestyle Trigger<br/>(keywords, patterns)"]:::classifier
|
| 28 |
+
|
| 29 |
+
Step3_1 -->|"NO lifestyle markers"| RegularFlow["Regular Medical Flow"]
|
| 30 |
+
Step3_1 -->|"YES lifestyle markers"| Step3_2
|
| 31 |
+
|
| 32 |
+
Step3_2["3.2 Gemini Classifier<br/>(type of MRE/CE message)"]:::classifier
|
| 33 |
+
Step3_2 --> Step3_3
|
| 34 |
+
|
| 35 |
+
Step3_3["3.3 FIRST PROMPT<br/>Generate: Suggested message + Escalation flag"]:::prompt
|
| 36 |
+
Step3_3 --> EscalationCheck
|
| 37 |
+
|
| 38 |
+
EscalationCheck{"3.4 Check Escalation Flag"}:::decision
|
| 39 |
+
|
| 40 |
+
%% Path 4.1: Escalation = TRUE
|
| 41 |
+
EscalationCheck -->|"🚨 Escalation = TRUE"| Path4_1["4.1 Regular Medical Prompts<br/>+ Triage"]:::prompt
|
| 42 |
+
Path4_1 --> AfterTriage
|
| 43 |
+
|
| 44 |
+
AfterTriage{"After Triage:<br/>Is lifestyle still relevant?"}:::decision
|
| 45 |
+
AfterTriage -->|"YES"| SetCheckIn["Set next check-in time<br/>OR activate immediately"]
|
| 46 |
+
AfterTriage -->|"NO"| EndMedical["Continue Medical Flow"]
|
| 47 |
+
|
| 48 |
+
SetCheckIn -.->|"Schedule next<br/>lifestyle session"| Trigger2
|
| 49 |
+
SetCheckIn -->|"Immediate"| LifestylePromptAfterTriage[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
%% Path 4.2: Escalation = FALSE + Lifestyle = TRUE
|
| 53 |
+
EscalationCheck -->|"✅ No Escalation +<br/>Lifestyle Trigger"| Path4_2["4.2 Direct to Lifestyle"]
|
| 54 |
+
Path4_2 --> LifestylePromptDirect3[["💚 LIFESTYLE PROMPT"]]:::lifestyle
|
| 55 |
+
|
| 56 |
+
%% Lifestyle Prompt Logic
|
| 57 |
+
LifestylePromptDirect1 --> ProfileCheck
|
| 58 |
+
LifestylePromptDirect2 --> ProfileCheck
|
| 59 |
+
LifestylePromptDirect3 --> ProfileCheck
|
| 60 |
+
LifestylePromptAfterTriage --> ProfileCheck
|
| 61 |
+
|
| 62 |
+
ProfileCheck{"Patient Profile<br/>Exists?"}:::decision
|
| 63 |
+
|
| 64 |
+
ProfileCheck -->|"❌ NO Profile"| GatherInfo["📋 GATHER INFORMATION<br/>• Limitations<br/>• Preferences<br/>• Goals<br/>• Medical conditions"]:::prompt
|
| 65 |
+
ProfileCheck -->|"✅ HAS Profile"| LifestyleCoaching["💚 LIFESTYLE COACHING<br/>Based on existing profile"]:::lifestyle
|
| 66 |
+
|
| 67 |
+
GatherInfo --> CreateProfile["Create Initial<br/>Patient Profile"]
|
| 68 |
+
CreateProfile --> LifestyleCoaching
|
| 69 |
+
|
| 70 |
+
LifestyleCoaching --> UpdateProfile["🔄 Update Profile<br/>with session data"]
|
| 71 |
+
UpdateProfile --> SessionEnd["Session Complete"]
|
| 72 |
+
|
diagram/lifestyle-architecture.mermaid
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flowchart TD
|
| 2 |
+
%% Стилізація
|
| 3 |
+
classDef patient fill:#e8f5e9,stroke:#4caf50,stroke-width:3px
|
| 4 |
+
classDef existing fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
|
| 5 |
+
classDef new fill:#fff3e0,stroke:#ff9800,stroke-width:2px
|
| 6 |
+
classDef data fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
|
| 7 |
+
|
| 8 |
+
%% Вхідні компоненти
|
| 9 |
+
Patient[("👤 ПАЦІЄНТ")]:::patient
|
| 10 |
+
DB[("🗄️ БАЗА ДАНИХ<br/>Clinical Background<br/>Історія чатів<br/>Patient Profile")]:::data
|
| 11 |
+
|
| 12 |
+
%% Детектор режиму
|
| 13 |
+
Detector{{"🔍 LLM-ДЕТЕКТОР<br/>Аналіз контексту<br/><b>[НОВИЙ]</b>"}}:::new
|
| 14 |
+
|
| 15 |
+
Patient -->|Повідомлення| Detector
|
| 16 |
+
DB -->|Контекст| Detector
|
| 17 |
+
|
| 18 |
+
%% Розгалуження
|
| 19 |
+
Detector -->|URGENT/REGULAR| MedicalFlow
|
| 20 |
+
Detector -->|LIFESTYLE| LifestyleFlow
|
| 21 |
+
|
| 22 |
+
%% Медичний потік (існуючий)
|
| 23 |
+
subgraph MedicalFlow["⚕️ МЕДИЧНИЙ ПОТІК [ІСНУЮЧИЙ]"]
|
| 24 |
+
direction LR
|
| 25 |
+
MRE["MRE<br/>Rule Engine"]:::existing
|
| 26 |
+
Assistant["LLM-Асистент<br/>Валідатор"]:::existing
|
| 27 |
+
MRE --> Assistant
|
| 28 |
+
end
|
| 29 |
+
|
| 30 |
+
%% Lifestyle потік (новий)
|
| 31 |
+
subgraph LifestyleFlow["💚 LIFESTYLE ПОТІК [НОВИЙ]"]
|
| 32 |
+
direction LR
|
| 33 |
+
LifestyleLLM["Lifestyle LLM<br/>Коучинг"]:::new
|
| 34 |
+
ProfileUpdate["Оновлення<br/>профілю"]:::new
|
| 35 |
+
LifestyleLLM --> ProfileUpdate
|
| 36 |
+
end
|
| 37 |
+
|
| 38 |
+
%% Відповідь
|
| 39 |
+
MedicalFlow -->|Медична відповідь| CE
|
| 40 |
+
LifestyleFlow -->|Коучинг відповідь| CE
|
| 41 |
+
CE["📱 CE/Пацієнт"]:::patient
|
| 42 |
+
|
| 43 |
+
%% Зворотній зв'язок
|
| 44 |
+
ProfileUpdate -.->|Оновлення| DB
|
| 45 |
+
Assistant -.->|Логування| DB
|
diagram/profile-lifecycle.mermaid
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flowchart TD
|
| 2 |
+
Start([Новий пацієнт])
|
| 3 |
+
Start --> InitialData
|
| 4 |
+
|
| 5 |
+
%% ЕТАП 1: ІНІЦІАЛІЗАЦІЯ
|
| 6 |
+
subgraph Init["🚀 ЕТАП 1: ІНІЦІАЛІЗАЦІЯ ПРОФІЛЮ"]
|
| 7 |
+
InitialData["📊 Збір базових даних<br/>• Clinical Background<br/>• Медикаменти<br/>• Діагнози"]
|
| 8 |
+
InitialData --> FirstSession
|
| 9 |
+
|
| 10 |
+
FirstSession["💬 Перша ознайомча сесія<br/>• Пояснення мети<br/>• Оцінка готовності<br/>• Базові питання"]
|
| 11 |
+
FirstSession --> Assessment
|
| 12 |
+
|
| 13 |
+
Assessment["📋 Детальна оцінка<br/>• Фізичні можливості<br/>• Харчові звички<br/>• Психосоціальні фактори<br/>• Мотивація"]
|
| 14 |
+
end
|
| 15 |
+
|
| 16 |
+
Assessment --> CreateProfile
|
| 17 |
+
|
| 18 |
+
%% ЕТАП 2: СТВОРЕННЯ
|
| 19 |
+
CreateProfile["🔨 Формування профілю v1.0<br/>• Автоматичне заповнення з медичних даних<br/>• Додавання відповідей з оцінки<br/>• Встановлення безпечних defaults"]
|
| 20 |
+
|
| 21 |
+
CreateProfile --> Validation
|
| 22 |
+
|
| 23 |
+
%% ЕТАП 3: ВАЛІДАЦІЯ
|
| 24 |
+
subgraph Valid["✅ ВАЛІДАЦІЯ ТА БЕЗПЕКА"]
|
| 25 |
+
Validation{Перевірка на<br/>протиріччя}
|
| 26 |
+
Validation -->|Знайдено| Clarify["🔍 Уточнення з пацієнтом<br/>або медичною командою"]
|
| 27 |
+
Validation -->|OK| Safety
|
| 28 |
+
Clarify --> Safety
|
| 29 |
+
|
| 30 |
+
Safety["🛡️ Перевірка безпеки<br/>• Red flags<br/>• Обмеження<br/>• Протипоказання"]
|
| 31 |
+
end
|
| 32 |
+
|
| 33 |
+
Safety --> Active
|
| 34 |
+
|
| 35 |
+
%% ЕТАП 4: АКТИВНЕ ВИКОРИСТАННЯ
|
| 36 |
+
subgraph Usage["💚 АКТИВНЕ ВИКОРИСТАННЯ"]
|
| 37 |
+
Active["📱 Профіль активний"]
|
| 38 |
+
Active --> Session["Lifestyle сесія"]
|
| 39 |
+
Session --> Track["📈 Трекінг<br/>• Виконання плану<br/>• Симптоми<br/>• Прогрес"]
|
| 40 |
+
Track --> Update{Потрібне<br/>оновлення?}
|
| 41 |
+
end
|
| 42 |
+
|
| 43 |
+
%% ЕТАП 5: ОНОВЛЕННЯ
|
| 44 |
+
Update -->|Так| UpdateFlow
|
| 45 |
+
Update -->|Ні| Session
|
| 46 |
+
|
| 47 |
+
subgraph UpdateFlow["🔄 ОНОВЛЕННЯ ПРОФІЛЮ"]
|
| 48 |
+
UpdateType{Тип оновлення}
|
| 49 |
+
UpdateType -->|Прогрес| ProgressUpdate["📊 Оновлення прогресу<br/>• Нові досягнення<br/>• Зміна можливостей<br/>• Коригування цілей"]
|
| 50 |
+
UpdateType -->|Медичне| MedicalUpdate["⚕️ Медичні зміни<br/>• Нові діагнози<br/>• Зміна ліків<br/>• Нові обмеження"]
|
| 51 |
+
UpdateType -->|Поведінкове| BehaviorUpdate["🧠 Зміни поведінки<br/>• Нові бар'єри<br/>• Зміна мотивації<br/>• Нові преференції"]
|
| 52 |
+
|
| 53 |
+
ProgressUpdate --> Version
|
| 54 |
+
MedicalUpdate --> Version
|
| 55 |
+
BehaviorUpdate --> Version
|
| 56 |
+
|
| 57 |
+
Version["📝 Створення нової версії<br/>• Збереження історії<br/>• Логування змін<br/>• Timestamp"]
|
| 58 |
+
end
|
| 59 |
+
|
| 60 |
+
Version --> Safety
|
| 61 |
+
|
| 62 |
+
%% Додаткові процеси
|
| 63 |
+
subgraph Review["🔍 ПЕРІОДИЧНИЙ REVIEW"]
|
| 64 |
+
Monthly["📅 Щомісячний аналіз<br/>• Ефективність підходу<br/>• Adherence rate<br/>• Необхідність змін"]
|
| 65 |
+
Quarterly["📊 Квартальний звіт<br/>• Загальний прогрес<br/>• Досягнення цілей<br/>• Рекомендації"]
|
| 66 |
+
end
|
| 67 |
+
|
| 68 |
+
Active -.->|Періодично| Review
|
| 69 |
+
Review -.-> UpdateFlow
|
| 70 |
+
|
| 71 |
+
style Init fill:#e8f5e9
|
| 72 |
+
style Valid fill:#fff3e0
|
| 73 |
+
style Usage fill:#e3f2fd
|
| 74 |
+
style UpdateFlow fill:#fce4ec
|
| 75 |
+
style Review fill:#f3e5f5
|
diagram/system-sequence.mermaid
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
sequenceDiagram
|
| 2 |
+
participant P as 👤 Пацієнт
|
| 3 |
+
participant D as 🔍 LLM-Детектор
|
| 4 |
+
participant DB as 🗄️ База даних
|
| 5 |
+
participant MRE as ⚕️ MRE
|
| 6 |
+
participant A as ✅ Асистент
|
| 7 |
+
participant L as 💚 Lifestyle LLM
|
| 8 |
+
participant CE as 📱 CE (Interface)
|
| 9 |
+
|
| 10 |
+
Note over P,CE: Сценарій 1: Медичне питання
|
| 11 |
+
P->>D: "Вчора був тиск 150/95"
|
| 12 |
+
D->>DB: Запит контексту
|
| 13 |
+
DB->>D: Clinical background + історія
|
| 14 |
+
D->>D: Аналіз: REGULAR
|
| 15 |
+
D->>MRE: Передача повідомлення
|
| 16 |
+
MRE->>A: Медична відповідь
|
| 17 |
+
A->>A: Валідація
|
| 18 |
+
A->>CE: Підтверджена відповідь
|
| 19 |
+
CE->>P: "Це підвищений тиск..."
|
| 20 |
+
|
| 21 |
+
Note over P,CE: Сценарій 2: Lifestyle запит
|
| 22 |
+
P->>D: "Хочу почати ходити щодня"
|
| 23 |
+
D->>DB: Запит контексту + lifestyle профіль
|
| 24 |
+
DB->>D: Дані пацієнта + обмеження
|
| 25 |
+
D->>D: Аналіз: LIFESTYLE_NEEDED
|
| 26 |
+
D->>L: Активація lifestyle режиму
|
| 27 |
+
L->>DB: Запит Patient Profile
|
| 28 |
+
DB->>L: Поточний профіль
|
| 29 |
+
L->>L: Генерація плану
|
| 30 |
+
L->>CE: Коучинг відповідь
|
| 31 |
+
CE->>P: "Чудово! Давайте почнемо з 15 хв..."
|
| 32 |
+
L->>DB: Оновлення профілю
|
| 33 |
+
|
| 34 |
+
Note over P,CE: Сценарій 3: Змішаний контекст
|
| 35 |
+
P->>D: "Втомлююсь, але хочу бути активнішим"
|
| 36 |
+
D->>DB: Запит повного контексту
|
| 37 |
+
DB->>D: Медичні дані + історія
|
| 38 |
+
D->>D: Аналіз: MIXED
|
| 39 |
+
D->>MRE: Спочатку медична перевірка
|
| 40 |
+
MRE->>A: Оцінка симптому
|
| 41 |
+
A->>D: Симптом не критичний
|
| 42 |
+
D->>L: Можна перейти до lifestyle
|
| 43 |
+
L->>CE: "Втома може бути від низької активності..."
|
| 44 |
+
CE->>P: Комбінована відповідь
|
lifestyle_profile.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"patient_name": "Serhii",
|
| 3 |
+
"patient_age": "52",
|
| 4 |
+
"conditions": [
|
| 5 |
+
"arrhythmia",
|
| 6 |
+
"hypertension"
|
| 7 |
+
],
|
| 8 |
+
"primary_goal": "Improve exercise tolerance safely to help control BP",
|
| 9 |
+
"exercise_preferences": [
|
| 10 |
+
"walking outdoors",
|
| 11 |
+
"light stretching"
|
| 12 |
+
],
|
| 13 |
+
"exercise_limitations": [
|
| 14 |
+
"avoid vigorous or high-impact activity due to arrhythmia"
|
| 15 |
+
],
|
| 16 |
+
"dietary_notes": [
|
| 17 |
+
"low sodium",
|
| 18 |
+
"moderate carb intake"
|
| 19 |
+
],
|
| 20 |
+
"personal_preferences": [
|
| 21 |
+
"prefers gradual changes",
|
| 22 |
+
"wants to feel in control of pace"
|
| 23 |
+
],
|
| 24 |
+
"journey_summary": "Patient expressed interest in increasing physical activity. Started with 15-min walks 3x/week and tolerated well.",
|
| 25 |
+
"last_session_summary": "Encouraged to continue 15-min walks; agreed to assess symptoms before progressing.",
|
| 26 |
+
"next_check_in": "not set"
|
| 27 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Core dependencies for Lifestyle Journey MVP
|
| 2 |
+
gradio>=4.0.0
|
| 3 |
+
python-dotenv>=1.0.0
|
| 4 |
+
google-genai>=0.5.0
|
| 5 |
+
|
| 6 |
+
# Data handling
|
| 7 |
+
typing-extensions>=4.5.0
|
| 8 |
+
|
| 9 |
+
# For HuggingFace Spaces compatibility
|
| 10 |
+
huggingface-hub>=0.16.0
|