Skip to content

Develop#1

Merged
SaidaAourras merged 60 commits intomainfrom
develop
Feb 28, 2026
Merged

Develop#1
SaidaAourras merged 60 commits intomainfrom
develop

Conversation

@SaidaAourras
Copy link
Copy Markdown
Owner

No description provided.

SaidaAourras and others added 27 commits February 24, 2026 22:59
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Cette pull request établit les fondations du backend de l'application HR-Pulse en introduisant une architecture robuste et des pratiques de développement modernes. Elle intègre la conteneurisation Docker, une gestion structurée des dépendances Python, des routes API pour la gestion des offres d'emploi et la prédiction salariale, ainsi qu'un système d'authentification complet. La réorganisation des modules de Machine Learning et de pipeline de données assure une meilleure maintenabilité et évolutivité, tandis que l'ajout de tests unitaires et d'une documentation détaillée facilite la compréhension et la collaboration.

Highlights

  • Infrastructure et Conteneurisation: Un nouveau Dockerfile a été introduit pour la construction multi-étapes de l'application FastAPI, utilisant uv pour la gestion des dépendances. Les fichiers .dockerignore et .python-version ont été ajoutés pour optimiser les builds Docker et spécifier la version de Python.
  • Architecture et Organisation du Projet: La structure du projet a été refactorisée avec de nouveaux modules pour les modèles de base de données (SQLAlchemy), les schémas Pydantic, les services métier, et les routes API. Les composants de Machine Learning et de pipeline de données ont également été réorganisés dans des répertoires dédiés.
  • Authentification Utilisateur: Un système d'authentification a été mis en place, incluant des routes pour l'enregistrement, la connexion et la déconnexion, avec gestion des tokens JWT et hachage des mots de passe.
  • Pipeline de Données et Modèle ML: De nouveaux scripts ont été ajoutés pour le nettoyage des données (clean.py), l'extraction d'entités nommées (NER) via spaCy localement (ner_local.py) ou Azure AI Language (ner_azure.py), l'injection de données dans la base de données (database_inject.py), et l'entraînement du modèle de prédiction salariale (train.py). Un notebook (train_model.ipynb) détaille le processus d'entraînement.
  • Documentation et Tests: Le fichier README.md a été considérablement mis à jour pour refléter la nouvelle architecture et les instructions d'installation. Des tests unitaires ont été ajoutés pour les routes jobs et predict, avec une configuration Pytest et une base de données SQLite en mémoire pour les tests.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .dockerignore
    • Ajouté un nouveau fichier pour exclure les fichiers et répertoires non nécessaires des images Docker.
  • .gitignore
    • Mis à jour pour inclure de nouveaux répertoires et types de fichiers à ignorer, tels que .venv, __pycache__, et les fichiers de données.
  • .python-version
    • Ajouté un fichier spécifiant la version de Python 3.11.
  • Dockerfile
    • Ajouté un nouveau Dockerfile multi-étapes pour construire l'application FastAPI, incluant l'installation de uv et des dépendances système.
  • README.md
    • Mis à jour avec des sections détaillées sur l'architecture, l'installation, le pipeline de données, les endpoints API, le modèle ML, les tests, Docker, CI/CD et les variables d'environnement.
  • backend/app/api/db/database.py
    • Ajouté un fichier pour la configuration de la base de données SQLAlchemy, y compris le moteur, la session et la base déclarative.
  • backend/app/api/db/models/job.py
    • Ajouté le modèle SQLAlchemy pour les offres d'emploi, incluant l'ID, le titre et les compétences extraites.
  • backend/app/api/db/models/user.py
    • Ajouté le modèle SQLAlchemy pour les utilisateurs, incluant l'ID, le nom d'utilisateur, l'email et le hachage du mot de passe.
  • backend/app/api/db/schemas/job.py
    • Ajouté les schémas Pydantic pour la validation et la sérialisation des données d'offres d'emploi.
  • backend/app/api/db/schemas/predict.py
    • Ajouté les schémas Pydantic pour les requêtes et réponses de prédiction.
  • backend/app/api/db/schemas/user.py
    • Ajouté les schémas Pydantic pour l'enregistrement, la connexion et les réponses de token utilisateur.
  • backend/app/api/routes/auth.py
    • Ajouté de nouvelles routes API pour l'authentification des utilisateurs (enregistrement, connexion, déconnexion).
  • backend/app/api/routes/jobs.py
    • Modifié les routes des offres d'emploi pour intégrer la dépendance d'authentification JWT.
  • backend/app/api/routes/predict.py
    • Modifié la route de prédiction pour utiliser le nouveau module de services de prédiction.
  • backend/app/ml/models/init.py
    • Renommé le fichier backend/app/core/__init__.py en backend/app/ml/models/__init__.py.
  • backend/app/ml/models/job.py
    • Renommé le fichier backend/app/models/job.py en backend/app/ml/models/job.py.
  • backend/app/ml/models/model_meta.json
    • Ajouté un fichier JSON contenant les métadonnées du modèle ML, y compris les colonnes catégorielles et les métriques d'évaluation.
  • backend/app/ml/notebooks/train_model.ipynb
    • Ajouté un notebook Jupyter détaillant le processus d'entraînement du modèle de Machine Learning.
  • backend/app/ml/predictor/predict.py
    • Renommé le fichier frontend/app/pages/predict.py en backend/app/ml/predictor/predict.py et adapté pour la logique de prédiction.
  • backend/app/ml/predictor/train.py
    • Ajouté un script pour l'entraînement du modèle ML et la sauvegarde des artefacts (modèle, vectoriseurs, encodeur).
  • backend/app/pipeline/init.py
    • Renommé le fichier backend/app/models/__init__.py en backend/app/pipeline/__init__.py.
  • backend/app/pipeline/clean.py
    • Ajouté un script pour le nettoyage des données brutes des offres d'emploi.
  • backend/app/pipeline/database_inject.py
    • Ajouté un script pour la création des tables de base de données et l'injection des données d'offres d'emploi nettoyées.
  • backend/app/pipeline/ner_azure.py
    • Ajouté un script pour l'extraction d'entités nommées (NER) utilisant Azure AI Language.
  • backend/app/pipeline/ner_local.py
    • Ajouté un script pour l'extraction d'entités nommées (NER) localement avec spaCy.
  • backend/app/services/auth_services.py
    • Ajouté un nouveau service pour la création et la vérification des tokens JWT.
  • backend/app/services/job_services.py
    • Ajouté un nouveau service pour interagir avec les données des offres d'emploi dans la base de données.
  • backend/app/services/predict_services.py
    • Ajouté un nouveau service pour charger les artefacts du modèle ML et effectuer des prédictions salariales.
  • backend/app/services/user_services.py
    • Ajouté un nouveau service pour la création et la vérification des utilisateurs.
  • backend/app/utils/hashing.py
    • Ajouté un utilitaire pour le hachage et la vérification des mots de passe.
  • docker-compose.yml
    • Mis à jour pour inclure la configuration du service backend, frontend et jaeger, avec des volumes et des dépendances.
  • main.py
    • Ajouté le fichier principal de l'application FastAPI, incluant l'initialisation de la base de données, le middleware CORS et l'inclusion des routeurs.
  • pyproject.toml
    • Ajouté un nouveau fichier pour la gestion des dépendances du projet avec uv, séparant les dépendances de l'API et du pipeline.
  • ruff.toml
    • Ajouté un nouveau fichier pour la configuration du linter Ruff.
  • setup_project.bat
    • Supprimé le script batch de configuration du projet.
  • tests/init.py
    • Renommé le fichier backend/tests/__init__.py en tests/__init__.py.
  • tests/conftest.py
    • Ajouté un fichier de configuration Pytest pour la base de données de test et les fixtures d'authentification.
  • tests/test_routes_jobs.py
    • Ajouté des tests unitaires pour les routes API liées aux offres d'emploi.
  • tests/test_routes_predict.py
    • Ajouté des tests unitaires pour la route API de prédiction.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/ci.yml
