Mikan 7cbe8da103 fix
2026-06-21 07:52:25 +03:00
fix
2026-06-21 07:52:25 +03:00
2026-06-20 22:21:47 +03:00
2026-06-20 19:13:05 +03:00
fix
2026-06-21 07:52:25 +03:00
2026-06-20 19:13:05 +03:00
2026-06-20 22:21:47 +03:00
2026-06-20 22:21:47 +03:00
2026-06-20 19:13:05 +03:00
fix
2026-06-21 07:52:25 +03:00
2026-06-20 22:21:47 +03:00
2026-06-20 19:13:05 +03:00
2026-06-21 01:02:25 +03:00
2026-06-21 02:41:48 +03:00

AI-RPG — Text RPG with an LLM Game Master

Version: 1.0.0
Stack: Python 3.12 · FastAPI · SQLAlchemy 2.x async · PostgreSQL 15 · Qdrant 1.9 · React 18 · Vite 5 · TypeScript 5 · Tailwind CSS 3 · zustand 4 · react-i18next 14

AI-RPG — это веб-приложение, в котором игрок ведёт текстовую ролевую игру с ИИ-мастером (GM). Игрок создаёт мир (или выбирает готовый пресет), настраивает персонажа, и далее вступает в пошаговое взаимодействие: каждое действие игрока обрабатывается трёхфазным orchestrator-ом, который генерирует нарратив, обновляет состояние мира через tool calls, и предлагает 1-3 следующих действия.

Полное ТЗ — в docs/AI-RPG_TZ_TDD.md.


Возможности (v1.0.0)

  • JWT-аутентификация — регистрация обычных пользователей и первого админа по токену.
  • Админ-панель — настройки (LLM, embeddings, Qdrant, UI, game), логи LLM-вызовов с фильтрами, список пользователей, статистика, диагностические кнопки (test LLM / test LLM tools / test embeddings / probe dimension / recreate collections), загрузка favicon/logo/OG-image.
  • Пресеты миров — 2 встроенных (Classic Fantasy, Deep Space Outpost) + создание/редактирование своих.
  • World Builder — генерация нового мира из пресета или формы через SSE-стрим: schemas → environment → entities → intro scene.
  • World Editor — чат-инструция для LLM, propose_changes с diff, ask_user для уточнений, optimistic locking.
  • Orchestrator (3 фазы):
    • Phase 1: planner+executor — цикл tool-calls до submit_plan.
    • Phase 2: writer — single LLM call с submit_step, стриминг scene_chunk.
    • Phase 3: persist + deferred triggers + summary (если история длинная) + suggest actions.
  • RAG через Qdrantrag_query / rag_add, двухстадийный retrieval (Qdrant → PostgreSQL), изоляция миров через payload-фильтр, фоновая индексация (через embedding_status).
  • EmbeddingsHashEmbedder (offline, для dev) и OpenAIEmbedder (OpenAI-compatible API), авто-fallback embeddings.api_urlllm.api_url.
  • Игровые инструменты (17 шт.): entity_create/get/list/update/delete, env_update/get, update_plot_rails, advance_time, schedule_trigger, calc (с кубиками), random_choice (детерминированный), rag_query/add, run_subagent, submit_plan/step, suggest_actions.
  • Schema toolsschema_add_type/add_field/remove_field/modify_field для world_editor.
  • Контекстный менеджер — последние N сообщений + summary при превышении порога, деградация recent → rag → summary.
  • SSE-стриминг — все долгие операции (world_builder, world_editor, orchestrator) отдают прогресс через SSE с event:/data:/id:, heartbeat, reconnect через Last-Event-ID.
  • Фронтенд — React+TS+Vite+Tailwind, тёмная тема, i18n (en/ru), мобильный responsive, SSE-клиент с автопереподключением.

Архитектура

┌──────────────────────────────────────────────────────────────┐
│  Браузер (React 18 + Vite + TS + Tailwind + zustand)         │
└──────────────────────────┬───────────────────────────────────┘
                           │ HTTP / SSE
