"""`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, )