Spaces:
Sleeping
Sleeping
| 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 |