Skip to content

Commit

Permalink
✅ Update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoinePELAMOURGUES committed Nov 21, 2024
1 parent 96bab83 commit 82e27eb
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 7 deletions.
43 changes: 41 additions & 2 deletions api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,30 +56,56 @@ class Token(BaseModel):
name='user_creation_requests_total',
documentation='Total number of user creation requests',
labelnames=['status_code'],
registry=collector
)

login_requests_counter = Counter(
name='login_requests_total',
documentation='Total number of login requests',
labelnames=['status_code'],
registry=collector
)

user_creation_duration_histogram = Histogram(
name='user_creation_duration_seconds',
documentation='Duration of user creation requests in seconds',
labelnames=['status_code'],
registry=collector
)

login_duration_histogram = Histogram(
name='login_duration_seconds',
documentation='Duration of login requests in seconds',
labelnames=['status_code'],
registry=collector
)

error_counter = Counter(
name='user_creation_errors_total',
documentation='Total number of user creation errors',
labelnames=['error_type'],
registry=collector
)

password_validation_counter = Counter(
name='password_validation_errors_total',
documentation='Total number of password validation errors',
labelnames=['error_type'],
registry=collector
)

email_validation_counter = Counter(
name='email_validation_errors_total',
documentation='Total number of email validation errors',
labelnames=['error_type'],
registry=collector
)

username_validation_counter = Counter(
name='username_validation_errors_total',
documentation='Total number of username validation errors',
labelnames=['error_type'],
registry=collector
)

# Fonction pour valider le nom d'utilisateur
Expand Down Expand Up @@ -117,17 +143,23 @@ async def create_user(create_user_request: CreateUserRequest):
# Validation checks
username_error = validate_username(create_user_request.username)
if username_error:
username_validation_counter.labels(error_type='invalid_username').inc()
error_counter.labels(error_type='invalid_username').inc()
logger.error(f"Erreur validation nom d'utilisateur: {username_error}")
raise HTTPException(status_code=400, detail=username_error)

mail_error = validate_email(create_user_request.email)
if mail_error:
email_validation_counter.labels(error_type='invalid_mail').inc()
error_counter.labels(error_type='invalid_mail').inc()
logger.error(f"Erreur validation email: {mail_error}")
raise HTTPException(status_code=400, detail=mail_error)

password_error = validate_password(create_user_request.password)
if password_error:
password_validation_counter.labels(error_type='invalid_password').inc()
error_counter.labels(error_type='invalid_password').inc()
logger.error(f"Erreur validation mot de passe: {password_error}")
raise HTTPException(status_code=400, detail=password_error)

try:
Expand All @@ -137,22 +169,24 @@ async def create_user(create_user_request: CreateUserRequest):
if cur.fetchone() is not None:
error_counter.labels(error_type='username_already_registered').inc()
user_creation_counter.labels(status_code='400').inc()
logger.error("Email déjà enregistré")
raise HTTPException(status_code=400, detail="Email already registered")

# Créer le nouvel utilisateur
hached_password = bcrypt_context.hash(create_user_request.password)
cur.execute("INSERT INTO users (username, email, hached_password) VALUES (%s, %s, %s)", (create_user_request.username, create_user_request.email, hached_password,))
conn.commit()
print("transaction validée")
logger.info("Utilisateur créé avec succès")

except psycopg2.Error as e:
error_counter.labels(error_type='database_error').inc()
logger.error(f"Erreur base de données: {str(e)}")
raise HTTPException(status_code=500, detail=f"Database error: {str(e)}")

duration = time.time() - start_time
user_creation_duration_histogram.labels(status_code='201').observe(duration)
user_creation_counter.labels(status_code='201').inc()

logger.info(f"Durée de création utilisateur: {duration} secondes")

# Route pour obtenir un token d'accès
@router.post("/token", response_model=Token)
Expand All @@ -163,12 +197,14 @@ async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm,
logger.info(f"Retour fonction authenticate_user: {user}")
if not user:
login_requests_counter.labels(status_code='401').inc()
logger.error("Échec de l'authentification: utilisateur non valide")
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail='Could not validate user.')

token = create_access_token(user['email'], user['userId'], timedelta(minutes=30))
duration = time.time() - start_time
login_duration_histogram.labels(status_code='200').observe(duration)
login_requests_counter.labels(status_code='200').inc()
logger.info(f"Durée de connexion: {duration} secondes")

# Modification de la structure de réponse pour garantir la cohérence
response = {
Expand All @@ -193,10 +229,12 @@ async def authenticate_user(email: str, password: str):

if not user:
login_requests_counter.labels(status_code='404').inc()
logger.error("Utilisateur non trouvé")
raise HTTPException(status_code=404, detail="Utilisateur non trouvé")

if not bcrypt_context.verify(password, user[3]):
login_requests_counter.labels(status_code='401').inc()
logger.error("Mot de passe incorrect")
raise HTTPException(status_code=401, detail="Mot de passe incorrect")

# Modification de la structure retournée pour garantir la cohérence
Expand All @@ -211,6 +249,7 @@ async def authenticate_user(email: str, password: str):

except psycopg2.Error as e:
error_counter.labels(error_type='database_error').inc()
logger.error(f"Erreur base de données: {str(e)}")
raise HTTPException(status_code=500, detail=f"Database error: {str(e)}")


Expand Down
43 changes: 38 additions & 5 deletions api/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,18 @@ def movie_finder(title):
documentation='Count of API errors by type',
labelnames=['error_type'],
registry=collector)
# Nombre de films recommandés
recommendations_counter = Counter(
name='number_of_recommendations',
documentation='Number of movie recommendations made',
labelnames=['endpoint'],
registry=collector)
# Temps de traitement des requêtes TMDB
tmdb_request_duration_histogram = Histogram(
name='tmdb_request_duration_seconds',
documentation='Duration of TMDB API requests',
labelnames=['endpoint'],
registry=collector)

