Files
microdao-daarion/NODE2-HOW-IT-WORKS.md
Apple 5290287058 feat: implement TTS, Document processing, and Memory Service /facts API
- 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)
2026-01-17 08:16:37 -08:00

11 KiB
Raw Blame History

🔍 Як працює НОДА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

Змінні середовища:

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:

    health_resp = await http_client.get(f"{SWAPPER_URL}/health")
    
  2. Завантаження моделі:

    load_resp = await http_client.post(
        f"{SWAPPER_URL}/load",
        json={"model": model_name}
    )
    
  3. Генерація (проблема):

    # Router намагається викликати:
    generate_resp = await http_client.post(
        f"{VISION_URL}/api/generate",  # Прямо до Ollama!
        ...
    )
    
  4. Отримання моделей:

    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:

@app.post("/v1/chat/completions")
async def chat_completions(request: ChatRequest):
    # Завантажити модель якщо потрібно
    # Викликати Ollama
    # Повернути відповідь

2. Виправити SWAPPER_URL в Router

Змінити:

# Замість:
SWAPPER_URL=http://192.168.1.33:8890

# Використати:
SWAPPER_URL=http://swapper-service:8890

3. Оновити Router для використання Swapper

Змінити генерацію:

# Замість прямого виклику 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
Статус: Аналіз завершено, виявлено проблеми інтеграції