4NK_IA_back/services/host_api/app_complete.py
ncantu 884a8eed96 fix: Corrections finales et optimisations
- Corrections mineures dans les pipelines
- Optimisations de l'API complète
- Améliorations de la documentation
- Finalisation du système
2025-09-09 04:57:45 +02:00

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)