"""Мониторинг пайплайна — вкладка «Обработка» (очередь и отсев).""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from ..auth import current_login from ..services import processing as processing_svc router = APIRouter(prefix="/api/pipeline", tags=["processing"]) class ReturnBody(BaseModel): reason: str = "" @router.get("/stats") def stats(_: str = Depends(current_login)) -> dict: """Сводка: размер очереди (new/ai) и число записей в отсеве.""" return processing_svc.stats() @router.get("/queue") def queue(limit: int = 100, _: str = Depends(current_login)) -> dict: """Сырые сообщения, ожидающие обработки (этап 1 или ИИ).""" q = processing_svc.queue_counts() return { "items": processing_svc.list_queue(limit), "counts": q, "rejected": processing_svc.rejected_count(), } @router.get("/rejected") def rejected( q: str = "", offset: int = 0, limit: int = 100, _: str = Depends(current_login), ) -> dict: """Отсев: что и почему не прошло пайплайн (полнотекстовый поиск по q).""" return processing_svc.list_rejected(q, offset, limit) @router.post("/rejected/clear") def rejected_clear(_: str = Depends(current_login)) -> dict: """Ручная полная очистка отсева (безвозвратно).""" cleared = processing_svc.clear_all() return {"ok": True, "cleared": cleared} @router.delete("/rejected/{rej_id}") def rejected_delete(rej_id: str, _: str = Depends(current_login)) -> dict: processing_svc.delete_one(rej_id) return {"ok": True} @router.post("/rejected/{rej_id}/return") def rejected_return(rej_id: str, body: ReturnBody, _: str = Depends(current_login)) -> dict: """Вернуть отсеянное сообщение в обработку. Для возвращённого сообщения причины отсева (стоп-лист, резюме, тип, без суммы, устарело, ML/ИИ-спам) игнорируются: оно уходит на ML/ИИ и создаёт карточку. ML обучается на действии (снятие «спама»), а решение ИИ по возвращённому сообщению снова учит ML. Запись в отсеве помечается «возвращено» с указанной пользователем причиной. """ try: out = processing_svc.return_to_queue(rej_id, body.reason) except KeyError as exc: raise HTTPException(404, "Запись не найдена") from exc except ValueError as exc: raise HTTPException(400, str(exc)) from exc return out