feat: add depense tagging

This commit is contained in:
2026-01-19 05:19:11 +01:00
parent c5e51a7513
commit 0fd6bdaeb3
8 changed files with 711 additions and 43 deletions

View File

@@ -14,6 +14,7 @@ from .. import __version__
from ..extractor import extract_compte_rendu
from ..database import init_db, get_session, DatabaseService
from ..database.service import DuplicateDocumentError
from ..services.tag_predictor import TagPredictor
app = FastAPI(
title="Plesna Gérance API",
@@ -38,6 +39,14 @@ class SaveRequest(BaseModel):
source_file: str | None = None
data: dict[str, Any]
depenses_tags: list[dict] | None = None # Liste des tags par index de dépense
overwrite: bool = False # Si True, écrase le document existant
class PredictTagsRequest(BaseModel):
"""Request body for predicting tags."""
depenses: list[dict] # Liste des dépenses à prédire
class SaveResponse(BaseModel):
@@ -159,6 +168,8 @@ async def save_document(
- **source_file**: Nom du fichier PDF original (optionnel)
- **data**: Donnees extraites (format identique a la reponse de /api/extract)
- **depenses_tags**: Liste des tags par index de depense (optionnel)
- **overwrite**: Si True, ecrase le document existant (optionnel)
Retourne un message de succes avec l'ID du document cree,
ou une erreur si le document existe deja (doublon).
@@ -166,7 +177,10 @@ async def save_document(
try:
db_service = DatabaseService(session)
document = db_service.save_document(
data=request.data, source_file=request.source_file
data=request.data,
source_file=request.source_file,
depenses_tags=request.depenses_tags,
overwrite=request.overwrite,
)
return SaveResponse(
@@ -328,6 +342,54 @@ async def check_duplicate(
}
@app.get("/api/tags", tags=["tags"])
async def list_tags(
session: Session = Depends(get_session),
) -> list[dict]:
"""Liste tous les tags disponibles pour le tagging des depenses.
Retourne une liste de tags avec leur id et nom.
"""
db_service = DatabaseService(session)
tags = db_service.list_tags()
return [{"id": tag.id, "nom": tag.nom} for tag in tags]
@app.post("/api/predict-tags", tags=["tags"])
async def predict_tags(
request: PredictTagsRequest,
session: Session = Depends(get_session),
) -> dict:
"""Predit les tags pour une liste de depenses basee sur l'historique.
- **depenses**: Liste des depenses a predire (avec fournisseur, sous_categorie, etc.)
Retourne une liste de predictions avec tag suggere, confiance et raison.
"""
try:
predictor = TagPredictor(session)
predictions = predictor.predict_batch(request.depenses)
return {
"predictions": [
{
"index": idx,
"tag_id": pred.tag_id,
"tag_name": pred.tag_name,
"confidence": pred.confidence,
"reason": pred.reason,
}
for idx, pred in enumerate(predictions)
]
}
except Exception as e:
raise HTTPException(
status_code=500, detail=f"Erreur lors de la prediction: {str(e)}"
)
# Mount static files for production (if dist exists)
if FRONTEND_DIST.exists():
# Serve static assets