2026-06-16 09:40:14 +03:00
2026-06-16 09:40:14 +03:00
2026-06-16 09:19:32 +03:00
2026-06-16 09:19:32 +03:00
2026-06-16 09:19:32 +03:00
2026-06-16 09:19:32 +03:00
2026-06-09 09:36:48 +03:00
2026-06-16 04:38:23 +00:00
2026-06-16 09:19:32 +03:00
2026-06-16 09:19:32 +03:00
2026-06-09 09:36:48 +03:00
2026-06-16 09:26:31 +03:00
2026-06-16 04:38:23 +00:00
2026-06-16 04:38:23 +00:00
2026-06-16 04:38:23 +00:00

Home AI Assistant

Домашний ИИ-ассистент с REST API, веб-интерфейсом и помидоро-таймером. LLM — OpenRouter (по умолчанию DeepSeek).

Возможности

  • Чат с потоковыми ответами (SSE), скриншоты и vision-разбор изображений
  • Помидоро-таймер с циклом работа/перерывы, управление из чата (tool calling)
  • Долгосрочная память, профиль пользователя, опциональный RAG (Qdrant)
  • Фитнес: дневник, TDEE/Navy, графики веса и состава тела
  • Списки покупок, календарь напоминаний
  • Персонаж и генерация картинок (ComfyUI / RP Chat)
  • Интеграции: Taiga, Gitea, погода, утренний дайджест, Netdata
  • Мультипользовательская авторизация по API-токену (/login)
  • Веб-интерфейс: Чат, Помидоро, Персонаж, Память, Фитнес, Покупки, Календарь, Настройки
  • REST API для внешних клиентов — см. Telegram-бот

Быстрый старт

1. Настройка окружения

cp .env.example .env

Заполните в .env:

OPENROUTER_API_KEY=sk-or-v1-...
BACKEND_PORT=8080
FRONTEND_PORT=3080

Если порт занят (например, 3000 уже используется Gitea), смените FRONTEND_PORT на свободный.

2. Запуск через Docker

docker compose up --build

Prod за nginx: при загрузке скриншотов возможна ошибка 413 Request Entity Too Large — дефолтный лимит nginx 1 MB. На host nginx (Ubuntu перед docker) добавьте client_max_body_size 64m; в server { } и в location /api/. Пример: deploy/nginx-host-assistant.conf.example. После правки: sudo nginx -t && sudo systemctl reload nginx. Контейнер frontend тоже поднимает лимит в frontend/nginx.conf — пересоберите образ.

Порты в .env:

Переменная По умолчанию Назначение
BACKEND_PORT 8080 API с хоста
FRONTEND_PORT 3080 Веб-морда с хоста
VITE_DEV_PORT 5173 Frontend при npm run dev
TAIGA_PORT 9000 Taiga (фаза 2)
GITEA_PORT 3000 Gitea HTTP (фаза 2)
GITEA_SSH_PORT 222 Gitea SSH (фаза 2)
QDRANT_PORT 6333 Qdrant HTTP
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB assistant PostgreSQL в docker compose

3. Локальная разработка

Backend:

cd backend
python -m venv .venv
.venv\Scripts\activate   # Windows
pip install -r requirements-dev.txt
uvicorn app.main:app --reload --port 8080

Для локального backend без Docker задайте в .env:

DATABASE_URL=sqlite:///./data/assistant.db

Frontend:

cd frontend
npm install
npm run dev

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 Описание
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 compose). Контейнер backend достучится через host.docker.internal (настроено в docker-compose.yml). Публичные URL — в .env (TAIGA_PUBLIC_URL, GITEA_PUBLIC_URL).

Настройка .env

TAIGA_BASE_URL=http://host.docker.internal:9000
TAIGA_USERNAME=...
TAIGA_PASSWORD=...
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.example.com
GITEA_WEBHOOK_SECRET=... # произвольная строка

Первый запуск

# 1. Синхронизировать проекты Taiga (ID подтянутся автоматически)
curl -X POST http://localhost:8080/api/v1/projects/sync-taiga

# 2. Привязать Gitea repo к проекту Taiga
curl -X PUT http://localhost:8080/api/v1/projects/home-assistant/gitea \
  -H "Content-Type: application/json" \
  -d '{"gitea_owner":"Grigo","gitea_repo":"Home_assistant","default_branch":"main"}'

Gitea webhook

В репозитории: Settings → Webhooks → Add Webhook:

  • URL (выбери один вариант):
    • Рекомендуется: https://assistant.example.com/api/v1/webhooks/gitea — nginx → 127.0.0.1:${BACKEND_PORT}
    • Если Gitea в Docker: http://172.17.0.1:${BACKEND_PORT}/api/v1/webhooks/gitea — не 127.0.0.1 (это localhost контейнера Gitea)
  • Content type: application/json
  • Secret: значение GITEA_WEBHOOK_SECRET
  • Events: Push

Проверка из контейнера Gitea: docker exec gitea wget -qO- http://172.17.0.1:8202/api/v1/health
Test delivery в Gitea должен вернуть 200, не 0.

Автозакрытие по коммиту

В сообщении коммита:

fix: кнопка сохранения
Closes gitea #12, taiga #45

Закроются Gitea issue #12 и Taiga story #45 (если только один ref — второй найдётся по связи в БД).

