Skip to content

f4rceful/BookRAG

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BookRAG — Умный поиск по книгам

Локальная RAG-система для семантического поиска по текстам книг и ответов на вопросы с опорой на найденные фрагменты. Работает полностью офлайн — интернет нужен только для первой загрузки моделей эмбеддингов.

Стек технологий

Слой Технологии
Фронтенд React 19, TypeScript, Vite, framer-motion
Бэкенд Python, FastAPI, LangChain
Эмбеддинги intfloat/multilingual-e5-small
Векторная БД ChromaDB (персистентная)
LLM Ollama (локально)
Поиск Гибридный BM25 + Векторный + расширение контекста (radius=2)

Архитектура поиска

Запрос пользователя
        │
        ├── Векторный поиск (ChromaDB, cosine similarity)
        │
        └── BM25 лексический поиск (с русским стеммером)
                    │
              Гибридное слияние (RRF + lexical overlap)
                    │
     Расширение контекста (соседние чанки, radius=2)
                    │
               Топ-N результатов → LLM → Ответ

Требования

  • Python 3.12
  • Node.js 18+ — нужен для запуска фронтенда (npm install, npm run dev)
  • Ollama — установлен и запущен

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

1. Клонируйте репозиторий

git clone https://github.com/f4rceful/BookRAG.git
cd BookRAG

2. Скачайте модель Ollama

# Рекомендуется (лучший баланс качества и скорости):
ollama pull qwen2.5:7b

# Или более мощный вариант:
ollama pull gemma3:12b

3. Запустите бэкенд

cd backend
python -m venv venv

# Windows:
venv\Scripts\activate
# Linux/macOS (bash/zsh):
source venv/bin/activate

# Установка зависимостей (автоматически определяет GPU):
python setup.py

uvicorn main:app --host 0.0.0.0 --port 8000

Бэкенд будет доступен на http://localhost:8000. Swagger-документация: http://localhost:8000/docs

setup.py автоматически определяет видеокарту (NVIDIA CUDA, AMD ROCm, Apple Silicon MPS) и устанавливает подходящую версию PyTorch.

4. Запустите фронтенд

В новом терминале:

cd BookRAG/frontend
npm install
npm run dev

Фронтенд откроется на http://localhost:5173.

Первый запуск: при старте бэкенд автоматически проиндексирует все книги из backend/books/ в фоне. Прогресс отображается в интерфейсе на странице «Управление книгами». Поиск будет доступен по мере готовности каждой книги. Полная индексация 4 книг занимает 10–20 минут (зависит от железа).

Альтернатива: запуск через Docker

docker-compose up --build

Модель можно сменить через страницу «Настройки» в интерфейсе — без перезапуска сервера.

Конфигурация

Настройки бэкенда находятся в backend/.env:

# Модель Ollama (должна быть скачана через ollama pull)
MODEL_NAME=qwen2.5:7b

# URL Ollama (по умолчанию локальный)
OLLAMA_BASE_URL=http://localhost:11434

# Модель эмбеддингов (скачается автоматически с HuggingFace)
EMBEDDING_MODEL=intfloat/multilingual-e5-small

# Параметры нарезки текста (влияют на качество поиска)
CHUNK_SIZE=800
CHUNK_OVERLAP=300
INDEX_BATCH_SIZE=100

Важно: после изменения CHUNK_SIZE или CHUNK_OVERLAP удалите книгу из базы и загрузите её заново — старые чанки в ChromaDB не обновляются автоматически.

Загрузка книг

Поддерживается формат .txt (до 50 МБ). Кодировка определяется автоматически (UTF-8, UTF-8 BOM, Windows-1251 и другие).

Авто-индексация из папки

Положите .txt файлы в backend/books/ и запустите (или перезапустите) бэкенд — книги проиндексируются автоматически в фоне. Прогресс индексации отображается в интерфейсе в реальном времени.

Через интерфейс

  1. Откройте фронтенд → страница «Управление книгами»
  2. Перетащите файл или нажмите на область загрузки
  3. Нажмите «Загрузить и проиндексировать»

Через API

curl -X POST http://localhost:8000/api/upload \
  -F "file=@/path/to/book.txt"

Для «Войны и мира» (~3 МБ, ~3500 чанков) индексация занимает 2–4 минуты.

API

Метод Эндпоинт Описание
GET / Health check
GET /api/books Список загруженных книг
GET /api/stats Количество книг и чанков в базе
GET /api/indexing-progress Прогресс авто-индексации
DELETE /api/book/{filename} Удалить книгу из базы
POST /api/upload Загрузить книгу (.txt)
POST /api/search Гибридный поиск фрагментов
POST /api/ask Вопрос-ответ
POST /api/ask/stream Стриминг ответа (SSE)
GET /api/models Текущая модель
GET /api/models/available Список моделей в Ollama
POST /api/model Сменить модель (с валидацией)

Примеры запросов

Поиск фрагментов:

