Files
infra/stacks/books
..

books.ruzzy.dev — читалка с ИИ

Личная веб-читалка владельца (только его Telegram ID): загрузка PDF/EPUB → главы по оглавлению → чтение в браузере (iPhone, Boox, Mac) → выделил текст → перевести / объяснить / спросить; рекапы глав (ИИ пишет, владелец правит), вопросы по книге и по всей библиотеке с цитатами [гл. N, с. P] и проверкой фактов по интернету; поиск по книгам и рекапам (RAG).

Как устроено

  • app/library.py — разбор: PDF — PyMuPDF (оглавление; если его нет — заголовки «Глава N/Chapter N» в начале страниц, колонтитулы отсекаются; иначе — по 20 страниц), EPUB — свой разбор (nav/NCX + spine; у PyMuPDF нет оглавления EPUB 3), «страница» EPUB ≈ 2000 символов. Хранение — SQLite data/books.db. Поиск — гибрид: FTS5 (BM25) + эмбеддинги paraphrase-multilingual-MiniLM-L12-v2 (fastembed/ONNX, на CPU fr1, модель в data/models), слияние по рангам (RRF). Рекапы тоже попадают в индекс.
  • app/llm.py — ИИ: Claude Code в фоновом режиме (claude -p --output-format stream-json) по подписке владельца (CLAUDE_CODE_OAUTH_TOKEN из claude setup-token), без инструментов (--tools "") — текст книги и выделения чужие, в них может быть внедрённая инструкция. Для «проверить по интернету» — только WebSearch. Модели: MODEL_MAIN=sonnet (рекапы, вопросы), MODEL_FAST=haiku (перевод, объяснение). До 3 запросов параллельно. ⚠️ --bare нельзя: в нём Claude Code принимает только API-ключ, не OAuth подписки.
  • app/main.py — FastAPI: вход Telegram Login Widget (проверка HMAC подписи ключом sha256(токен бота), auth_date ≤ сутки, ID из ALLOWED_TG_IDS), сессия — подписанная cookie на 30 дней. Ответы ИИ — потоком. noindex везде, robots.txt — Disallow.
  • Интерфейс — серверные шаблоны + static/app.js без сборки; вёрстка под e-ink (чёрное на белом, без анимаций). Markdown ответов рендерится после экранирования — HTML из ответа ИИ не исполняется.

Установка на fr1

rsync -a --exclude data --exclude .env stacks/books/ rus-161:books/
ssh rus-161 'cd ~/books && docker compose up -d --build'
sudo sh ~/books/nginx/install.sh        # vhost + certbot (на fr1, один раз)

.env (только на сервере, 600): TG_BOT_NAME, TG_BOT_TOKEN (бот для входа; у @BotFather /setdomain → books.ruzzy.dev), ALLOWED_TG_IDS=607015, SESSION_SECRET (случайный, сменить = разлогинить всех), CLAUDE_CODE_OAUTH_TOKEN, MODEL_MAIN, MODEL_FAST. После правки — docker compose up -d.

Данные

~/books/data/: books.db (книги, главы, текст, рекапы, вопросы, индекс), files/ (оригиналы), models/ (эмбеддинги, ~0,5 ГБ, скачиваются при первом запуске), claude/ (конфиг Claude Code, CLAUDE_CONFIG_DIR).

Потом

  • Интеграция с малиной: рекапы → vault Книги/<книга>.md, вопросы из Telegram через Astra (отдельный этап).
  • Импорт библиотеки из OneDrive (229 PDF в Ruslan/Книги), OCR сканов.