batchCooking/services/tech-step-intent-service/intent_service/routes/train.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

58 lines
2.1 KiB
Python

"""`POST /v1/train` — appelé par `apps/api` (`IntentServiceClient.train`,
`TechStepClassifierService._train`) une fois par locale à chaque warm-up
serveur, avec l'intégralité de `TECH_STEP_TRAINING_DATA` filtrée pour cette
locale. Voir `LocalePipeline.train` pour ce que "reconstruit à neuf" signifie
concrètement.
"""
import logging
from fastapi import APIRouter, Depends, HTTPException, status
from ..locale_pipeline import TrainEntry, UnsupportedLocaleError
from ..pipeline_registry import registry
from ..schemas import TrainRequest, TrainResponse
from ..security import require_valid_secret
logger = logging.getLogger(__name__)
router = APIRouter(dependencies=[Depends(require_valid_secret)])
@router.post("/v1/train", response_model=TrainResponse)
def train(request: TrainRequest) -> TrainResponse:
entries = [
TrainEntry(uid=entry.uid, synonyms=entry.synonyms, utterances=entry.utterances)
for entry in request.entries
]
logger.info(
"tech-step NLP train starting",
extra={"locale": request.locale, "uids": [entry.uid for entry in entries]},
)
try:
label_count, utterance_count, synonym_count = registry.train(request.locale, entries)
except UnsupportedLocaleError as err:
logger.warning("tech-step NLP train rejected", extra={"locale": request.locale, "error": str(err)})
# 422, pas 500 : une locale non supportée dans une requête de
# `apps/api` est une erreur de configuration/version-skew entre les
# deux services (voir le contrat documenté dans le plan de
# migration), pas un échec inattendu du service lui-même.
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(err)) from err
logger.info(
"tech-step NLP train done",
extra={
"locale": request.locale,
"labelCount": label_count,
"utteranceCount": utterance_count,
"synonymCount": synonym_count,
},
)
return TrainResponse(
locale=request.locale,
label_count=label_count,
utterance_count=utterance_count,
synonym_count=synonym_count,
)