Документация сильно разошлась с кодом за последние недели работы — привёл в
соответствие ARCHITECTURE.md, README, DIAGRAM.md, INGESTION.md:
- LLM (L4) и эмбеддинги (L3) теперь переключаемые бэкенды (LLM_BACKEND,
EMBED_BACKEND), а не жёстко Ollama/qwen2.5:7b — старая модель эмбеддингов
(768d mpnet) заменена на bge-m3 (1024d); L4 может идти через OpenRouter
(DeepSeek) с прокси singbox для обхода геоблокировки.
- .env на проде больше не редактируется руками — на каждом деплое
генерируется из Infisical; старая инструкция "cp .env.example .env; nano
.env" вводила в заблуждение (правки терялись бы на следующем деплое).
- README "Три docker-compose файла"/deploy разделы противоречили реальности:
фронтенд+TLS реально раздаёт хостовой nginx на CT 102, не докеризованный
nginx-сервис из compose (тот не запускается вообще).
добавлен PMC-парсер, self-match исключение объяснено, число тестов (113)
синхронизировано между файлами (было 82/122 в разных местах).
- INGESTION.md: снимок "42K доков, 0 русских" от 12.08 заменён актуальным
(165K доков, ru теперь большинство) — иначе документ откровенно врёт.
- Diagram: узлы под текущую топологию (embedding-gpu, OpenRouter, Infisical).
Заодно, раз перепроверял код на соответствие докам:
- Удалён мёртвый и битый эндпоинт GET /reports/{task_id} — фильтровал по
внутреннему Task.id вместо public_id (никогда не мог сработать через
обычный клиентский поток), фронтенд его всё равно не вызывал —
функциональность полностью дублирует рабочий GET /tasks/{public_id}.
- Убран мёртвый конфиг FAISS_NLIST/FAISS_NPROBE (worker-gpu/config.py) —
индекс всегда IndexFlatIP, IVF нигде не строится, эти поля ничего не делали.
93 lines
4.3 KiB
Python
93 lines
4.3 KiB
Python
"""Конфигурация GPU воркера."""
|
||
|
||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||
|
||
|
||
class Settings(BaseSettings):
|
||
"""Настройки GPU воркера."""
|
||
|
||
model_config = SettingsConfigDict(
|
||
env_file=".env",
|
||
env_file_encoding="utf-8",
|
||
case_sensitive=False,
|
||
extra="ignore", # игнорировать поля общего .env, не относящиеся к воркеру
|
||
)
|
||
|
||
# PostgreSQL
|
||
POSTGRES_HOST: str = "postgres"
|
||
POSTGRES_PORT: int = 5432
|
||
POSTGRES_DB: str = "antiplagiator"
|
||
POSTGRES_USER: str = "antiplagiator"
|
||
POSTGRES_PASSWORD: str = "changeme"
|
||
|
||
# Redis
|
||
REDIS_URL: str = "redis://redis:6379/0"
|
||
|
||
# RabbitMQ
|
||
RABBITMQ_URL: str = "amqp://guest:guest@rabbitmq:5672/"
|
||
|
||
# MinIO
|
||
MINIO_ENDPOINT: str = "minio:9000"
|
||
MINIO_ACCESS_KEY: str = "minioadmin"
|
||
MINIO_SECRET_KEY: str = "changeme"
|
||
MINIO_BUCKET_DOCS: str = "documents"
|
||
|
||
# Elasticsearch
|
||
ELASTICSEARCH_URL: str = "http://elasticsearch:9200"
|
||
|
||
# Ollama
|
||
OLLAMA_URL: str = "http://ollama:11434"
|
||
|
||
# LLM_BACKEND: "ollama" (локальная модель, нужен GPU-хост) или "openrouter"
|
||
# (облачный API, дешёвая модель — для L4-проверки парафраза "умность" не
|
||
# критична, это не творческая задача). Переключается без изменения кода.
|
||
LLM_BACKEND: str = "ollama"
|
||
OPENROUTER_API_KEY: str = ""
|
||
OPENROUTER_MODEL: str = "deepseek/deepseek-chat"
|
||
OPENROUTER_URL: str = "https://openrouter.ai/api/v1/chat/completions"
|
||
# OpenRouter блокирует запросы из РФ — заворачиваем именно эти запросы
|
||
# через sing-box (docker-compose сервис singbox-proxy). Пусто = без прокси.
|
||
OPENROUTER_PROXY_URL: str = "socks5://singbox-proxy:1080"
|
||
|
||
# FAISS / ML
|
||
FAISS_INDEX_PATH: str = "/data/index/faiss.index"
|
||
FAISS_ID_MAP_PATH: str = "/data/index/faiss_id_map.json"
|
||
# EMBED_BACKEND: "ollama" (GGUF-модель через Vulkan, для AMD GPU без ROCm/atomics),
|
||
# "sentence_transformers" (локальная загрузка, CUDA/CPU) или "cloud" (облачный
|
||
# инференс той же модели — не нужен вообще никакой локальный GPU).
|
||
EMBED_BACKEND: str = "ollama"
|
||
EMBED_MODEL: str = "bge-m3"
|
||
EMBED_DEVICE: str = "cuda" # используется только при EMBED_BACKEND=sentence_transformers
|
||
# Ollama обрабатывает тексты в пачке последовательно (один "slot" в llama.cpp,
|
||
# не параллельно) — 64 реальных документа в один HTTP-запрос регулярно не
|
||
# укладывались в таймаут. Меньше пачка — короче и надёжнее каждый запрос.
|
||
EMBED_BATCH_SIZE: int = 16
|
||
EMBED_DIM: int = 1024 # bge-m3; было 768 у paraphrase-multilingual-mpnet-base-v2
|
||
# DeepInfra — OpenAI-совместимый инференс BAAI/bge-m3 в облаке, та же модель,
|
||
# что и на VM109, дешёвый пей-пер-токен. Используется при EMBED_BACKEND=cloud.
|
||
CLOUD_EMBED_URL: str = "https://api.deepinfra.com/v1/openai/embeddings"
|
||
CLOUD_EMBED_MODEL: str = "BAAI/bge-m3"
|
||
CLOUD_EMBED_API_KEY: str = ""
|
||
|
||
# Векторный бэкенд: "faiss" (файловый синглтон, дефолт) или "qdrant" (сервис,
|
||
# снимает SPOF и конкурентную запись). Переключается без изменения кода.
|
||
VECTOR_BACKEND: str = "faiss"
|
||
QDRANT_URL: str = "http://qdrant:6333"
|
||
QDRANT_COLLECTION: str = "documents"
|
||
|
||
# App
|
||
APP_URL: str = "https://academic.jze9.ru"
|
||
ENVIRONMENT: str = "development"
|
||
DEBUG: bool = False
|
||
|
||
@property
|
||
def database_url_sync(self) -> str:
|
||
"""Синхронный URL для SQLAlchemy (psycopg2)."""
|
||
return (
|
||
f"postgresql+psycopg2://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||
f"@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
||
)
|
||
|
||
|
||
settings = Settings()
|