curl -X POST http://localhost:8000/api/search \
  -H "Content-Type: application/json" \
  -d '{"query": "письмо Татьяны к Онегину", "top_k": 5}'

Вопрос-ответ:

curl -X POST http://localhost:8000/api/ask \
  -H "Content-Type: application/json" \
  -d '{"question": "Почему Раскольников убил старуху-процентщицу?", "top_k": 5}'

Смена модели:

curl -X POST http://localhost:8000/api/model \
  -H "Content-Type: application/json" \
  -d '{"model_name": "qwen2.5:7b"}'

Если модель не установлена в Ollama, вернётся 400 со списком доступных моделей.

Выбор модели Ollama

Модель можно переключить на странице «Настройки» без перезапуска сервера.

Модель RAM Качество на русском Скорость
qwen2.5:7b ~5 ГБ ★★★★★ Средняя
qwen2.5:3b ~2 ГБ ★★★★☆ Быстрая
gemma3:12b ~8 ГБ ★★★★★ Медленная

Важно: не используйте модели с суффиксом :thinking — они значительно замедляют ответ из-за режима размышлений.


Примеры работы

В репозитории уже есть четыре тестовые книги в папке backend/books/:

  • Булгаков — «Мастер и Маргарита»
  • Достоевский — «Преступление и наказание»
  • Пушкин — «Евгений Онегин»
  • Чехов — «Вишнёвый сад»

После запуска бэкенда они индексируются автоматически. Ниже — примеры запросов и ожидаемые ответы.


Пример 1 — Поиск фрагментов (Пушкин)

Запрос:

curl -X POST http://localhost:8000/api/search \
  -H "Content-Type: application/json" \
  -d '{"query": "письмо Татьяны к Онегину", "top_k": 2}'

Ответ:

{
  "results": [
    {
      "content": "Письмо Татьяны к Онегину\n\nЯ к вам пишу - чего же боле?\nЧто я могу еще сказать?\nТеперь, я знаю, в вашей воле\nМеня презреньем наказать.",
      "source": "Пушкин — «Евгений Онегин».txt",
      "score": 0.955,
      "location": "Стр. ~55"
    },
    {
      "content": "Письмо Онегина к Татьяне\n\nПредвижу все: вас оскорбит\nПечальной тайны объясненье.\nКакое горькое презренье...",
      "source": "Пушкин — «Евгений Онегин».txt",
      "score": 0.955,
      "location": "Стр. ~154"
    }
  ]
}

Пример 2 — Вопрос-ответ (Достоевский)

Запрос:

curl -X POST http://localhost:8000/api/ask \
  -H "Content-Type: application/json" \
  -d '{"question": "Почему Раскольников убил старуху-процентщицу?", "top_k": 5}'

Ответ:

{
  "answer": "Согласно предоставленным фрагментам, Раскольников убил старуху-процентщицу и её сестру Лизавету. Мотивы его поступка сложны и не сводятся к простому желанию ограбления.\n\nУбийство Раскольникова было «идейным» преступлением — в отличие от схожего реального дела Данилова, мотивы которого были более элементарными. Раскольников руководствовался теорией, по которой «необыкновенный» человек вправе переступить моральный закон ради высшей цели. Однако его «честная, добрая природа постоянно проявлялась сквозь болезненную рефлексию» — он мучился и в итоге сам пришёл с повинной.",
  "sources": ["Достоевский — «Преступление и наказание».txt"]
}

Пример 3 — Поиск по «Мастеру и Маргарите»

Запрос:

curl -X POST http://localhost:8000/api/search \
  -H "Content-Type: application/json" \
  -d '{"query": "Воланд на Патриарших прудах", "top_k": 2}'

Ответ:

{
  "results": [
    {
      "content": "Попросим мистера Воланда! Замаскированного великана, клетчатого помощника и кота встретили аплодисментами. Коровьев раскланялся с публикой...",
      "source": "Булгаков — «Мастер и Маргарита».txt",
      "score": 0.953,
      "location": "Стр. ~120"
    },
    {
      "content": "Попытки Иванушки сочинить заявление относительно таинственного консультанта не привели ни к чему. Он написал: «В ОГПУ. Вчера около семи часов...»",
      "source": "Булгаков — «Мастер и Маргарита».txt",
      "score": 0.952,
      "location": "Стр. ~85"
    }
  ]
}

Пример 4 — Вопрос-ответ (Чехов)

Запрос:

curl -X POST http://localhost:8000/api/ask \
  -H "Content-Type: application/json" \
  -d '{"question": "Кто купил вишнёвый сад и почему?", "top_k": 5}'

Ответ:

{
  "answer": "Согласно предоставленным фрагментам, вишнёвый сад купил Лопахин. Он купил его, потому что Любовь Андреевна и другие владельцы имения не смогли расплатиться с долгами — имение было выставлено на торги. Лопахин заранее предлагал разбить землю на дачные участки, чтобы спасти имение, но владельцы так и не решились принять его проект до начала торгов.",
  "sources": ["Чехов — «Вишнёвый сад».txt"]
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors