OCR + reportistica

This commit is contained in:
2026-03-27 13:54:07 +01:00
parent cbeedc2d2f
commit bb2060c1ae
26 changed files with 5503 additions and 237 deletions
+53 -2
View File
@@ -1,12 +1,13 @@
"""
Schema Pydantic per TenantSettings lettura e aggiornamento impostazioni tenant.
Include schemi per il modulo di indicizzazione full-text.
"""
import uuid
from datetime import datetime
from typing import Literal
from typing import Literal, Optional
from pydantic import BaseModel, Field, HttpUrl, field_validator
from pydantic import BaseModel, Field, field_validator
ArchivalMode = Literal["mock", "production"]
@@ -68,3 +69,53 @@ class TenantSettingsUpdate(BaseModel):
if v is not None and v not in ("mock", "production"):
raise ValueError("archival_mode deve essere 'mock' o 'production'")
return v
# ─── Schemi indicizzazione full-text ──────────────────────────────────────────
class IndexingStats(BaseModel):
"""Statistiche di copertura dell'indicizzazione per un tenant."""
total_messages: int
indexed_messages: int
unindexed_messages: int
coverage_pct: float # percentuale messaggi con search_vector != NULL
attachments_total: int # allegati PDF/DOCX totali
attachments_extracted: int # allegati con testo estratto
attachments_pct: float # percentuale allegati con testo estratto
class IndexingJobStatus(BaseModel):
"""Stato di un job di reindex in corso o completato."""
status: str # idle | running | completed | failed | cancelled
mode: Optional[str] = None # full | differential
total: int = 0
processed: int = 0
progress_pct: float = 0.0
started_at: Optional[str] = None # ISO datetime
finished_at: Optional[str] = None # ISO datetime
started_by: Optional[str] = None # email utente che ha avviato il job
elapsed_seconds: Optional[int] = None
is_stale: bool = False # True se running da piu' di STALE_THRESHOLD_HOURS
error: Optional[str] = None
class StartReindexRequest(BaseModel):
"""Body per POST /settings/indexing/reindex."""
mode: Literal["full", "differential"] = "differential"
class StartRescanRequest(BaseModel):
"""Body per POST /settings/indexing/rescan."""
force: bool = Field(
default=False,
description=(
"False (default): estrae solo allegati con extracted_text NULL. "
"True: ri-estrae tutti gli allegati, sovrascrivendo i testi gia' presenti."
),
)