┌──────────────────────────▼───────────────────────────────────┐
│  FastAPI Backend (uvicorn)                                   │
│  ├─ app/api/         — роутеры (auth, worlds, sessions, ...)  │
│  ├─ app/engine/      — game_master, world_builder, editor    │
│  │   └─ tools/       — ToolRegistry + 17 game tools          │
│  ├─ app/core/        — llm, rag, embeddings, security, ...   │
│  ├─ app/models/      — SQLAlchemy ORM                        │
│  ├─ app/prompts/     — системные промпты (en)                │
│  └─ app/schemas/     — Pydantic request/response             │
└──────┬─────────────────────────────────┬─────────────────────┘
       │ async SQLAlchemy                │ httpx + qdrant-client
┌──────▼──────────────┐         ┌───────▼──────────────────────┐
│ PostgreSQL 15       │         │ Qdrant 1.9 (векторный индекс)│
│ (users, worlds,     │         │ collections: entities,       │
│  entities, steps,   │         │ story_entries                │
│  logs, ...)         │         └──────────────────────────────┘
└─────────────────────┘                  ▲
                                         │ httpx (embeddings API)
                                ┌────────┴─────────────┐
                                │ LLM Provider (any    │
                                │ OpenAI-compatible)   │
                                └──────────────────────┘

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

Опция 1: docker-compose (рекомендуется)

# 1. Скопировать .env.example в .env и отредактировать
cp .env.example .env
# Отредактируйте SECRET_KEY, ADMIN_SETUP_TOKEN, LLM_API_URL, LLM_API_KEY

# 2. Поднять всё
docker compose up -d --build

# 3. Открыть в браузере:
#    - Frontend (nginx + React build):  http://localhost:8080
#    - Backend Swagger docs:            http://localhost:8000/api/docs
#    - Health-check:                    http://localhost:8000/api/health

При первом старте backend напечатает в лог:

=== AI-RPG Admin Setup ===
No admin user yet. Open this URL in your browser:
  /register/admin?token=<ADMIN_SETUP_TOKEN>
===========================

Посмотреть лог: docker compose logs backend | head -20.

Откройте http://localhost:8080/register/admin?token=<...> и создайте первого админа.

Примечание про LLM: если у вас Ollama на хосте, используйте LLM_API_URL=http://host.docker.internal:11434/v1 — backend-контейнер автоматически резолвит host.docker.internal через extra_hosts: host-gateway (работает на Linux/macOS/Windows).

Опция 2: локальный dev (backend + frontend раздельно)

# Backend
cd /path/to/ai-rpg
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# Запустить PostgreSQL и Qdrant (через docker compose up db qdrant)
docker compose up -d db qdrant

# Применить миграции (создаёт все таблицы)
python -c "import asyncio; from app.db import get_engine; from app.migrations.versions._001_initial_schema import create_all_tables; asyncio.run(create_all_tables(get_engine()))"

# Запустить backend
uvicorn app.main:app --reload --port 8000

# В другом терминале — frontend
cd frontend
npm install
npm run dev
# Откроется http://localhost:5173

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

AI-RPG работает с любым OpenAI-compatible API:

Provider LLM_API_URL Пример LLM_MODEL
OpenAI https://api.openai.com/v1 gpt-4o-mini
Ollama (local) http://localhost:11434/v1 qwen2.5:7b-instruct
LM Studio http://localhost:1234/v1 local-model
vLLM http://localhost:8000/v1 Qwen/Qwen2.5-7B-Instruct
OpenRouter https://openrouter.ai/api/v1 qwen/qwen-2.5-7b-instruct

Если LLM_API_URL пуст — backend использует MockLlmClient (возвращает записанные replay-ответы). Это удобно для dev и тестов.

Embeddings

Два провайдера:

  • offline_hash (по умолчанию) — HashEmbedder, детерминированный bag-of-words + hash projection. Не делает HTTP-запросов, работает offline. Размерность 256.
  • openai — OpenAI-compatible embeddings API. URL/key fallback на llm.api_url/llm.api_key, если embeddings.api_url/embeddings.api_key пустые.

Кнопка «Авто-проба размерности» в админке (POST /api/admin/test/embeddings/probe-dimension) определяет реальную размерность модели и предлагает сохранить её в embeddings.dimension.


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

