batchCooking/services/tech-step-intent-service/intent_service/config.py
Nicolas 74a0052431 feat(recipes): journalise chaque input/output du pipeline NLP
Ajoute un logging JSON structure (meme convention que LoggerService cote
apps/api) a services/tech-step-intent-service : chaque appel
POST /v1/process journalise locale/texte en entree et
entites/intent/score en sortie, chaque POST /v1/train journalise les uid
entraines et les compteurs resultants. Chatter interne de spaCy mis a
WARNING pour ne pas noyer ces lignes.

Bug trouve et corrige en verifiant les octets bruts d'un log reel (pas
juste son affichage terminal) : l'encodage par defaut de sys.stdout sur
Windows produisait de vrais octets UTF-8 invalides pour tout texte
accentue journalise (le francais des etapes de recette) — corrige par
sys.stdout.reconfigure(encoding="utf-8") au demarrage.

LOG_LEVEL configurable (INFO par defaut), documente dans le README du
service et .env.example.

Verifie : 30/30 pytest (3 nouveaux tests sur le formateur JSON), smoke
test HTTP reel confirmant au niveau des octets que les caracteres
accentues sont preserves, lint complet du monorepo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 21:34:40 +02:00

51 lines
2.6 KiB
Python

"""Configuration du service, lue depuis l'environnement (`pydantic-settings`).
Contrairement à `requireInternalWorker` côté `apps/api`
(`apps/api/src/middlewares/require-internal-worker.ts`), qui tolère un
`INTERNAL_WORKER_SECRET` absent (le worker LLM est un job de fond
optionnel) et échoue "juste" requête par requête dans ce cas, ce service est
une dépendance coeur : `INTENT_SERVICE_SECRET` absent doit empêcher
`uvicorn` de démarrer du tout plutôt que de démarrer dans un état où chaque
requête échouerait silencieusement en boucle — `Settings` n'a donc aucune
valeur par défaut ni type optionnel pour ce champ, la validation Pydantic
lève dès l'import de ce module si la variable manque.
"""
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
# `env_file=".env"` : lu uniquement en dev natif (`cp .env.example .env`,
# voir le README de ce service) — sans effet en Docker, où
# docker-compose.yml passe les variables directement en `environment:`
# et où aucun `.env` n'est copié dans l'image. Un `.env` absent n'est pas
# une erreur ici (pydantic-settings ignore silencieusement un fichier
# manquant) ; c'est bien `intent_service_secret` ci-dessous, sans valeur
# par défaut, qui fait échouer le démarrage si la variable n'est
# disponible par aucune des deux voies.
#
# `case_sensitive` par défaut (False) : `INTENT_SERVICE_SECRET` (la
# convention majuscule utilisée partout ailleurs dans le repo, cf.
# `docker-compose.yml`/`.env.example`) matche bien le champ
# `intent_service_secret` ci-dessous.
model_config = SettingsConfigDict(env_file=".env")
# Secret partagé attendu sur le header `X-Intent-Service-Secret` de
# chaque requête (sauf `GET /health`) — voir `security.py`. Doit matcher
# `INTENT_SERVICE_SECRET` côté `apps/api/src/config/env.ts`.
intent_service_secret: str
# Pas de `port` ici : `uvicorn` prend son port en argument de ligne de
# commande (`--port`, voir le Dockerfile et le README de ce service),
# jamais lu depuis `Settings` — une variable d'env dupliquant ce que la
# commande de démarrage fixe déjà explicitement n'aurait aucun lecteur.
# Niveau du logging structuré (`logging_config.py`) — voir ce module pour
# le format. `INFO` par défaut : c'est à ce niveau que `routes/process.py`
# et `routes/train.py` journalisent chaque input/output du pipeline NLP,
# pour qu'un déploiement par défaut les voie sans configuration
# supplémentaire (`docker logs`/Portainer).
log_level: str = "INFO"
settings = Settings()