
- Corrections mineures dans les pipelines - Optimisations de l'API complète - Améliorations de la documentation - Finalisation du système
364 lines
12 KiB
Python
364 lines
12 KiB
Python
"""
|
|
API complète pour le système notarial avec base de données et pipelines
|
|
"""
|
|
|
|
from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Depends
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Dict, Any
|
|
import uvicorn
|
|
import asyncio
|
|
from datetime import datetime
|
|
import uuid
|
|
|
|
# Import des modèles et de la base de données
|
|
from domain.database import get_db, init_db, check_db_connection
|
|
from domain.models import Document, Entity, Verification, ProcessingLog
|
|
|
|
# Configuration
|
|
app = FastAPI(
|
|
title="API Notariale Complète",
|
|
description="API complète pour l'analyse de documents notariaux",
|
|
version="1.0.0"
|
|
)
|
|
|
|
# CORS
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
@app.on_event("startup")
|
|
async def startup_event():
|
|
"""Initialisation au démarrage"""
|
|
print("🚀 Démarrage de l'API Notariale")
|
|
|
|
# Vérification de la connexion à la base de données
|
|
if check_db_connection():
|
|
print("✅ Connexion à la base de données réussie")
|
|
# Initialisation des tables
|
|
init_db()
|
|
else:
|
|
print("⚠️ Connexion à la base de données échouée, mode dégradé")
|
|
|
|
@app.get("/")
|
|
async def root():
|
|
"""Page d'accueil"""
|
|
return {
|
|
"message": "API Notariale Complète - Version 1.0.0",
|
|
"status": "operational",
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
@app.get("/api/health")
|
|
async def health_check():
|
|
"""Vérification de l'état de l'API"""
|
|
db_status = check_db_connection()
|
|
|
|
return {
|
|
"status": "healthy" if db_status else "degraded",
|
|
"timestamp": datetime.now().isoformat(),
|
|
"version": "1.0.0",
|
|
"services": {
|
|
"api": "OK",
|
|
"database": "OK" if db_status else "ERROR",
|
|
"llm": "Simulé",
|
|
"external_apis": "Simulé"
|
|
}
|
|
}
|
|
|
|
@app.get("/api/notary/stats")
|
|
async def get_stats(db: Session = Depends(get_db)):
|
|
"""Statistiques des documents"""
|
|
try:
|
|
total_docs = db.query(Document).count()
|
|
processed = db.query(Document).filter(Document.status == "completed").count()
|
|
processing = db.query(Document).filter(Document.status == "processing").count()
|
|
error = db.query(Document).filter(Document.status == "error").count()
|
|
|
|
return {
|
|
"total_documents": total_docs,
|
|
"processed": processed,
|
|
"processing": processing,
|
|
"error": error,
|
|
"pending": total_docs - processed - processing - error
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"total_documents": 0,
|
|
"processed": 0,
|
|
"processing": 0,
|
|
"error": 0,
|
|
"pending": 0,
|
|
"error": str(e)
|
|
}
|
|
|
|
@app.get("/api/notary/documents")
|
|
async def get_documents(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
status: str = None,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Liste des documents"""
|
|
try:
|
|
query = db.query(Document)
|
|
|
|
if status:
|
|
query = query.filter(Document.status == status)
|
|
|
|
documents = query.offset(skip).limit(limit).all()
|
|
|
|
return {
|
|
"documents": [
|
|
{
|
|
"id": doc.id,
|
|
"filename": doc.filename,
|
|
"status": doc.status,
|
|
"progress": doc.progress,
|
|
"document_type": doc.document_type,
|
|
"created_at": doc.created_at.isoformat() if doc.created_at else None,
|
|
"updated_at": doc.updated_at.isoformat() if doc.updated_at else None
|
|
}
|
|
for doc in documents
|
|
],
|
|
"total": db.query(Document).count()
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@app.get("/api/notary/documents/{document_id}")
|
|
async def get_document(document_id: str, db: Session = Depends(get_db)):
|
|
"""Détails d'un document"""
|
|
try:
|
|
document = db.query(Document).filter(Document.id == document_id).first()
|
|
|
|
if not document:
|
|
raise HTTPException(status_code=404, detail="Document non trouvé")
|
|
|
|
# Récupération des entités
|
|
entities = db.query(Entity).filter(Entity.document_id == document_id).all()
|
|
|
|
# Récupération des vérifications
|
|
verifications = db.query(Verification).filter(Verification.document_id == document_id).all()
|
|
|
|
return {
|
|
"id": document.id,
|
|
"filename": document.filename,
|
|
"status": document.status,
|
|
"progress": document.progress,
|
|
"current_step": document.current_step,
|
|
"document_type": document.document_type,
|
|
"confidence_score": document.confidence_score,
|
|
"ocr_text": document.ocr_text,
|
|
"created_at": document.created_at.isoformat() if document.created_at else None,
|
|
"updated_at": document.updated_at.isoformat() if document.updated_at else None,
|
|
"processed_at": document.processed_at.isoformat() if document.processed_at else None,
|
|
"entities": [
|
|
{
|
|
"type": entity.entity_type,
|
|
"value": entity.entity_value,
|
|
"confidence": entity.confidence,
|
|
"context": entity.context
|
|
}
|
|
for entity in entities
|
|
],
|
|
"verifications": [
|
|
{
|
|
"type": verif.verification_type,
|
|
"status": verif.verification_status,
|
|
"result_data": verif.result_data,
|
|
"error_message": verif.error_message
|
|
}
|
|
for verif in verifications
|
|
]
|
|
}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@app.post("/api/notary/upload")
|
|
async def upload_document(
|
|
file: UploadFile = File(...),
|
|
id_dossier: str = Form(...),
|
|
etude_id: str = Form(...),
|
|
utilisateur_id: str = Form(...),
|
|
source: str = Form("upload"),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Upload d'un document"""
|
|
try:
|
|
# Validation du fichier
|
|
if not file.filename:
|
|
raise HTTPException(status_code=400, detail="Aucun fichier fourni")
|
|
|
|
# Génération d'un ID unique
|
|
doc_id = str(uuid.uuid4())
|
|
|
|
# Création du document en base
|
|
document = Document(
|
|
id=doc_id,
|
|
filename=file.filename,
|
|
original_filename=file.filename,
|
|
mime_type=file.content_type or "application/octet-stream",
|
|
size=file.size or 0,
|
|
id_dossier=id_dossier,
|
|
etude_id=etude_id,
|
|
utilisateur_id=utilisateur_id,
|
|
source=source,
|
|
status="uploaded",
|
|
progress=0
|
|
)
|
|
|
|
db.add(document)
|
|
db.commit()
|
|
db.refresh(document)
|
|
|
|
# Simulation du traitement (en attendant Celery)
|
|
asyncio.create_task(process_document_simulated(doc_id, db))
|
|
|
|
return {
|
|
"message": "Document uploadé avec succès",
|
|
"document_id": doc_id,
|
|
"status": "uploaded"
|
|
}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
db.rollback()
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
async def process_document_simulated(doc_id: str, db: Session):
|
|
"""Simulation du traitement d'un document"""
|
|
try:
|
|
# Mise à jour du statut
|
|
document = db.query(Document).filter(Document.id == doc_id).first()
|
|
if document:
|
|
document.status = "processing"
|
|
document.progress = 10
|
|
document.current_step = "Pré-traitement"
|
|
db.commit()
|
|
|
|
# Simulation des étapes
|
|
steps = [
|
|
("Pré-traitement", 20),
|
|
("OCR", 40),
|
|
("Classification", 60),
|
|
("Extraction d'entités", 80),
|
|
("Vérifications", 95),
|
|
("Finalisation", 100)
|
|
]
|
|
|
|
for step_name, progress in steps:
|
|
await asyncio.sleep(2) # Simulation du temps de traitement
|
|
|
|
if document:
|
|
document.progress = progress
|
|
document.current_step = step_name
|
|
db.commit()
|
|
|
|
# Résultats simulés
|
|
if document:
|
|
document.status = "completed"
|
|
document.progress = 100
|
|
document.current_step = "Terminé"
|
|
document.document_type = "acte_vente"
|
|
document.confidence_score = 0.85
|
|
document.ocr_text = "Texte extrait simulé du document..."
|
|
document.processed_at = datetime.utcnow()
|
|
db.commit()
|
|
|
|
# Ajout d'entités simulées
|
|
entities = [
|
|
Entity(
|
|
document_id=doc_id,
|
|
entity_type="person",
|
|
entity_value="Jean Dupont",
|
|
confidence=0.9,
|
|
context="Vendeur: Jean Dupont"
|
|
),
|
|
Entity(
|
|
document_id=doc_id,
|
|
entity_type="person",
|
|
entity_value="Marie Martin",
|
|
confidence=0.9,
|
|
context="Acquéreur: Marie Martin"
|
|
),
|
|
Entity(
|
|
document_id=doc_id,
|
|
entity_type="address",
|
|
entity_value="123 Rue de la Paix, 75001 Paris",
|
|
confidence=0.8,
|
|
context="Adresse du bien: 123 Rue de la Paix, 75001 Paris"
|
|
)
|
|
]
|
|
|
|
for entity in entities:
|
|
db.add(entity)
|
|
|
|
# Ajout de vérifications simulées
|
|
verifications = [
|
|
Verification(
|
|
document_id=doc_id,
|
|
verification_type="cadastre",
|
|
verification_status="success",
|
|
result_data={"status": "OK", "parcelle": "123456"}
|
|
),
|
|
Verification(
|
|
document_id=doc_id,
|
|
verification_type="georisques",
|
|
verification_status="success",
|
|
result_data={"status": "OK", "risques": []}
|
|
)
|
|
]
|
|
|
|
for verification in verifications:
|
|
db.add(verification)
|
|
|
|
db.commit()
|
|
|
|
except Exception as e:
|
|
print(f"Erreur lors du traitement simulé de {doc_id}: {e}")
|
|
if document:
|
|
document.status = "error"
|
|
document.current_step = f"Erreur: {str(e)}"
|
|
db.commit()
|
|
|
|
@app.delete("/api/notary/documents/{document_id}")
|
|
async def delete_document(document_id: str, db: Session = Depends(get_db)):
|
|
"""Suppression d'un document"""
|
|
try:
|
|
document = db.query(Document).filter(Document.id == document_id).first()
|
|
|
|
if not document:
|
|
raise HTTPException(status_code=404, detail="Document non trouvé")
|
|
|
|
# Suppression des entités associées
|
|
db.query(Entity).filter(Entity.document_id == document_id).delete()
|
|
|
|
# Suppression des vérifications associées
|
|
db.query(Verification).filter(Verification.document_id == document_id).delete()
|
|
|
|
# Suppression des logs de traitement
|
|
db.query(ProcessingLog).filter(ProcessingLog.document_id == document_id).delete()
|
|
|
|
# Suppression du document
|
|
db.delete(document)
|
|
db.commit()
|
|
|
|
return {"message": "Document supprimé avec succès"}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
db.rollback()
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
if __name__ == "__main__":
|
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|