Чат

«Заведи баг: кнопка не сохраняет настройки» → create_work_item → Taiga story + Gitea issue + ветка feature/45-....

Структура проекта

backend/        FastAPI, OpenRouter, PostgreSQL (docker) / SQLite (local dev)
frontend/       React + Vite
telegram-bot/   Telegram-клиент (отдельный VPS)
data/           uploads, generated media, SQLite-бэкап при миграции
deploy/         примеры nginx

PostgreSQL

В docker compose по умолчанию поднимается PostgreSQL 16. Переменные — POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB в .env.

Миграция с SQLite

Если уже есть ./data/assistant.db:

# 1. Бэкап
cp -a data data.bak.$(date +%Y%m%d)

# 2. Поднять postgres и пересобрать backend (скрипт миграции в образе)
docker compose up -d postgres
docker compose build backend

# 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.

Слой Что хранит
Профиль имя, timezone, language, notes
Факты устойчивые знания с категорией и важностью
Сводка чата краткое содержание длинной сессии

В system prompt на каждый ответ: персонаж → время → память → фитнес → погода → помидоро → проекты.
История чата обрезается до 40 последних сообщений; раннее — в session_summaries.

Автоизвлечение: после каждого ответа LLM анализирует ход диалога и сохраняет устойчивые факты (source=auto). Отключить: MEMORY_AUTO_EXTRACT=false.

UI: вкладка /memory — профиль, факты, JSON-снимок для отладки.

Tools

  • remember_fact — «запомни, что…»
  • recall_memories — поиск по памяти
  • forget_memory — удалить факт по id
  • update_profile — имя, часовой пояс и т.д.
  • update_session_summary — сжать тему длинного чата

API

Method Path Описание
GET /api/v1/memory снимок памяти (+ ?session_id=)
GET/PUT /api/v1/profile профиль
GET/POST /api/v1/memory/facts список / создать факт
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 существующих фактов:

docker compose exec backend python -m app.rag.migrate_memory_to_qdrant

Ограничения: нет API удаления документов; session summaries индексируются, но в чате читаются из SQLite; при ошибке embedding — fallback на топ фактов из БД.

Фитнес-трекер

Профиль, дневник (еда/вода/вес/шаги/тренировки), калькуляторы TDEE и Navy (WHR/LBM/FFMI), графики веса и состава тела (/fitness, API /fitness/charts), LLM-оценка ккал/БЖУ, lookup wger + Open Food Facts, vision-импорт скриншотов Mi Fitness, напоминания в чат.

Чат: «обед: гречка 200г, курица 150г», «выпил 300 мл воды», «жим 80×5×3».

Списки покупок

Несколько списков, позиции с количеством, отметка «куплено». Вкладка /shopping, tools в чате (add_shopping_items, list_shopping_lists, …).

Чат: «добавь молоко и хлеб в продукты», «что в списке покупок», «отметь молоко купленным».

Homelab API (фаза 4)

Интеграции с домашней инфраструктурой:

Сервис URL по умолчанию Назначение
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 в чат

Утренний дайджест (MORNING_DIGEST_HOUR=8): погода + RSS (Habr, r/programming по умолчанию).
По запросу: «что на улице», «будет ли дождь» → get_weather; полный брифинг → get_morning_briefing.

Переменные — в .env.example (секция Homelab).

Проверка доступности

В образе backend нет curl/wget. Удобнее всего — API-диагностика (из контейнера или с хоста):

curl -s http://localhost:${BACKEND_PORT:-8202}/api/v1/homelab/status | python3 -m json.tool

Или изнутри backend через Python:

docker compose exec backend python -c "
import os, httpx
for url in [
    os.environ.get('OPENMETEO_BASE_URL', 'http://host.docker.internal:8085').rstrip('/') + '/v1/forecast?latitude=59.93&longitude=30.33&current=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:
        r = httpx.get(url, timeout=10)
        print(url, '->', r.status_code, r.text[:120])
    except Exception as e:
        print(url, '-> ERROR', e)
"

По умолчанию Anima (как в aiChatBot): COMFYUI_UNET + COMFYUI_CLIP + COMFYUI_VAE + style LoRA.
COMFYUI_CHECKPOINT оставь пустым. Для SD1.5/Pony — укажи checkpoint и очисти COMFYUI_UNET.

Telegram-бот

Отдельный сервис в telegram-bot/: диалог с ассистентом с VPS, привязка API-токена, дублирование notice из чата.
Создание пользователя: Settings → Пользователи или docker compose exec backend python -m scripts.create_user.

Разработка и тесты

cd backend
pip install -r requirements-dev.txt
pytest tests/ -q

Перед деплоем Jenkins запускает pytest (см. Jenkinsfile). CI на GitHub Actions нет — только Jenkins на linux-ноде.

Следующие фазы

  • Taiga/fitness в утреннем дайджесте
  • LLM-мотивация в фитнес-напоминаниях (сейчас шаблонные строки)
  • API удаления документов и re-index при включении RAG задним числом

Модель

По умолчанию: deepseek/deepseek-chat через OpenRouter. Альтернатива для болтовни: google/gemini-2.0-flash.

S
Description
No description provided
Readme 2 MiB
Languages
Python 73.9%
TypeScript 21%
CSS 4.9%