# ---------------------------------------------------------------

Expand Down Expand Up @@ -318,7 +330,11 @@ async def predict(user_request: UserRequest) -> Dict[str, Any]:
df_user = df_user.sort_values(by='rating', ascending=False)
best_movies = df_user.head(3)
imdb_list = [imdb_dict[movie_id] for movie_id in best_movies['movieId'] if movie_id in imdb_dict]
start_tmdb_time = time.time()
results = api_tmdb_request(imdb_list)
tmdb_duration = time.time() - start_tmdb_time
tmdb_request_duration_histogram.labels(endpoint='/predict/best_user_movies').observe(tmdb_duration)
recommendations_counter.labels(endpoint='/predict/best_user_movies').inc(len(results))
# Mesurer la taille de la réponse et l'enregistrer
response_size = len(json.dumps(results))
# Calculer la durée et enregistrer dans l'histogramme
Expand All @@ -329,10 +345,13 @@ async def predict(user_request: UserRequest) -> Dict[str, Any]:
response_size_histogram.labels(method='POST', endpoint='/predict/best_user_movies').observe(response_size) # Enregistrer la taille de la réponse
# Utiliser le logger pour voir les résultats
logger.info(f"Api response: {results}")
logger.info(f"Durée de la requête: {duration} secondes")
logger.info(f"Taille de la réponse: {response_size} octets")
return results
except ValueError as e:
status_code_counter.labels(status_code="400").inc() # Compter les réponses échouées
error_counter.labels(error_type="ValueError").inc() # Enregistrer l'erreur spécifique
logger.error(f"Erreur de conversion de l'ID utilisateur: {e}")
raise HTTPException(status_code=400, detail="L'ID utilisateur doit être un nombre entier")


Expand Down Expand Up @@ -363,9 +382,11 @@ async def predict(user_request: UserRequest) -> Dict[str, Any]:
recommendations = get_user_recommendations(user_id, model_svd, ratings, n_recommendations = 8)
logger.info(f"Recommandations pour l'utilisateur {userId}: {recommendations}")
imdb_list = [imdb_dict[movie_id] for movie_id in recommendations if movie_id in imdb_dict]
start_tmdb_time = time.time()
results = api_tmdb_request(imdb_list)


tmdb_duration = time.time() - start_tmdb_time
tmdb_request_duration_histogram.labels(endpoint='/predict/identified_user').observe(tmdb_duration)
recommendations_counter.labels(endpoint='/predict/identified_user').inc(len(results))
# Mesurer la taille de la réponse et l'enregistrer
response_size = len(json.dumps(results))
# Calculer la durée et enregistrer dans l'histogramme
Expand All @@ -376,11 +397,14 @@ async def predict(user_request: UserRequest) -> Dict[str, Any]:
response_size_histogram.labels(method='POST', endpoint='/predict/identified_user').observe(response_size) # Enregistrer la taille de la réponse
# Utiliser le logger pour voir les résultats
logger.info(f"Api response: {results}")
logger.info(f"Durée de la requête: {duration} secondes")
logger.info(f"Taille de la réponse: {response_size} octets")
return results

except ValueError as e:
status_code_counter.labels(status_code="400").inc() # Compter les réponses échouées
error_counter.labels(error_type="ValueError").inc() # Enregistrer l'erreur spécifique
logger.error(f"Erreur de conversion de l'ID utilisateur: {e}")
raise HTTPException(status_code=400, detail="L'ID utilisateur doit être un nombre entier")


Expand All @@ -404,17 +428,26 @@ async def predict(user_request: UserRequest) -> Dict[str, Any]:
# Récupérer les ID des films recommandés en utilisant la fonction de similarité
recommendations = get_movie_title_recommendations(model_Knn, movie_id, X, movie_mapper, movie_inv_mapper, 9)
imdb_list = [imdb_dict[movie_id] for movie_id in recommendations if movie_id in imdb_dict]
start_tmdb_time = time.time()
results = api_tmdb_request(imdb_list)

tmdb_duration = time.time() - start_tmdb_time
tmdb_request_duration_histogram.labels(endpoint='/predict/similar_movies').observe(tmdb_duration)
recommendations_counter.labels(endpoint='/predict/similar_movies').inc(len(results))
# Mesurer la taille de la réponse et l'enregistrer
response_size = len(json.dumps(results))
# Calculer la durée et enregistrer dans l'histogramme
duration = time.time() - start_time
# Enregistrement des métriques pour Prometheus
# Enregistrement des m��triques pour Prometheus
status_code_counter.labels(status_code="200").inc() # Compter les réponses réussies
duration_of_requests_histogram.labels(method='POST', endpoint='/predict/similar_movies', user_id="N/A").observe(duration) # Enregistrer la durée de la requête
response_size_histogram.labels(method='POST', endpoint='/predict/similar_movies').observe(response_size) # Enregistrer la taille de la réponse
logger.info(f"Api response: {results}")
response_size_histogram.labels(method='POST', endpoint='/identified_user').observe(response_size) # Enregistrer la taille de la réponse
logger.info(f"Durée de la requête: {duration} secondes")
logger.info(f"Taille de la réponse: {response_size} octets")
return results
except Exception as e:
status_code_counter.labels(status_code="500").inc() # Compter les réponses échouées
error_counter.labels(error_type="Exception").inc() # Enregistrer l'erreur spécifique
logger.error(f"Erreur lors du traitement de la requête: {e}")
raise HTTPException(status_code=500, detail="Erreur interne du serveur")

0 comments on commit 82e27eb

Please sign in to comment.