ai-rpg/
├── app/                          # Backend (Python 3.12)
│   ├── api/                      # FastAPI роутеры
│   │   ├── auth.py               #   /api/register, /api/auth/*
│   │   ├── worlds.py             #   /api/worlds
│   │   ├── sessions.py           #   /api/sessions/* (SSE streams)
│   │   ├── presets.py            #   /api/presets
│   │   ├── admin.py              #   /api/admin/* (settings, logs, test, upload)
│   │   └── misc.py               #   /api/health, /api/i18n
│   ├── core/                     # Сквозные сервисы
│   │   ├── llm.py                #   LlmClient + MockLlmClient
│   │   ├── rag.py                #   RAG через Qdrant + PostgreSQL
│   │   ├── embeddings.py         #   HashEmbedder, OpenAIEmbedder
│   │   ├── qdrant_client.py      #   singleton AsyncQdrantClient
│   │   ├── security.py           #   JWT + bcrypt
│   │   ├── settings_service.py   #   settings table CRUD + seed
│   │   ├── state_validator.py    #   validate_state, apply_patch
│   │   ├── time_utils.py         #   GameTime, parse_delta, advance_time
│   │   └── logging.py            #   structlog setup
│   ├── engine/                   # Игровой движок
│   │   ├── game_master.py        #   orchestrator (3 фазы)
│   │   ├── world_builder.py      #   flow создания мира
│   │   ├── world_editor.py       #   flow редактирования мира
│   │   ├── context.py            #   контекстный менеджер
│   │   ├── sse.py                #   SseEmitter
│   │   └── tools/
│   │       ├── base.py           #   Tool, ToolRegistry, ToolContext, ToolResult
│   │       ├── game.py           #   17 игровых инструментов
│   │       ├── schema_tools.py   #   4 schema-инструмента
│   │       └── register_all.py   #   build_default_registry()
│   ├── models/                   # SQLAlchemy ORM (10 таблиц)
│   ├── prompts/
│   │   ├── registry.py           #   get_prompt(stage, language)
│   │   └── stages/               #   11 stage-промптов (en)
│   ├── schemas/                  # Pydantic request/response
│   ├── migrations/
│   │   ├── init_db.py            #   init_db(session)
│   │   ├── init_qdrant.py        #   re-export init_qdrant_collections
│   │   ├── seed.py               #   builtin presets (fantasy, sci-fi)
│   │   └── versions/_001_initial_schema.py
│   ├── config.py                 # Settings (pydantic-settings)
│   ├── db.py                     # async engine + session factory
│   └── main.py                   # FastAPI app + lifespan
├── frontend/                     # Frontend (React 18 + Vite + TS)
│   ├── src/
│   │   ├── pages/                # 8 pages
│   │   ├── components/
│   │   │   ├── ui/               # 9 primitives (Button, Card, Modal, ...)
│   │   │   ├── sessions/         # Chat, ToolCallBubble, ActionInput, ...
│   │   │   ├── worlds/           # WorldCard, WorldBuilder, WorldEditor
│   │   │   └── admin/            # SettingsPanel, LlmLogsTable, ...
│   │   ├── stores/               # zustand (auth, ui, worlds, session, toast)
│   │   ├── lib/                  # api.ts, sse.ts, cn.ts
│   │   ├── i18n/                 # en.json, ru.json
│   │   └── types/index.ts
│   ├── package.json
│   ├── vite.config.ts
│   ├── tsconfig.json
│   └── tailwind.config.js
├── tests/                        # pytest
│   ├── unit/                     # 65+ unit-тестов
│   └── integration/              # (placeholder)
├── deploy/
│   ├── Dockerfile.backend
│   ├── Dockerfile.frontend
│   └── nginx.conf
├── docs/
│   └── AI-RPG_TZ_TDD.md          # оригинальное ТЗ
├── docker-compose.yml
├── requirements.txt
├── pytest.ini
├── .env.example
└── README.md

API обзор

Полная OpenAPI-схема — на http://localhost:8000/api/docs (Swagger UI).

Ключевые эндпоинты