Activity
  • Le développeur SaidaAourras a initié cette pull request pour intégrer des changements significatifs à l'infrastructure et à l'architecture du projet.
  • De nombreux nouveaux fichiers ont été ajoutés, couvrant la conteneurisation Docker, la gestion des dépendances Python, les modèles de base de données, les schémas de données, les services métier, les routes API, les pipelines de données ML et les tests unitaires.
  • Des fichiers existants ont été renommés et modifiés pour s'adapter à la nouvelle structure du projet.
  • La documentation README.md a été mise à jour de manière exhaustive pour guider les utilisateurs et les développeurs à travers les nouvelles fonctionnalités et la configuration du projet.
  • Un script de configuration de projet obsolète (setup_project.bat) a été supprimé, indiquant une transition vers des méthodes de configuration plus modernes et standardisées.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@SaidaAourras SaidaAourras merged commit 50bb02b into main Feb 28, 2026
6 checks passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Ce pull request introduit l'ensemble du backend pour le projet HR-Pulse. Il s'agit d'une initialisation de projet très complète, incluant l'API FastAPI, le pipeline de données, le modèle de machine learning, la configuration Docker et les tests. Mon retour se concentre sur plusieurs points critiques de sécurité, des bugs qui empêcheraient le code de fonctionner, ainsi que des améliorations de robustesse et de maintenabilité. J'ai identifié une vulnérabilité de sécurité critique dans le processus de connexion qui doit être corrigée en priorité. D'autres problèmes incluent des bugs dans les scripts de pipeline, une configuration Docker à améliorer pour la production, et des pratiques à revoir pour augmenter la robustesse de l'application.

