QuentinL52's picture
Update main.py
66c37ba verified
raw
history blame
5.85 kB
import logging
import os
import requests # Ajout de la librairie pour les requêtes HTTP
from fastapi import FastAPI, HTTPException, Body, UploadFile, File
from pydantic import BaseModel
from typing import List, Dict, Any
from dotenv import load_dotenv
from fastapi.concurrency import run_in_threadpool
# --- Import de VOS modules de travail ---
from src.cv_parsing_agents import CVParser
from src.interview_simulator.entretient_version_prod import InterviewProcessor
from src.config import Config
# --- Celery n'est plus importé ici ---
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# --- Récupération de l'URL du nouveau service ---
# Vous devrez ajouter cette variable à votre environnement sur la plateforme où vous déploierez cette API.
CELERY_SERVICE_URL = os.environ.get("CELERY_SERVICE_URL")
if not CELERY_SERVICE_URL:
logger.warning("La variable d'environnement CELERY_SERVICE_URL n'est pas définie. Les analyses asynchrones échoueront.")
app = FastAPI(
title="AIrh Main API",
description="API principale gérant le parsing de CV et la simulation interactive.",
version="2.1.0"
)
# --- Modèles de données Pydantic ---
class ParsedCVResponse(BaseModel):
candidat: Dict[str, Any]
class InterviewRequest(BaseModel):
cv_document: Dict[str, Any]
job_offer: Dict[str, Any]
messages: List[Dict[str, Any]]
conversation_history: List[Dict[str, Any]]
class InterviewResponse(BaseModel):
response: str
class AnalysisRequest(BaseModel):
conversation_history: List[Dict[str, Any]]
job_description_text: str
class TaskStatusResponse(BaseModel):
task_id: str
status: str
result: Any = None
# --- Endpoints de l'API ---
@app.get("/", summary="Health Check")
async def read_root():
return {"message": "AIrh Main API est opérationnelle."}
# --- SECTION ORIGINALE (INCHANGÉE) ---
@app.post("/parse-cv/", response_model=ParsedCVResponse, tags=["1. Parsing de CV"])
async def parse_cv(file: UploadFile = File(...)):
logger.info(f"Réception du fichier CV: {file.filename}")
cv_content = await file.read()
if not cv_content:
raise HTTPException(status_code=400, detail="Le fichier CV est vide.")
try:
parser = CVParser()
parsed_data = await run_in_threadpool(parser.parse, cv_content)
if not parsed_data or "candidat" not in parsed_data:
raise HTTPException(status_code=422, detail="Impossible d'extraire les données structurées du CV.")
return parsed_data
except Exception as e:
logger.error(f"Erreur critique lors du parsing du CV: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Erreur interne du serveur lors du parsing: {str(e)}")
@app.post("/simulate-interview/", response_model=InterviewResponse, tags=["2. Simulation d'Entretien"])
async def simulate_interview(request: InterviewRequest):
logger.info("Réception d'une requête pour la simulation d'entretien.")
try:
processor = InterviewProcessor(
cv_document=request.cv_document,
job_offer=request.job_offer,
conversation_history=request.conversation_history
)
ai_response_object = await run_in_threadpool(processor.run, messages=request.messages)
last_message = ai_response_object["messages"][-1].content
return {"response": last_message}
except Exception as e:
logger.error(f"Erreur lors de la simulation d'entretien: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Erreur interne du serveur lors de la simulation: {str(e)}")
# --- SECTION MODIFIÉE POUR APPELER LE SERVICE EXTERNE ---
@app.post("/trigger-analysis/", response_model=TaskStatusResponse, status_code=202, tags=["3. Analyse Asynchrone (Externe)"])
async def trigger_analysis(request: AnalysisRequest):
"""
Déclenche l'analyse en appelant le service Celery externe.
"""
logger.info("Redirection de la demande d'analyse vers le service Celery externe.")
if not CELERY_SERVICE_URL:
raise HTTPException(status_code=503, detail="Le service d'analyse est actuellement indisponible.")
try:
# On fait une requête POST à notre service Celery sur Render
api_url = f"{CELERY_SERVICE_URL}/trigger-analysis"
logger.info(f"Appel de l'API externe : {api_url}")
response = requests.post(api_url, json=request.dict())
response.raise_for_status() # Lève une exception si le statut n'est pas 2xx
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Erreur de communication avec le service Celery: {e}")
raise HTTPException(status_code=502, detail="Erreur de communication avec le service d'analyse.")
@app.get("/analysis-status/{task_id}", response_model=TaskStatusResponse, tags=["3. Analyse Asynchrone (Externe)"])
async def get_analysis_status(task_id: str):
"""
Vérifie le statut d'une tâche en interrogeant le service Celery externe.
"""
logger.info(f"Vérification du statut de la tâche externe: {task_id}")
if not CELERY_SERVICE_URL:
raise HTTPException(status_code=503, detail="Le service d'analyse est actuellement indisponible.")
try:
# On fait une requête GET à notre service Celery sur Render
api_url = f"{CELERY_SERVICE_URL}/analysis-status/{task_id}"
logger.info(f"Appel de l'API externe : {api_url}")
response = requests.get(api_url)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Erreur de communication avec le service Celery: {e}")
raise HTTPException(status_code=502, detail="Erreur de communication avec le service d'analyse.")