Прод переключён на новый сервер эмбеддингов (VM 210 «embedding-cpu», 192.168.1.40, хост pve2). Ключевое, чего не было в исходном плане переключения: OLLAMA_URL живёт в Infisical, и deploy.sh генерирует .env из него на каждом запуске — правка .env на сервере откатилась бы первым же деплоем. Совместимость векторов проверена прямым сравнением, а не на слово: косинус 0.9999997, расхождение 1e-4 (округление AVX2 против AVX-512) — переиндексация 93 тыс. векторов не понадобилась. Документация приведена в соответствие с фактами: - ARCHITECTURE/DIAGRAM/README/CREDENTIALS: новый сервер, старый помечен как выведенный; убрано упоминание CUDA — GPU в проекте нет; - DR-HA: эмбеддинги больше не висят на хосте .254, чьё падение 28.08 разом унесло брокер, прокси и секреты; - INGESTION: исправлено собственное враньё про КиберЛенинку — «48 часов на 100 тысяч» опровергнуто практикой, сайт блокирует выкачку после ~130 статей; снапшот OpenAlex вычеркнут как путь к миллионам (там только метаданные). bulk_ingest_pmc.py: снята пометка «не закончен» — бага не было, первый прогон упал уже после успешной вставки, а второй корректно пропустил дубли. Проверено: 100 статей, 183 090 отпечатков. Реальный темп 0.3 ст/с записан честно. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
114 lines
4.3 KiB
Markdown
114 lines
4.3 KiB
Markdown
# Схема системы
|
||
|
||
Визуальная схема к [ARCHITECTURE.md](ARCHITECTURE.md) (там — полное текстовое описание).
|
||
|
||
## Компоненты и потоки данных
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph client["Клиент"]
|
||
FE["Frontend (React SPA)<br/>CT 102, nginx"]
|
||
end
|
||
|
||
subgraph app["App-хост 1.32"]
|
||
API["API (FastAPI)<br/>JWT · rate-limit · /metrics"]
|
||
MQ[("RabbitMQ .82<br/>брокер Celery")]
|
||
|
||
subgraph workers["Celery-воркеры"]
|
||
IDX["worker-indexer<br/>L1 Winnowing · L2 MinHash<br/>PDF/DOCX · парсеры"]
|
||
GPU["worker-gpu<br/>L3 семантика · L4 LLM<br/>эмбеддинги"]
|
||
GOST["worker-gost<br/>ГОСТ 7.1 / 7.0.5"]
|
||
NOTIFY["worker-notifier<br/>SMTP email"]
|
||
end
|
||
|
||
ES[("Elasticsearch<br/>BM25, local")]
|
||
VEC{{"Векторный бэкенд<br/>VECTOR_BACKEND"}}
|
||
FAISS["FAISS<br/>(файл, дефолт)"]
|
||
QDR["Qdrant<br/>(опционально)"]
|
||
end
|
||
|
||
subgraph shared["Общая инфраструктура"]
|
||
PG[("PostgreSQL 1.38<br/>users/tasks/documents/<br/>fingerprints/...")]
|
||
REDIS[("Redis 1.35<br/>кэш · rate-limit · LSH-индекс")]
|
||
MINIO[("MinIO 1.21<br/>документы · full-text · бэкапы")]
|
||
OLLAMA["Ollama 1.40 embedding-cpu<br/>bge-m3, эмбеддинги (L3)"]
|
||
OPENROUTER["OpenRouter/DeepSeek<br/>LLM L4 (опц., через singbox-proxy)"]
|
||
INFISICAL["Infisical .111<br/>секреты → .env на каждом деплое"]
|
||
end
|
||
|
||
subgraph obs["Опционально (профили compose)"]
|
||
PROM["Prometheus"]
|
||
GRAF["Grafana"]
|
||
end
|
||
|
||
FE -->|"HTTPS /api, /ws"| API
|
||
API -->|"send_task"| MQ
|
||
API <-->|"users/tasks"| PG
|
||
API <-->|"session/rate-limit"| REDIS
|
||
|
||
MQ -->|"queue.index"| IDX
|
||
MQ -->|"queue.gpu"| GPU
|
||
MQ -->|"queue.gost"| GOST
|
||
MQ -->|"queue.notify"| NOTIFY
|
||
|
||
IDX <-->|"documents/fingerprints"| PG
|
||
IDX <-->|"MinHash LSH (antiplag_lsh)"| REDIS
|
||
IDX <-->|"PDF/full-text"| MINIO
|
||
IDX --> ES
|
||
IDX -->|"gpu.embed_documents"| MQ
|
||
|
||
GPU <-->|"documents"| PG
|
||
GPU -->|"L3 эмбеддинги"| OLLAMA
|
||
GPU --> VEC
|
||
VEC --> FAISS
|
||
VEC -.->|"переключение флагом"| QDR
|
||
GPU -.->|"L4 парафраз (LLM_BACKEND)"| OLLAMA
|
||
GPU -.->|"L4 парафраз, опц."| OPENROUTER
|
||
GPU --> ES
|
||
|
||
GOST <-->|"documents"| PG
|
||
NOTIFY <-->|"tasks"| PG
|
||
NOTIFY -->|"email"| SMTP(["jze9mail.ru"])
|
||
|
||
API -->|"/metrics"| PROM
|
||
PROM --> GRAF
|
||
|
||
style VEC fill:#00000000,stroke-dasharray: 4 3
|
||
style obs fill:#00000000,stroke-dasharray: 4 3
|
||
```
|
||
|
||
## Конвейер проверки плагиата (4 уровня)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as Студент
|
||
participant API as API
|
||
participant IDX as worker-indexer
|
||
participant GPU as worker-gpu
|
||
participant LLM as Ollama/OpenRouter<br/>(LLM_BACKEND)
|
||
|
||
U->>API: upload файла
|
||
API->>API: сохранить в MinIO, создать Task, commit
|
||
API->>IDX: index.extract_and_check
|
||
IDX->>IDX: извлечь текст → фрагменты
|
||
IDX->>IDX: L1 Winnowing (fingerprints)
|
||
IDX->>IDX: L2 MinHash LSH (Redis)
|
||
IDX->>GPU: gpu.check_plagiarism (частичные совпадения)
|
||
loop по подозрительным фрагментам
|
||
GPU->>GPU: L3 семантический поиск (FAISS/Qdrant)
|
||
GPU->>LLM: L4 check_paraphrase
|
||
LLM-->>GPU: is_paraphrase, confidence
|
||
end
|
||
GPU->>GPU: app.scoring.aggregate_results (итоговый %)
|
||
GPU->>API: результат → Task.result
|
||
GPU-->>U: notify.send_task_done → email/WebSocket
|
||
```
|
||
|
||
## Легенда
|
||
|
||
- Сплошные стрелки — прямые вызовы/запросы; пунктир у `VEC` — переключение бэкенда
|
||
по настройке `VECTOR_BACKEND`, не одновременная работа обоих. Пунктир у L4
|
||
(`OLLAMA`/`OPENROUTER`) — то же самое для `LLM_BACKEND`.
|
||
- `obs` (Prometheus/Grafana) и `Qdrant` — опциональны, поднимаются под
|
||
`docker compose --profile qdrant|observability`, по умолчанию выключены.
|