load_dotenv()

SECRET_KEY = os.getenv('SECRET_KEY')
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('ACCESS_TOKEN_EXPIRE_MINUTES',30))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

La valeur par défaut pour os.getenv doit être une chaîne de caractères. En passant l'entier 30, une TypeError sera levée si la variable d'environnement ACCESS_TOKEN_EXPIRE_MINUTES n'est pas définie, ce qui empêchera l'application de démarrer. La valeur par défaut doit être '30'.

Suggested change
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('ACCESS_TOKEN_EXPIRE_MINUTES',30))
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('ACCESS_TOKEN_EXPIRE_MINUTES', '30'))

id = Column(Integer, primary_key=True, index=True)
username = Column(String(255), unique=True, nullable=False)
email = Column(String(255), unique=True, nullable=False)
password_hash = Column(Text, nullable=False)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Le schéma de réponse UserResponse attend un champ createdAt, mais celui-ci est absent du modèle SQLAlchemy User. Cela provoquera une AttributeError lors de la sérialisation de l'objet. Vous devriez ajouter une colonne createdAt au modèle pour assurer la cohérence entre le modèle de base de données et le schéma Pydantic.

Suggested change
password_hash = Column(Text, nullable=False)
password_hash = Column(Text, nullable=False)
createdAt = Column(DateTime, nullable=False, server_default=func.now())



if __name__ == "__main__":
INPUT_PATH = "data/ds-jobs-.csv"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Il y a une coquille dans le chemin du fichier d'entrée. Le nom data/ds-jobs-.csv contient un tiret en trop à la fin. Cela provoquera une erreur FileNotFoundError à l'exécution du script. Le nom correct, tel que mentionné dans le README.md, est data/ds_jobs.csv (ou un nom similaire sans le tiret final).

Suggested change
INPUT_PATH = "data/ds-jobs-.csv"
INPUT_PATH = "data/ds-jobs.csv"

Comment on lines +30 to +48
def login(user:LoginRequest , db:Session = Depends(get_db)):
user_exists = verify_user_is_exists(user , db)

if user_exists:
token_payload = {
"sub": str(user_exists.id),
"email": user_exists.email
}
access_token = create_token(token_payload)

return TokenResponse(
access_token=access_token,
token_type="bearer"
)

