""" 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)