Метод Путь Назначение
POST /api/register Регистрация пользователя
POST /api/register/admin?token= Регистрация первого админа
POST /api/auth/login Логин по email/username → JWT
GET /api/auth/me Текущий профиль
GET /api/worlds Список миров пользователя
POST /api/worlds Создать мир → SSE URL для world_builder
GET /api/sessions/worlds/{id}/state Текущее состояние для play-страницы
POST /api/sessions/worlds/{id}/iterate Запустить orchestrator → SSE URL
GET /api/sessions/worlds/{id}/iterate/stream SSE-стрим итерации
POST /api/sessions/worlds/{id}/retry Повторить последний шаг
POST /api/sessions/worlds/{id}/rollback Откатить последний шаг
GET /api/admin/settings Все настройки (секреты замаскированы)
PATCH /api/admin/settings Обновить настройки
GET /api/admin/llm-logs?stage=&status_filter=&... Логи LLM-вызовов с фильтрами
POST /api/admin/test/llm?api_url=&api_key=&model= Проверка связности LLM
POST /api/admin/test/embeddings/probe-dimension Авто-проба размерности эмбеддингов
POST /api/admin/upload-icon Загрузить favicon/logo/og_image
GET /api/health Health-check (db, qdrant, llm, emb)

SSE-события (orchestrator)

Event Когда
phase_start Начало Phase 1/2/3
phase_end Конец фазы
tool_call LLM вызвала инструмент
llm_call_start/end Начало/конец LLM-вызова
scene_chunk Streaming-чанк текста из Phase 2
scene_complete Полный текст сцены + delta_time
suggested_actions 1-3 следующих действия
trigger_fired Сработал отложенный триггер
summary_generated Сгенерирован summary
iteration_complete Полное завершение итерации
done Успешное завершение стрима
error Фатальная ошибка, стрим закрывается

Тестирование

# Backend unit-тесты
pytest tests/unit/ -v

# С покрытием
pytest --cov=app --cov-report=term-missing tests/

# Frontend
cd frontend
npm run typecheck   # tsc --noEmit
npm run lint        # ESLint
npm run test        # vitest
npm run build       # production build

Покрытие unit-тестами:

  • app.core.time_utils — парсинг/advance времени, дельты
  • app.core.security — JWT, bcrypt, валидация пароля
  • app.core.state_validator — валидация state/world, apply_patch (set/inc/dec/append/remove)
  • app.core.embeddings.HashEmbedder — детерминизм, нормализация, размерность
  • app.core.llm.MockLlmClient — replay, исчерпание, запись вызовов, стриминг
  • app.engine.tools.base.ToolRegistry — регистрация, диспетч, unknown tool, исключения
  • app.engine.tools.game.CalcTool — арифметика, кубики, переменные, ошибки
  • app.engine.tools.game.RandomChoiceTool — детерминизм, веса
  • app.engine.sse.SseEmitter — emit/done/error, ID, сериализация
  • app.prompts.registry — все 11 stage-промптов валидны

Production-деплой

См. docs/AI-RPG_TZ_TDD.md §13 (DevOps / Deployment) и §18.3 (Pre-deploy checklist).

Ключевые моменты:

  1. SECRET_KEY — сгенерировать через python -c "import secrets; print(secrets.token_urlsafe(48))".
  2. ADMIN_SETUP_TOKEN — задать в .env ИЛИ оставить пустым (тогда сгенерируется случайно при первом старте, напечатается в логах).
  3. HTTPS — terminate TLS на nginx или на внешнем reverse-proxy.
  4. Backups — ежедневно pg_dump + Qdrant snapshot в S3.
  5. Health-checkGET /api/health должен вернуть 200 с db:true, qdrant:true.
  6. Мониторинг — structlog пишет JSON в stdout, забирается любой log-агрегатор.

Лицензия

MIT — см. LICENSE (если отсутствует, предполагается MIT).


Changelog

v1.0.0 (2026-06-20)

  • Первый release. Реализованы все 8 спринтов из ТЗ:
    • Sprint 1: Foundation (docker-compose, БД, Qdrant, миграции, seed, health-check)
    • Sprint 2: Auth + Admin (JWT, регистрация, админ-панель настроек, тесты LLM/embeddings)
    • Sprint 3: World Builder (LLM-клиент, промпты, SSE-стрим генерации мира)
    • Sprint 4: World Editor (чат-редактор, propose_changes, ask_user, optimistic lock)
    • Sprint 5: Orchestrator (3 фазы, retry/rollback)
    • Sprint 6: Frontend polish (i18n en/ru, тёмная тема, responsive, SSE reconnect)
    • Sprint 7: RAG + Triggers + Summary + Context Manager
    • Sprint 8: Production (README, метрики, тесты, сборка ZIP)
Description
No description provided
Readme 803 KiB
Languages
Python 53.9%
TypeScript 45.4%
CSS 0.4%
JavaScript 0.2%