raise HTTPException(
status_code=401,
detail="Email ou mot de passe incorrect"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Vulnérabilité de sécurité critique : La logique de connexion vérifie uniquement si l'utilisateur existe par son email, mais ne vérifie jamais le mot de passe. Cela signifie que n'importe qui peut se connecter à n'importe quel compte en connaissant simplement l'adresse e-mail. Il est impératif de vérifier le mot de passe fourni par rapport au hash stocké en base de données avant de générer un token.

def login(user:LoginRequest , db:Session = Depends(get_db)):
    from backend.app.utils.hashing import verify_password

    user_in_db = verify_user_is_exists(user , db)

    if not user_in_db or not verify_password(user.password, user_in_db.password_hash):
        raise HTTPException(
            status_code=401,
            detail="Email ou mot de passe incorrect"
        )

    token_payload = {
        "sub": str(user_in_db.id),
        "email": user_in_db.email
    }
    access_token = create_token(token_payload)

    return TokenResponse(
        access_token=access_token,
        token_type="bearer"
    )

Comment on lines +10 to +21
try:
result = predict(
job_title = req.job_title,
job_description = req.job_description,
sector = req.sector,
size = req.size,
type_of_ownership = req.type_of_ownership,
state = req.state,
)
return PredictResponse(**result)
except Exception as e:
raise HTTPException(500, detail=str(e))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

La capture d'une exception générique (except Exception as e:) masque la nature des erreurs. Si une erreur est due à des données d'entrée invalides (par exemple, une catégorie inconnue non gérée), un code 500 (Erreur Interne du Serveur) est renvoyé alors qu'un code 422 (Unprocessable Entity) serait plus approprié. Il est préférable de capturer des exceptions plus spécifiques pour fournir des retours d'erreur plus précis et significatifs.

```bash
# Étape 1 — Nettoyage du CSV brut
uv run python backend/app/pipeline/clean.py
# Input : data/ds_jobs.csv
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Il y a une petite coquille dans le chemin du fichier d'entrée mentionné ici. Le script backend/app/pipeline/clean.py utilise data/ds-jobs-.csv (avec un tiret en trop), ce qui causera une erreur. Le nom correct du fichier est data/ds_jobs.csv.

return token


def verify_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme), db=Depends(get_db)):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

La dépendance db=Depends(get_db) est injectée dans la fonction verify_token mais n'est jamais utilisée. Ce paramètre devrait être retiré pour alléger la signature de la fonction et éviter toute confusion.

Suggested change
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme), db=Depends(get_db)):
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme)):


EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

L'utilisation de uvicorn directement est adaptée pour le développement, mais pour un environnement de production, il est fortement recommandé d'utiliser un serveur d'application WSGI/ASGI plus robuste comme Gunicorn, qui gérera les workers Uvicorn. Cela améliore la stabilité, la performance et la capacité à gérer plusieurs requêtes simultanément.

Voici un exemple de CMD pour la production :

CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", "0.0.0.0:8000", "main:app"]

N'oubliez pas d'ajouter gunicorn à vos dépendances dans pyproject.toml.

]

# Dependances pipeline (NER, nettoyage) — PAS dans Docker
[dependency-groups]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

La table [dependency-groups] est une extension spécifique à uv. Pour une meilleure compatibilité avec l'écosystème Python (comme pip), il est recommandé d'utiliser la table standard [project.optional-dependencies] pour définir les groupes de dépendances optionnelles. uv est également compatible avec cette syntaxe standard.

Suggested change
[dependency-groups]
[project.optional-dependencies]

from backend.app.api.db.database import Base, get_db
from backend.app.services.auth_services import create_token

TEST_DATABASE_URL = "sqlite:///./test.db"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Utiliser une base de données SQLite sur disque (./test.db) pour les tests peut laisser des fichiers résiduels et potentiellement causer des interférences entre les exécutions de tests. Il est généralement préférable d'utiliser une base de données en mémoire (sqlite:///:memory:) pour garantir un environnement de test propre à chaque exécution.

Suggested change
TEST_DATABASE_URL = "sqlite:///./test.db"
TEST_DATABASE_URL = "sqlite:///:memory:"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant