Files
anti-plagiarism/docs/DIAGRAM.md
jze9 e4ca4a7150
All checks were successful
Deploy / test (push) Successful in 2m59s
Deploy / deploy (push) Successful in 3s
docs: сервер эмбеддингов переехал на .1.40 + честные итоги проверок
Прод переключён на новый сервер эмбеддингов (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>
2026-08-31 17:06:41 +05:00

4.3 KiB
Raw Blame History

Схема системы

Визуальная схема к ARCHITECTURE.md (там — полное текстовое описание).

Компоненты и потоки данных

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 уровня)

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, по умолчанию выключены.