File size: 5,025 Bytes
84c7ce0
 
2e32ddd
2b16a80
84c7ce0
 
 
 
57af3d0
84c7ce0
8165461
2e32ddd
c42e6f5
 
84c7ce0
2b16a80
84c7ce0
2d06d01
 
 
84c7ce0
 
 
 
 
 
037629b
84c7ce0
2b16a80
 
037629b
84c7ce0
a8ee0db
2e32ddd
2b16a80
 
2e32ddd
 
a8ee0db
 
2e32ddd
 
 
 
 
 
 
c42e6f5
84c7ce0
 
2d06d01
6fd206b
84c7ce0
a8ee0db
84c7ce0
 
2b16a80
8165461
2b16a80
8165461
c42e6f5
2e32ddd
2b16a80
84c7ce0
2e32ddd
 
84c7ce0
 
 
 
037629b
ae434c1
 
 
 
84c7ce0
 
037629b
 
84c7ce0
ae434c1
 
84c7ce0
ae434c1
84c7ce0
f95f21f
 
84c7ce0
037629b
 
ae434c1
 
 
037629b
ae434c1
 
 
 
 
037629b
84c7ce0
2e32ddd
 
84c7ce0
 
 
c42e6f5
2e32ddd
84c7ce0
2d06d01
 
 
 
 
 
84c7ce0
 
 
 
 
 
 
 
 
2d06d01
3181519
84c7ce0
2b16a80
 
 
 
 
2d06d01
 
 
c42e6f5
84c7ce0
c42e6f5
2e32ddd
84c7ce0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import logging
import sys
import os
import json
import tempfile
from datetime import datetime

# CORRECTION : Assurez-vous que 'Request' est bien présent dans cette ligne d'import
from fastapi import FastAPI, Request, HTTPException, UploadFile, File, BackgroundTasks
from fastapi.responses import JSONResponse
from fastapi.concurrency import run_in_threadpool
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from typing import List, Dict, Any, Optional
from bson import ObjectId

# --- Imports de vos services et classes ---
from src.models import load_all_models
from src.services.cv_service import CVParsingService
from src.services.analysis_service import AnalysisService
from services.graph_service import GraphInterviewProcessor

# --- Configuration du logging ---
logging.basicConfig(level=logging.INFO)
# Le logger global est utilisé pour les messages au démarrage de l'application.
logger = logging.getLogger(__name__)

# --- Configuration de l'environnement pour les fichiers temporaires ---
os.makedirs('/tmp/feedbacks', exist_ok=True)


# --- Initialisation de l'application FastAPI ---
app = FastAPI(
    title="AIrh Interview Assistant",
    description="API pour l'analyse de CV et la simulation d'entretiens d'embauche avec analyse asynchrone.",
    version="2.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# --- Initialisation des services ---
logger.info("Chargement des modèles et initialisation des services...")
models = load_all_models()
cv_service = CVParsingService(models)
logger.info("Services initialisés.")


# --- Définition des modèles Pydantic ---
class Feedback(BaseModel):
    status: str
    feedback_data: Optional[Dict[str, Any]] = None

class HealthCheck(BaseModel):
    status: str = "ok"

# --- Endpoint de santé ---
@app.get("/", response_model=HealthCheck, tags=["Status"])
async def health_check():
    return HealthCheck()

# --- Endpoint principal pour la simulation d'entretien ---
@app.post("/api/v1/simulate-interview/")
async def simulate_interview(request: Request):
    """
    Ce endpoint reçoit les données de l'entretien, instancie le processeur de graphe
    et lance la conversation.
    """
    # CORRECTION : Récupérer l'instance du logger pour garantir sa disponibilité dans le scope de la fonction.
    logger = logging.getLogger(__name__)
    try:
        payload = await request.json()
        
        if not all(k in payload for k in ["user_id", "job_offer_id", "cv_document", "job_offer"]):
            raise HTTPException(status_code=400, detail="Données manquantes dans le payload (user_id, job_offer_id, cv_document, job_offer).")
            
        logger.info(f"Début de la simulation pour l'utilisateur : {payload['user_id']}")
        
        processor = GraphInterviewProcessor(payload)
        result = processor.invoke(payload.get("messages", []))
        
        return JSONResponse(content=result)

    except ValueError as ve:
        logger.error(f"Erreur de validation des données : {ve}", exc_info=True)
        return JSONResponse(content={"error": str(ve)}, status_code=400)
    except Exception as e:
        logger.error(f"Erreur interne dans le endpoint simulate-interview: {e}", exc_info=True)
        return JSONResponse(
            content={"error": "Une erreur interne est survenue sur le serveur de l'assistant."},
            status_code=500
        )

# --- Endpoint pour l'analyse de CV ---
@app.post("/parse-cv/", tags=["CV Parsing"])
async def parse_cv(file: UploadFile = File(...)):
    """
    Analyse un fichier CV (PDF) et retourne les données extraites.
    """
    if file.content_type != "application/pdf":
        raise HTTPException(status_code=400, detail="Fichier PDF requis")
    
    contents = await file.read()
    
    with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
        tmp.write(contents)
        tmp_path = tmp.name
    
    try:
        result = await run_in_threadpool(cv_service.parse_cv, tmp_path)
    finally:
        if os.path.exists(tmp_path):
            os.remove(tmp_path)
            
    if not result:
        raise HTTPException(status_code=500, detail="Échec de l'extraction des données du CV.")
        
    return result

# --- Endpoint pour récupérer le feedback ---
@app.get("/get-feedback/{user_id}", response_model=Feedback, tags=["Analysis"])
async def get_feedback(user_id: str):
    feedback_path = f"/tmp/feedbacks/{user_id}.json"
    if not os.path.exists(feedback_path):
        raise HTTPException(status_code=404, detail="Feedback non trouvé ou non encore traité.")
    with open(feedback_path, "r", encoding="utf-8") as f:
        data = json.load(f)
    return Feedback(**data)

# --- Démarrage de l'application (pour un test local) ---
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)