- TTS: xtts-v2 integration with voice cloning support
- Document: docling integration for PDF/DOCX/PPTX processing
- Memory Service: added /facts/upsert, /facts/{key}, /facts endpoints
- Added required dependencies (TTS, docling)
306 lines
11 KiB
Markdown
306 lines
11 KiB
Markdown
# 🔍 Як працює НОДА2 - Детальний розбір
|
||
|
||
**Дата:** 2026-01-12
|
||
**Статус:** ✅ Повний аналіз роботи НОДА2
|
||
|
||
---
|
||
|
||
## 🏗️ Архітектура НОДА2
|
||
|
||
### Основні компоненти
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ НОДА2 (MacBook M4 Max) │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ Router │──────│ Swapper │ │
|
||
│ │ (9102) │ │ (8890) │ │
|
||
│ └──────┬────────┘ └──────┬──────┘ │
|
||
│ │ │ │
|
||
│ │ │ │
|
||
│ │ ┌────────▼────────┐ │
|
||
│ │ │ Ollama │ │
|
||
│ │ │ (host:11434) │ │
|
||
│ │ └─────────────────┘ │
|
||
│ │ │
|
||
│ └──────────────┬─────────────────┐ │
|
||
│ │ │ │
|
||
│ ┌─────▼─────┐ ┌─────▼─────┐ │
|
||
│ │ NATS │ │ Gateway │ │
|
||
│ │ (4222) │ │ (9300) │ │
|
||
│ └────────────┘ └────────────┘ │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Як працює Router
|
||
|
||
### Основні функції Router
|
||
|
||
1. **Маршрутизація запитів:**
|
||
- Отримує запити на порту 9102
|
||
- Аналізує запит та визначає провайдера
|
||
- Маршрутизує до відповідного сервісу
|
||
|
||
2. **Інтеграція з Swapper:**
|
||
- Перевіряє доступність Swapper через `/health`
|
||
- Завантажує моделі через `/models/{name}/load`
|
||
- Отримує список моделей через `/models`
|
||
- **Проблема:** Намагається викликати `/v1/chat/completions` (не існує)
|
||
|
||
3. **Провайдери (17 штук):**
|
||
- LLM провайдери (9 штук)
|
||
- DevTools провайдери (5 штук)
|
||
- Інші провайдери (3 штуки)
|
||
|
||
### Конфігурація Router
|
||
|
||
**Змінні середовища:**
|
||
```bash
|
||
SWAPPER_URL=http://192.168.1.33:8890 # IP адреса хоста
|
||
NATS_URL=nats://nats:4222
|
||
STT_URL=http://192.168.1.33:8895
|
||
VISION_URL=http://192.168.1.33:11434
|
||
OCR_URL=http://192.168.1.33:8896
|
||
```
|
||
|
||
**Проблема:** Використовує IP замість Docker service name
|
||
|
||
**Рекомендація:** Змінити на `http://swapper-service:8890`
|
||
|
||
---
|
||
|
||
## 🔄 Як працює Swapper
|
||
|
||
### Основні функції Swapper
|
||
|
||
1. **Динамічне завантаження моделей:**
|
||
- Завантажує моделі з Ollama за запитом
|
||
- Вивантажує моделі для звільнення пам'яті
|
||
- Управляє станом моделей (loaded/unloaded)
|
||
|
||
2. **Single-active режим:**
|
||
- Тільки одна модель активна одночасно
|
||
- Автоматичне вивантаження при завантаженні нової
|
||
- Timeout: 30 секунд для swap
|
||
|
||
3. **Інтеграція з Ollama:**
|
||
- Доступ через `host.docker.internal:11434`
|
||
- Викликає Ollama API для генерації
|
||
- Відстежує стан моделей
|
||
|
||
### API Endpoints Swapper
|
||
|
||
**Основні:**
|
||
- `GET /health` - перевірка здоров'я
|
||
- `GET /status` - статус сервісу
|
||
- `GET /models` - список моделей
|
||
- `GET /models/{name}` - інформація про модель
|
||
- `POST /models/{name}/load` - завантажити модель
|
||
- `POST /models/{name}/unload` - вивантажити модель
|
||
|
||
**Cabinet API:**
|
||
- `GET /api/cabinet/swapper/status` - статус для кабінету
|
||
- `GET /api/cabinet/swapper/models` - моделі для кабінету
|
||
- `GET /api/cabinet/swapper/metrics/summary` - метрики
|
||
|
||
**⚠️ Відсутній:** `/v1/chat/completions` (Router намагається викликати)
|
||
|
||
---
|
||
|
||
## 🔗 Інтеграція Router ↔ Swapper
|
||
|
||
### Поточна реалізація
|
||
|
||
**З коду Router (`main.py`):**
|
||
|
||
1. **Перевірка Swapper:**
|
||
```python
|
||
health_resp = await http_client.get(f"{SWAPPER_URL}/health")
|
||
```
|
||
|
||
2. **Завантаження моделі:**
|
||
```python
|
||
load_resp = await http_client.post(
|
||
f"{SWAPPER_URL}/load",
|
||
json={"model": model_name}
|
||
)
|
||
```
|
||
|
||
3. **Генерація (проблема):**
|
||
```python
|
||
# Router намагається викликати:
|
||
generate_resp = await http_client.post(
|
||
f"{VISION_URL}/api/generate", # Прямо до Ollama!
|
||
...
|
||
)
|
||
```
|
||
|
||
4. **Отримання моделей:**
|
||
```python
|
||
resp = await http_client.get(f"{SWAPPER_URL}/models")
|
||
```
|
||
|
||
### Проблема інтеграції
|
||
|
||
**Що не працює:**
|
||
- Router намагається викликати `/v1/chat/completions` на Swapper
|
||
- Swapper не має такого endpoint
|
||
- Router використовує `VISION_URL` для генерації (прямо до Ollama)
|
||
|
||
**Що працює:**
|
||
- ✅ Health check
|
||
- ✅ Завантаження моделей
|
||
- ✅ Отримання списку моделей
|
||
- ❌ Генерація через Swapper (Router йде напряму до Ollama)
|
||
|
||
---
|
||
|
||
## 🔄 Потік запиту (поточна реалізація)
|
||
|
||
### Варіант 1: Router → Ollama (прямий)
|
||
|
||
```
|
||
Клієнт
|
||
↓ POST /route
|
||
Router (9102)
|
||
↓ [визначає модель]
|
||
↓ POST /api/generate
|
||
Ollama (host:11434)
|
||
↓ [генерує]
|
||
Router
|
||
↓
|
||
Клієнт
|
||
```
|
||
|
||
**Проблема:** Обходить Swapper, не використовує динамічне завантаження
|
||
|
||
### Варіант 2: Router → Swapper → Ollama (ідеальний)
|
||
|
||
```
|
||
Клієнт
|
||
↓ POST /route
|
||
Router (9102)
|
||
↓ [визначає модель]
|
||
↓ POST /models/{name}/load
|
||
Swapper (8890)
|
||
↓ [перевіряє модель]
|
||
↓ [завантажує якщо потрібно]
|
||
Ollama (host:11434)
|
||
↓ [генерує]
|
||
Swapper
|
||
↓
|
||
Router
|
||
↓
|
||
Клієнт
|
||
```
|
||
|
||
**Проблема:** Swapper не має `/generate` або `/v1/chat/completions` endpoint
|
||
|
||
---
|
||
|
||
## 📊 Поточний стан
|
||
|
||
### ✅ Що працює
|
||
|
||
1. **Router:**
|
||
- ✅ Запущений, healthy
|
||
- ✅ Підключений до NATS
|
||
- ✅ Може викликати Swapper для завантаження моделей
|
||
- ✅ Може отримувати список моделей з Swapper
|
||
|
||
2. **Swapper:**
|
||
- ✅ Запущений, healthy
|
||
- ✅ Активна модель `gpt-oss-latest`
|
||
- ✅ Доступ до Ollama працює
|
||
- ✅ Може завантажувати/вивантажувати моделі
|
||
|
||
3. **Ollama:**
|
||
- ✅ Працює на хості
|
||
- ✅ 9 моделей доступні
|
||
- ✅ Модель `gpt-oss:latest` завантажена
|
||
|
||
### ⚠️ Що не працює повністю
|
||
|
||
1. **Генерація через Swapper:**
|
||
- Router намагається викликати `/v1/chat/completions`
|
||
- Swapper не має такого endpoint
|
||
- Router йде напряму до Ollama
|
||
|
||
2. **SWAPPER_URL:**
|
||
- Використовує IP адресу замість service name
|
||
- Може не працювати при зміні IP
|
||
|
||
3. **NATS Unhealthy:**
|
||
- Може впливати на messaging
|
||
|
||
---
|
||
|
||
## 🔧 Рекомендації для виправлення
|
||
|
||
### 1. Додати endpoint в Swapper
|
||
|
||
**Потрібно додати в Swapper:**
|
||
```python
|
||
@app.post("/v1/chat/completions")
|
||
async def chat_completions(request: ChatRequest):
|
||
# Завантажити модель якщо потрібно
|
||
# Викликати Ollama
|
||
# Повернути відповідь
|
||
```
|
||
|
||
### 2. Виправити SWAPPER_URL в Router
|
||
|
||
**Змінити:**
|
||
```yaml
|
||
# Замість:
|
||
SWAPPER_URL=http://192.168.1.33:8890
|
||
|
||
# Використати:
|
||
SWAPPER_URL=http://swapper-service:8890
|
||
```
|
||
|
||
### 3. Оновити Router для використання Swapper
|
||
|
||
**Змінити генерацію:**
|
||
```python
|
||
# Замість прямого виклику Ollama:
|
||
generate_resp = await http_client.post(f"{VISION_URL}/api/generate", ...)
|
||
|
||
# Викликати Swapper:
|
||
generate_resp = await http_client.post(
|
||
f"{SWAPPER_URL}/v1/chat/completions",
|
||
...
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 Висновок
|
||
|
||
**НОДА2 працює наступним чином:**
|
||
|
||
1. ✅ **Router** - маршрутизує запити, має 17 провайдерів
|
||
2. ✅ **Swapper** - управляє моделями, активна модель `gpt-oss-latest`
|
||
3. ✅ **Ollama** - локальний LLM runtime, 9 моделей доступні
|
||
4. ⚠️ **Інтеграція** - частково працює, потрібні доопрацювання
|
||
|
||
**Поточна реалізація:**
|
||
- Router може завантажувати моделі через Swapper
|
||
- Router йде напряму до Ollama для генерації
|
||
- Swapper не використовується для генерації
|
||
|
||
**Ідеальна реалізація:**
|
||
- Router → Swapper → Ollama (повний потік)
|
||
- Swapper керує всіма LLM операціями
|
||
- Динамічне завантаження моделей за потреби
|
||
|
||
---
|
||
|
||
**Оновлено:** 2026-01-12
|
||
**Статус:** ✅ Аналіз завершено, виявлено проблеми інтеграції
|