refactor
This commit is contained in:
@@ -2,12 +2,18 @@
|
||||
|
||||
Домашний ИИ-ассистент с REST API, веб-интерфейсом и помидоро-таймером. LLM — OpenRouter (по умолчанию DeepSeek).
|
||||
|
||||
## Возможности (MVP)
|
||||
## Возможности
|
||||
|
||||
- Чат с потоковыми ответами (SSE)
|
||||
- Управление помидоро из чата через tool calling
|
||||
- REST API для внешних клиентов (Telegram-бот, мобильное приложение)
|
||||
- Веб-морда: вкладки «Чат» и «Помидоро»
|
||||
- Чат с потоковыми ответами (SSE), скриншоты и vision-разбор изображений
|
||||
- Помидоро-таймер с циклом работа/перерывы, управление из чата (tool calling)
|
||||
- Долгосрочная память, профиль пользователя, опциональный RAG (Qdrant)
|
||||
- Фитнес: дневник, TDEE/Navy, графики веса и состава тела
|
||||
- Списки покупок, календарь напоминаний
|
||||
- Персонаж и генерация картинок (ComfyUI / RP Chat)
|
||||
- Интеграции: Taiga, Gitea, погода, утренний дайджест, Netdata
|
||||
- Мультипользовательская авторизация по API-токену (`/login`)
|
||||
- Веб-интерфейс: Чат, Помидоро, Персонаж, Память, Фитнес, Покупки, Календарь, Настройки
|
||||
- REST API для внешних клиентов — см. [Telegram-бот](telegram-bot/README.md)
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
@@ -49,7 +55,8 @@ docker compose up --build
|
||||
| `TAIGA_PORT` | 9000 | Taiga (фаза 2) |
|
||||
| `GITEA_PORT` | 3000 | Gitea HTTP (фаза 2) |
|
||||
| `GITEA_SSH_PORT` | 222 | Gitea SSH (фаза 2) |
|
||||
| `QDRANT_PORT` | 6333 | Qdrant HTTP (фаза 3) |
|
||||
| `QDRANT_PORT` | 6333 | Qdrant HTTP |
|
||||
| `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB` | assistant | PostgreSQL в docker compose |
|
||||
|
||||
### 3. Локальная разработка
|
||||
|
||||
@@ -59,10 +66,16 @@ docker compose up --build
|
||||
cd backend
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate # Windows
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-dev.txt
|
||||
uvicorn app.main:app --reload --port 8080
|
||||
```
|
||||
|
||||
Для локального backend без Docker задайте в `.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL=sqlite:///./data/assistant.db
|
||||
```
|
||||
|
||||
**Frontend:**
|
||||
|
||||
```bash
|
||||
@@ -75,34 +88,30 @@ Vite dev-server: http://localhost:5173 (проксирует `/api` на backend
|
||||
|
||||
## REST API
|
||||
|
||||
Полная схема — Swagger UI: `http://localhost:${BACKEND_PORT:-8080}/docs`
|
||||
|
||||
Основные эндпоинты (префикс `/api/v1`, авторизация `Authorization: Bearer <token>` если `AUTH_REQUIRED=true`):
|
||||
|
||||
| Method | Path | Описание |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/v1/health` | Healthcheck |
|
||||
| POST | `/api/v1/chat/sessions` | Создать чат-сессию |
|
||||
| GET | `/api/v1/chat/sessions` | Список сессий |
|
||||
| GET | `/api/v1/chat/sessions/{id}` | История сообщений |
|
||||
| POST | `/api/v1/chat/sessions/{id}/messages` | Отправить сообщение (SSE) |
|
||||
| DELETE | `/api/v1/chat/sessions/{id}` | Удалить сессию |
|
||||
| GET | `/api/v1/pomodoro/status` | Статус таймера |
|
||||
| POST | `/api/v1/pomodoro/start` | Старт `{duration_min, task_note}` |
|
||||
| POST | `/api/v1/pomodoro/pause` | Пауза |
|
||||
| POST | `/api/v1/pomodoro/resume` | Продолжить |
|
||||
| POST | `/api/v1/pomodoro/stop` | Стоп `{result, completed}` |
|
||||
| GET | `/api/v1/pomodoro/history` | История сессий |
|
||||
| GET | `/api/v1/projects` | Проекты Taiga + привязка Gitea |
|
||||
| POST | `/api/v1/projects/sync-taiga` | Синхронизировать проекты из Taiga |
|
||||
| PUT | `/api/v1/projects/{slug}/gitea` | Привязать Gitea repo |
|
||||
| POST | `/api/v1/work-items` | Создать фичу/баг → Taiga + Gitea |
|
||||
| GET | `/api/v1/work-items` | Список work items |
|
||||
| POST | `/api/v1/webhooks/gitea` | Webhook для автозакрытия по push |
|
||||
| POST | `/login` | Получить сессию по API-токену |
|
||||
| GET | `/health` | Healthcheck |
|
||||
| POST/GET | `/chat/sessions` | Чат-сессии и история |
|
||||
| POST | `/chat/sessions/{id}/messages` | Сообщение (SSE) |
|
||||
| GET/POST | `/pomodoro/*` | Таймер |
|
||||
| GET/PUT | `/memory`, `/profile` | Память и профиль |
|
||||
| GET/POST | `/fitness/*` | Фитнес, графики `/fitness/charts` |
|
||||
| GET/POST | `/shopping/*` | Списки покупок |
|
||||
| GET/POST | `/reminders/*` | Напоминания и календарь |
|
||||
| GET/POST | `/documents/*` | Загрузка документов (RAG) |
|
||||
| GET | `/homelab/status`, `/homelab/weather` | Homelab |
|
||||
| GET/PUT | `/settings` | RAG toggle, пользователи |
|
||||
| GET/POST | `/projects`, `/work-items` | Taiga + Gitea |
|
||||
| POST | `/webhooks/gitea` | Webhook автозакрытия |
|
||||
|
||||
## Taiga + Gitea (фаза 2)
|
||||
|
||||
Taiga и Gitea работают **на хосте** (не в Docker):
|
||||
- Taiga: `127.0.0.1:9000` → `taiga.grigowashere.ru`
|
||||
- Gitea: `127.0.0.1:3000` → `git.grigowashere.ru`
|
||||
|
||||
Контейнер backend достучится через `host.docker.internal` (настроено в `docker-compose.yml`).
|
||||
Taiga и Gitea обычно работают **на хосте** (не в Docker compose). Контейнер backend достучится через `host.docker.internal` (настроено в `docker-compose.yml`). Публичные URL — в `.env` (`TAIGA_PUBLIC_URL`, `GITEA_PUBLIC_URL`).
|
||||
|
||||
### Настройка `.env`
|
||||
|
||||
@@ -110,11 +119,11 @@ Taiga и Gitea работают **на хосте** (не в Docker):
|
||||
TAIGA_BASE_URL=http://host.docker.internal:9000
|
||||
TAIGA_USERNAME=...
|
||||
TAIGA_PASSWORD=...
|
||||
TAIGA_PUBLIC_URL=https://taiga.grigowashere.ru
|
||||
TAIGA_PUBLIC_URL=https://taiga.example.com
|
||||
|
||||
GITEA_BASE_URL=http://host.docker.internal:3000
|
||||
GITEA_TOKEN=... # Settings → Applications → Generate Token
|
||||
GITEA_PUBLIC_URL=https://git.grigowashere.ru
|
||||
GITEA_PUBLIC_URL=https://git.example.com
|
||||
GITEA_WEBHOOK_SECRET=... # произвольная строка
|
||||
```
|
||||
|
||||
@@ -162,14 +171,44 @@ Closes gitea #12, taiga #45
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
backend/ FastAPI, OpenRouter, SQLite, помидоро
|
||||
frontend/ React + Vite, чат и таймер
|
||||
data/ SQLite БД (создаётся автоматически)
|
||||
backend/ FastAPI, OpenRouter, PostgreSQL (docker) / SQLite (local dev)
|
||||
frontend/ React + Vite
|
||||
telegram-bot/ Telegram-клиент (отдельный VPS)
|
||||
data/ uploads, generated media, SQLite-бэкап при миграции
|
||||
deploy/ примеры nginx
|
||||
```
|
||||
|
||||
## Память и контекст (фаза 3a)
|
||||
## PostgreSQL
|
||||
|
||||
Долгосрочная память в SQLite, без векторов:
|
||||
В `docker compose` по умолчанию поднимается **PostgreSQL 16**. Переменные — `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` в `.env`.
|
||||
|
||||
### Миграция с SQLite
|
||||
|
||||
Если уже есть `./data/assistant.db`:
|
||||
|
||||
```bash
|
||||
# 1. Бэкап
|
||||
cp -a data data.bak.$(date +%Y%m%d)
|
||||
|
||||
# 2. Поднять postgres
|
||||
docker compose up -d postgres
|
||||
|
||||
# 3. Dry-run (подсчёт строк)
|
||||
docker compose run --rm backend python scripts/migrate_sqlite_to_postgres.py --dry-run
|
||||
|
||||
# 4. Импорт (DATABASE_URL уже указывает на postgres в compose)
|
||||
docker compose run --rm backend python scripts/migrate_sqlite_to_postgres.py
|
||||
|
||||
# 5. Перезапуск
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Флаги: `--force` — очистить Postgres перед импортом; `--sqlite-path` — путь к файлу.
|
||||
SQLite-файл **не удаляется** — остаётся бэкапом.
|
||||
|
||||
## Память и контекст
|
||||
|
||||
Долгосрочная память в БД (PostgreSQL или SQLite). При включённом RAG — семантический поиск фактов через Qdrant.
|
||||
|
||||
| Слой | Что хранит |
|
||||
|------|------------|
|
||||
@@ -203,10 +242,29 @@ data/ SQLite БД (создаётся автоматически)
|
||||
| DELETE | `/api/v1/memory/facts/{id}` | забыть |
|
||||
| PUT | `/api/v1/memory/sessions/{id}/summary` | сводка чата |
|
||||
|
||||
## RAG (Qdrant)
|
||||
|
||||
Векторный поиск по фактам памяти и загруженным документам. **Два условия одновременно:**
|
||||
|
||||
1. `RAG_ENABLED=true` в `.env` (Qdrant должен быть доступен)
|
||||
2. Toggle «RAG включён» в **Настройки** (веб-UI)
|
||||
|
||||
Загрузка документов: Settings → документы, или `POST /api/v1/documents/upload` (текст: `.txt`, `.md`, `.json`, `.csv`).
|
||||
Tool в чате: `search_documents`.
|
||||
|
||||
Backfill существующих фактов:
|
||||
|
||||
```bash
|
||||
docker compose exec backend python -m app.rag.migrate_memory_to_qdrant
|
||||
```
|
||||
|
||||
Ограничения: нет API удаления документов; session summaries индексируются, но в чате читаются из SQLite; при ошибке embedding — fallback на топ фактов из БД.
|
||||
|
||||
## Фитнес-трекер
|
||||
|
||||
Профиль, дневник (еда/вода/вес/тренировки), калькуляторы TDEE, LLM-оценка ккал/БЖУ,
|
||||
lookup wger + Open Food Facts, напоминания в чат (`💪`), вкладка `/fitness`.
|
||||
Профиль, дневник (еда/вода/вес/шаги/тренировки), калькуляторы TDEE и Navy (WHR/LBM/FFMI),
|
||||
графики веса и состава тела (`/fitness`, API `/fitness/charts`), LLM-оценка ккал/БЖУ,
|
||||
lookup wger + Open Food Facts, vision-импорт скриншотов Mi Fitness, напоминания в чат.
|
||||
|
||||
Чат: «обед: гречка 200г, курица 150г», «выпил 300 мл воды», «жим 80×5×3».
|
||||
|
||||
@@ -222,8 +280,8 @@ lookup wger + Open Food Facts, напоминания в чат (`💪`), вкл
|
||||
|
||||
| Сервис | URL по умолчанию | Назначение |
|
||||
|--------|------------------|------------|
|
||||
| Open-Meteo | `http://192.168.1.109:8085` | Погода СПб в контексте и tool `get_weather` |
|
||||
| ComfyUI | `http://192.168.1.109:8188` | fallback / рофл-watcher |
|
||||
| Open-Meteo | `$OPENMETEO_BASE_URL` | Погода в контексте и tool `get_weather` |
|
||||
| ComfyUI | `$COMFYUI_BASE_URL` | fallback / рофл-watcher |
|
||||
| RP Chat (aiChatBot) | `http://host.docker.internal:8201` | `generate_image`: sd-prompt + Anima; appearance в `/character` |
|
||||
| Netdata | `http://host.docker.internal:19999` | Алерты warning/critical → notice в чат |
|
||||
|
||||
@@ -244,10 +302,10 @@ curl -s http://localhost:${BACKEND_PORT:-8202}/api/v1/homelab/status | python3 -
|
||||
|
||||
```bash
|
||||
docker compose exec backend python -c "
|
||||
import httpx
|
||||
import os, httpx
|
||||
for url in [
|
||||
'http://192.168.1.109:8085/v1/forecast?latitude=59.93&longitude=30.33¤t=temperature_2m',
|
||||
'http://192.168.1.109:8188/system_stats',
|
||||
os.environ.get('OPENMETEO_BASE_URL', 'http://host.docker.internal:8085').rstrip('/') + '/v1/forecast?latitude=59.93&longitude=30.33¤t=temperature_2m',
|
||||
os.environ.get('COMFYUI_BASE_URL', 'http://host.docker.internal:8188').rstrip('/') + '/system_stats',
|
||||
'http://host.docker.internal:19999/api/v1/info',
|
||||
]:
|
||||
try:
|
||||
@@ -261,12 +319,26 @@ for url in [
|
||||
По умолчанию **Anima** (как в aiChatBot): `COMFYUI_UNET` + `COMFYUI_CLIP` + `COMFYUI_VAE` + style LoRA.
|
||||
`COMFYUI_CHECKPOINT` оставь пустым. Для SD1.5/Pony — укажи checkpoint и очисти `COMFYUI_UNET`.
|
||||
|
||||
## Telegram-бот
|
||||
|
||||
Отдельный сервис в [`telegram-bot/`](telegram-bot/README.md): диалог с ассистентом с VPS, привязка API-токена, дублирование notice из чата.
|
||||
Создание пользователя: Settings → Пользователи или `docker compose exec backend python -m scripts.create_user`.
|
||||
|
||||
## Разработка и тесты
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
pip install -r requirements-dev.txt
|
||||
pytest tests/ -q
|
||||
```
|
||||
|
||||
Перед деплоем Jenkins запускает pytest (см. `Jenkinsfile`). CI на GitHub Actions нет — только Jenkins на linux-ноде.
|
||||
|
||||
## Следующие фазы
|
||||
|
||||
- RAG по файлам (Qdrant)
|
||||
- Telegram-бот
|
||||
- Taiga/fitness в утреннем дайджесте
|
||||
- Графики веса, LLM-мотивация в напоминаниях
|
||||
- LLM-мотивация в фитнес-напоминаниях (сейчас шаблонные строки)
|
||||
- API удаления документов и re-index при включении RAG задним числом
|
||||
|
||||
## Модель
|
||||
|
||||
|
||||
Reference in New Issue
Block a user