github-actions[bot]
Deploy snapshot 73053884eaccbd2ab4535c17ecba37a677a3fc0d
be9501c
Raw
History Blame Contribute Delete
3.16 kB
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from dotenv import load_dotenv
ROOT_DIR = Path(__file__).resolve().parents[1]
ARTIFACTS_DIR = ROOT_DIR / "artifacts"
AVG_SALARY_BY_LEVEL_PATH = ARTIFACTS_DIR / "salaire_moyen_par_niveau_hierarchique.json"
def load_avg_salary_by_level(path: Path = AVG_SALARY_BY_LEVEL_PATH) -> dict[str, float]:
payload = json.loads(path.read_text(encoding="utf-8"))
return {str(level).strip(): float(value) for level, value in payload.items()}
AVG_SALARY_BY_LEVEL = load_avg_salary_by_level()
def normalize_level_key(value: Any) -> str:
if isinstance(value, bool):
raise ValueError("niveau_hierarchique_poste doit être un nombre valide")
if isinstance(value, int):
return str(value)
if isinstance(value, float):
return str(int(value)) if value.is_integer() else str(value)
return str(value).strip()
def preprocess_record_for_model(
record: dict[str, Any],
avg_salary_by_level: dict[str, float] | None = None,
) -> dict[str, Any]:
processed = dict(record)
salary_map = avg_salary_by_level if avg_salary_by_level is not None else AVG_SALARY_BY_LEVEL
level_value = float(processed["niveau_hierarchique_poste"])
if level_value < 1 or level_value > 5:
raise ValueError("niveau_hierarchique_poste doit être compris entre 1 et 5")
level_key = normalize_level_key(processed["niveau_hierarchique_poste"])
if level_key not in salary_map:
raise ValueError(f"niveau_hierarchique_poste inconnu: {processed['niveau_hierarchique_poste']!r}")
avg_salary = float(salary_map[level_key])
if avg_salary == 0.0:
raise ValueError("Salaire moyen par niveau invalide (division par zéro)")
monthly_salary = float(processed["revenu_mensuel"])
total_experience = float(processed["annee_experience_totale"])
ratio_denominator = total_experience + 1.0
if ratio_denominator <= 0.0:
raise ValueError("annee_experience_totale doit être > -1")
processed["diff_salaire_vs_niveau_pct"] = (monthly_salary - avg_salary) / avg_salary
processed["ratio_salaire_anciennete"] = monthly_salary / ratio_denominator
processed.pop("niveau_hierarchique_poste", None)
processed.pop("annee_experience_totale", None)
return processed
def load_env(root_dir: Path | None = None) -> None:
"""
Cherche et charge le premier fichier .env trouvé dans l'arborescence du projet.
Priorité :
1. .env à la racine du projet
2. confs/**/.env
3. confs/**/.env.*
"""
if root_dir is None:
root_dir = Path(__file__).resolve().parent.parent # remonte à la racine depuis src/
root_env = root_dir / ".env"
if root_env.exists():
load_dotenv(dotenv_path=root_env, override=False)
return
confs_dir = root_dir / "confs"
if confs_dir.exists():
env_candidates = sorted(confs_dir.rglob(".env"))
if env_candidates:
load_dotenv(dotenv_path=env_candidates[0], override=False)
return
env_pattern_candidates = sorted(confs_dir.rglob(".env.*"))
if env_pattern_candidates:
load_dotenv(dotenv_path=env_pattern_candidates[0], override=False)
return