diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml new file mode 100644 index 0000000..5ca2c5a --- /dev/null +++ b/.github/workflows/publish-website.yml @@ -0,0 +1,51 @@ +name: Publish website + +# Déploie le site Quarto (docs/) sur GitHub Pages à chaque commit sur website ou main, +# via la méthode artifact officielle (pas de branche gh-pages). +on: + push: + branches: + - website + - main + workflow_dispatch: + +# Permissions requises par la méthode artifact (OIDC + déploiement Pages). +permissions: + contents: read + pages: write + id-token: write + +# Un seul déploiement à la fois ; on ne coupe pas un déploiement en cours. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + + # Pas de setup Python/R : les pages docs/ ne contiennent aucun chunk exécutable. + - name: Render site + run: quarto render docs + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/_site + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/docs/00-generalites.qmd b/docs/00-generalites.qmd new file mode 100644 index 0000000..8e5ffd7 --- /dev/null +++ b/docs/00-generalites.qmd @@ -0,0 +1,85 @@ +--- +title: "Le processus — Généralités" +subtitle: "Vue d'ensemble du pipeline de codification COICOP" +--- + +> 🚧 **Page en construction (squelette).** Compléter les sections ci-dessous. + +## Principe + +Le pipeline `codif-coicop-bdf` rattache chaque libellé de produit à un poste de la +nomenclature COICOP en combinant plusieurs classifieurs complémentaires, puis en les +arbitrant via un LLM (*LLM-as-judge*). Il est orchestré par **Argo Workflows** +(`argo/codif-pipeline.yaml`). + +## Le DAG du pipeline + +Schéma Excalidraw du [pipeline](https://link.excalidraw.com/l/9vLymO4fSxN/3JjfZov3UgX). + +```text + ┌──→ create-vector-db ──────────────┐ (skippable) + preprocessing ──┐ ┌──→ prune ────┤ ├──→ run-rag(-annotations) ─┐ + └──→┤ └──→ create-vector-db-annotations ───┘ │ + └──→ codif-regex ─┬──→ codif-lcs ──────────────────────────────────────────────┼──→ decide-coicop ──→ final-output ──→ report + (→ prune) └──→ run-ttc ───────────────────────────────────────────────┘ +``` + +## Les classifieurs + +Quatre classifieurs tournent en parallèle, puis sont conciliés par `decide-coicop` : + +| Classifieur | Approche | Page | +|---|---|---| +| Regex | Règles | [La codification par regex](02-codif-regex.qmd) | +| LCS | Similarité de chaînes | [LCS](03-codif-lcs.qmd) | +| TTC | Classifieur neuronal | [TTC](05-run-ttc.qmd) | +| RAG COICOP | RAG sur notices | [RAG sur COICOP](04-coicop-rag.qmd) | +| RAG annotations | RAG sur exemples codifiés | [RAG sur annotation](09-rag-annotation.qmd) | + +## Modes prod / éval + + + + +*TODO* — `input_file` non vide = **production** (code un fichier externe) ; vide = +**évaluation** (code le split test des annotations). Décrire le pilotage de bout en bout. + +## Échantillonnage + +*TODO* — sampling centralisé à `codif-regex` (`sample-observations` en prod, +`sample-annotations` en éval) hérité par tous les classifieurs. + + + diff --git a/docs/06-decide-coicop.qmd b/docs/06-decide-coicop.qmd index 4e80093..cabf235 100644 --- a/docs/06-decide-coicop.qmd +++ b/docs/06-decide-coicop.qmd @@ -5,21 +5,32 @@ title: "6. Decide — arbitrage LLM-as-judge" ## Rôle de l'étape `decide-coicop` est l'**arbitre final**. Pour chaque produit non codé par regex, elle réunit -les trois prédictions candidates — [LCS](03-codif-lcs.qmd), [RAG](04-coicop-rag.qmd), -[TTC](05-run-ttc.qmd) — et choisit le code COICOP final, soit automatiquement (consensus), -soit en interrogeant un LLM qui pèse les indices. +les prédictions candidates — [LCS](03-codif-lcs.qmd), [RAG](04-coicop-rag.qmd), +[TTC](05-run-ttc.qmd) et, optionnellement, [RAG-Annotations](09-rag-annotation.qmd) — puis +choisit le code COICOP final, soit automatiquement (consensus), soit en interrogeant un LLM +qui pèse les indices. - Code : [`coicop-bdf-classifier/src/decide_coicop.py`](../coicop-bdf-classifier/src/decide_coicop.py) - Commande : sous-commande `decide-coicop` de `main.py` ## Entrées -| Source | Chemin S3 | -|---|---| -| LCS | `…/{run}/codif-lcs/raw_test_LCS.parquet` | -| RAG | `…/{run}/run-rag/predictions.parquet` | -| TTC | `…/{run}/run-ttc/predictions.parquet` | -| Nomenclature | fichier des codes COICOP valides | +| Source | Chemin S3 | Argument | +|---|---|---| +| LCS | `…/{run}/codif-lcs/raw_test_LCS.parquet` | `--lcs-file` | +| RAG | `…/{run}/run-rag/predictions.parquet` | `--rag-file` | +| TTC | `…/{run}/run-ttc/predictions.parquet` | `--ttc-file` | +| RAG-Annotations *(optionnel)* | `…/{run}/run-rag-annotations/predictions.parquet` | `--rag-annotations-file` | +| Nomenclature | fichier CSV des codes COICOP valides (`Code`, `Libelle`) | `--nomenclature` | + +Les prédictions sont fusionnées sur la colonne `id` (`load_all_observations()`). Le bloc +RAG-Annotations (colonnes `ragann_code`, `ragann_confidence`, `ragann_codable`) n'est joint que +si `--rag-annotations-file` est fourni : le 4ᵉ classifieur est donc **optionnel au niveau du +module/CLI** (`default=None`), et tout le traitement aval s'adapte au nombre de modèles +réellement disponibles. En revanche, **le pipeline Argo le passe systématiquement** (la step +`decide-coicop` dépend de `run-rag-annotations` et fournit toujours `--rag-annotations-file`) : +les 4 classifieurs sont donc la norme en production, l'optionalité servant surtout aux lancements +manuels ou au débogage. ## Traitement @@ -29,38 +40,48 @@ Pour économiser temps et tokens sur les cas faciles, `try_consensus_decision()` **sans appeler le LLM** quand : - la confiance TTC top-1 est suffisante (`ttc_conf_1 ≥ 0,90`), **et** -- tous les codes disponibles (`lcs_code`, `rag_code`) sont **égaux** à `ttc_code_1`. +- tous les autres codes **disponibles** (`lcs_code`, `rag_code`, `ragann_code`) sont **égaux** + à `ttc_code_1`. ```python if float(ttc_conf) < threshold: # threshold = 0.90 return None ... +# codes non nuls parmi lcs_code, rag_code, ragann_code if not all(c == ttc_code for c in other_codes): return None # → décision par consensus, confiance = 5, llm_model = "consensus" ``` -La décision porte alors la mention *« Consensus automatique : les N modèles s'accordent… »*. +Seuls les codes réellement présents (non `NA`) participent au vote : si RAG-Annotations n'a pas +été fourni, le consensus se joue sur les modèles restants. La décision porte alors la mention +*« Consensus automatique : les N modèles s'accordent… »* (où `N` est le nombre de codes +concordants). ### 2. Arbitrage par LLM Sinon, le LLM est sollicité : -- **Filtrage de la nomenclature** (`filter_nomenclature()`) : seules les sections COICOP - pertinentes (préfixes L2 des prédictions) sont envoyées dans le prompt — réduction ×4 à ×10 - du nombre de tokens. +- **Filtrage de la nomenclature** (`filter_nomenclature()`) : au lieu d'envoyer les ~700 codes + COICOP, on ne soumet au LLM que les codes « autour » des prédictions des modèles (voir le + détail [ci-dessous](#comment-est-construite-la-liste-de-codes-soumise-au-llm)) — réduction + typique de ~700 à ~50-150 lignes (gain ×4 à ×10 sur les tokens). L'option + `--full-nomenclature` désactive ce filtrage et envoie la nomenclature complète. - **Construction du prompt** (`build_prompt()`) : un prompt structuré présentant le produit, - les trois prédictions, la nomenclature filtrée et les consignes : + les prédictions des modèles, la nomenclature filtrée et les consignes : ```text ═══ PRODUIT ═══ Libellé brut : Max garden flowers balle surprise Libellé normalisé : max garden flowers balle surprise Enseigne : Action + Type de magasin : … Montant (€) : 3.99 + Code de référence : … ═══ PRÉDICTIONS DES MODÈLES ═══ - [LCS] Code prédit : … (proportion …, distance …) - [RAG] Code prédit : … (confiance …) + [LCS] Code prédit : … (sous-chaîne …, proportion …, distance …) + [RAG] Code prédit : … (confiance …, codable …) + [RAG-Annotations] Code prédit : … (confiance …, codable …) ← seulement si fourni [TTC] Top 1 : … (confiance …) / Top 2 : … / Top 3 : … ═══ NOMENCLATURE COICOP (codes valides) ═══ … @@ -69,6 +90,46 @@ Sinon, le LLM est sollicité : 4. Attribue un score de confiance de 1 (très faible) à 5 (très élevé). ``` + Le bloc `[RAG-Annotations]` n'apparaît dans le prompt que si une prédiction `ragann_code` + non nulle existe pour l'observation. + +#### Comment est construite la liste de codes soumise au LLM ? + +`filter_nomenclature()` part de **tous** les codes prédits pour l'observation (`lcs_code`, +`rag_code`, `ragann_code`, `ttc_code_1`, `ttc_code_2`, `ttc_code_3`, après suppression des +`NA`) et en extrait deux ensembles de préfixes : + +- **L1** = la *section*, soit le segment avant le premier point — `"01.1.2.3"` → `"01"` ; +- **L2** = la *sous-section*, soit les deux premiers segments — `"01.1.2.3"` → `"01.1"`. + +Puis, pour **chaque code de la nomenclature complète**, la décision de le garder dépend de +*son propre* niveau de profondeur : + +| Code de la nomenclature | Exemple | Conservé si… | +|---|---|---| +| 1 segment — en-tête de section | `01` | sa section appartient à **L1** | +| 2 segments — sous-section | `01.1`, `01.2` | sa section appartient à **L1** (filtré sur L1, pas sur L2) | +| 3 segments et plus | `01.1.2`, `01.1.2.3` | il **commence par** l'un des préfixes **L2** | + +L'asymétrie est volontaire : + +- **Aux niveaux 1 et 2**, le filtre est *large* : on garde l'en-tête de section **et toutes ses + sous-sections** (`01.1`, `01.2`, `01.3`…), même celles dont aucun code fin ne sera listé. Cela + donne au LLM une **vue d'ensemble de la section** pour réorienter si les modèles se sont + trompés de sous-section. +- **À partir du niveau 3**, le filtre est *étroit* : on ne garde que la descendance des L2 + réellement prédits, pour ne pas noyer le prompt sous les feuilles non pertinentes. + +**Exemple** — si les modèles prédisent `09.3.1` et `05.1.1`, alors `L1 = {09, 05}` et +`L2 = {09.3, 05.1}`. La liste soumise contient : les en-têtes `05` et `09` ; **toutes** les +sous-sections de `05` et `09` (`05.1`, `05.2`, …, `09.1`, …, `09.3`, …) ; mais, au niveau fin, +**uniquement** les codes sous `05.1.*` et `09.3.*`. Le LLM reste donc libre de choisir un code +précis dans ces deux sous-sections, de basculer vers une autre sous-section des sections 05/09, +ou de remonter à un niveau plus agrégé. + +Cas limites : si **aucune** prédiction n'est disponible (tous les codes `NA`), ou si +`full=True` (`--full-nomenclature`), la nomenclature **complète** est renvoyée. + - **Sortie structurée** : le LLM répond en JSON validé par le modèle Pydantic `DecisionCoicop` : @@ -104,7 +165,7 @@ Le message *user* est produit par `build_prompt()` (valeurs des modèles illustr ```text Tu es un expert en comptabilité nationale et en statistiques de consommation. Ta mission est de déterminer le code COICOP le plus approprié pour un produit acheté, -en t'appuyant sur le contexte d'achat et les prédictions de trois modèles automatiques. +en t'appuyant sur le contexte d'achat et les prédictions de plusieurs modèles automatiques. ═══════════════════════════════════════ PRODUIT @@ -130,6 +191,11 @@ PRÉDICTIONS DES MODÈLES Confiance : 60% Codable : True +[RAG-Annotations — RAG sur exemples déjà codifiés] ← présent seulement si --rag-annotations-file fourni + Code prédit : 09.3.1 + Confiance : 72% + Codable : True + [TTC — Classificateur par apprentissage profond] Top 1 : 09.3.1 (confiance 41%) Top 2 : 05.1.1 (confiance 22%) @@ -149,7 +215,7 @@ INSTRUCTIONS ═══════════════════════════════════════ 1. Choisis UN code COICOP parmi ceux listés dans la nomenclature ci-dessus. 2. Le code doit correspondre au niveau le plus précis qui te semble justifié. -3. Explique en 1 phrase maximum comment tu as pesé les prédictions des trois modèles +3. Explique en 1 phrase maximum comment tu as pesé les prédictions des différents modèles et tout autre indice (enseigne, type de magasin, montant). 4. Attribue un score de confiance de 1 (très faible) à 5 (très élevé). ``` @@ -185,7 +251,7 @@ On peut reproduire ce prompt pour n'importe quelle ligne avec le mode mono-obser | Produit | Consensus ? | Décision | |---|---|---| -| `Bagu. Tradition U Blé Bretagne` | si LCS = RAG = TTC et `ttc_conf_1 ≥ 0,90` → **oui** | code pain repris sans LLM, `confiance = 5`, `llm_model = "consensus"` | +| `Bagu. Tradition U Blé Bretagne` | si tous les codes disponibles = `ttc_code_1` et `ttc_conf_1 ≥ 0,90` → **oui** | code pain repris sans LLM, `confiance = 5`, `llm_model = "consensus"` | | `Max garden flowers balle surprise` | les modèles divergent (jouet vs jardin) → **non** | le LLM arbitre à partir de l'enseigne (*Action*), du prix et des candidats | ## Que peut renvoyer la décision ? @@ -208,6 +274,7 @@ possibles : | Connexion impossible | `APIConnectionError: …` | | Réponse coupée (limite de tokens) | `Response truncated before JSON was complete…` | | JSON illisible | `JSON parsing failed: …` | + | Toute autre erreur (auth, etc.) | `: …` (catch-all) | ::: {.callout-warning} ## Le code n'est pas validé contre la nomenclature diff --git a/docs/09-rag-annotation.qmd b/docs/09-rag-annotation.qmd new file mode 100644 index 0000000..3769942 --- /dev/null +++ b/docs/09-rag-annotation.qmd @@ -0,0 +1,37 @@ +--- +title: "RAG sur annotation" +subtitle: "Codification par RAG sur exemples déjà codifiés (few-shot)" +--- + +> 🚧 **Page en construction (squelette).** Compléter les sections ci-dessous. + +## Principe + +Le module `coicop-rag-annotations/` code chaque produit par **RAG sur exemples annotés** : +on récupère dans une base vectorielle les produits déjà codifiés les plus similaires, puis on +construit un prompt *few-shot* pour demander le code COICOP à un LLM. + +## Étapes + +1. **Construction de la vector DB** (`0_build_annotation_vector_db.py`) — indexe la KB + d'annotations prunée (+ suggester) dans Qdrant. +2. **Codification** (`1_run_rag.py`) — embeddings de l'input, recherche des k plus proches + voisins, prompt few-shot, génération, parsing JSON, export des prédictions. + + + +## KB indexée et sources exclues + +*TODO* — `exclude_sources` (éval) vs `exclude_sources_prod` (prod), inclusion du suggester, +sources exclues (ex. `copain`). + +## Collection Qdrant de test + +*TODO* — quand `sample-annotations` est non vide, une collection `_test` (suffixe sur +`collection_name`) est utilisée pour ne pas écraser la vector DB de production. + +## Sortie et intégration + +*TODO* — colonnes `ragann_*` consommées par [l'étape de réconciliation finale](06-decide-coicop.qmd) +(`decide-coicop`). diff --git a/docs/_quarto.yml b/docs/_quarto.yml index d1287ef..0bdb301 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -4,27 +4,33 @@ project: website: title: "Codification COICOP — BDF" - description: "Documentation pas à pas du pipeline de codification automatique des produits BDF selon la nomenclature COICOP." + description: "Documentation du pipeline de codification automatique des produits BDF selon la nomenclature COICOP." navbar: left: - href: index.qmd - text: Accueil - - text: Étapes + text: Introduction + - href: donnees.qmd + text: Les données + - text: Le processus menu: + - href: 00-generalites.qmd + text: Généralités - href: 01-preprocessing.qmd - text: 1. Preprocessing + text: Le preprocessing - href: 02-codif-regex.qmd - text: 2. Codif regex + text: La codification par regex - href: 03-codif-lcs.qmd - text: 3. Codif LCS - - href: 04-coicop-rag.qmd - text: 4. RAG (prune, vector-db, run-rag) + text: LCS - href: 05-run-ttc.qmd - text: 5. TTC + text: TTC + - href: 04-coicop-rag.qmd + text: RAG sur COICOP + - href: 09-rag-annotation.qmd + text: RAG sur annotation - href: 06-decide-coicop.qmd - text: 6. Decide (LLM-as-judge) + text: Étape de réconciliation finale - href: 07-final-output.qmd - text: 7. Final output + text: Final output - href: 08-report.qmd text: 8. Report - text: Guides @@ -57,11 +63,17 @@ website: format: html: - theme: cosmo + theme: + light: [flatly, brand.scss] + dark: [darkly, brand.scss] toc: true toc-depth: 3 toc-title: "Sur cette page" code-copy: true code-overflow: wrap number-sections: false + anchor-sections: true + smooth-scroll: true + link-external-icon: true + link-external-newwindow: true lang: fr diff --git a/docs/brand.scss b/docs/brand.scss new file mode 100644 index 0000000..5944b16 --- /dev/null +++ b/docs/brand.scss @@ -0,0 +1,7 @@ +/*-- scss:defaults --*/ +$primary: #2c6e9b; +$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; +$h1-font-size: 2.1rem; +$h2-font-size: 1.5rem; +$toc-font-size: 0.85rem; +$border-radius: 0.5rem; diff --git a/docs/donnees.qmd b/docs/donnees.qmd new file mode 100644 index 0000000..e9746ed --- /dev/null +++ b/docs/donnees.qmd @@ -0,0 +1,36 @@ +--- +title: "Les données" +subtitle: "Sources mobilisées par le pipeline de codification COICOP" +--- + +> 🚧 **Page en construction. + + +## Vue d'ensemble + +Le pipeline mobilise plusieurs fichiers **en entrée** (sources externes, non produites par +le pipeline lui-même). Tous résident dans le bucket S3 `projet-budget-famille`. + +A noter que ces fichiers ne sont pas utilisées de la même manière selon qu'on utilise le pipeline en mode production (il faut coder un fichier) ou en mode évaluation (on utilise des observations déjà labellisées pour évaluer le processus). + +| Fichier | Définition | Format | Path S3 | Lu par | Commentaire +|---|--------|---|---|---|--------| +| `annotations_test_2024.csv` | Annotations manuelles BdF 2024 (vérité terrain / KB ; sources `receipts_from_app`, `manual_from_app`, `manual_from_book`) | CSV `;` | `s3://projet-budget-famille/data/codification-manuelle-anterieure/annotations_test_2024.csv` | `preprocessing` | Base produite à partir de trois fichiers fournis par l'équipe BDF. Voir ce repo : https://git.lab.sspcloud.fr/ssplab/experimentation-bdf/construction-dataset| +| `annotations_BDF_2017.csv` | Annotations historiques de l'enquête BdF 2017 (source `bdf_2017`, KB uniquement) | CSV `;` | `s3://projet-budget-famille/data/codification-manuelle-anterieure/annotations_BDF_2017.csv` | `preprocessing` | Utilise l'ancien millésime de la Coicop (difficilement exploitable) | +| `liste_produits_fr_copain.csv` | Liste de produits codifiés issue du *suggester* de l'application de l'enquête — exemples additionnels de la KB des RAG | CSV | `s3://projet-budget-famille/data/input-annotation/liste_produits_fr_copain.csv` | `preprocessing`, `prune` | | +| `liste_magasins.csv` | Table de correspondance enseigne → type de magasin | CSV | `s3://projet-budget-famille/data/input-annotation/liste_magasins.csv` | `preprocessing` | | +| `produit_non_annotable.csv` | Liste des libellés non codables (retirés en amont) | CSV | `s3://projet-budget-famille/data/codification-manuelle-anterieure/ produit_non_annotable.csv` | `preprocessing` | | +| `coicop-2018_envoi_rmes_20251022.csv` | Nomenclature COICOP 2018 brute (référentiel des codes + libellés) | CSV | `s3://projet-budget-famille/data/coicop-2018_envoi_rmes_20251022.csv` | `prune`, `coicop-rag` | | +| *fichier d'observations* | Entrée de **production** : libellés à coder, sans vérité terrain (paramètre Argo `input_file`) | CSV / parquet | `s3://projet-budget-famille/data/workflow_inputs/…` (ex. `BDF_data_tickets_appli_20260320_a_codif.csv`) | `preprocessing` (mode prod) | | + +::: {.callout-note} +## Deux entrées particulières +- **Modèle TTC** : le classifieur neuronal n'est pas un fichier S3 mais un artefact MLflow, + référencé par le paramètre Argo `ttc-model-uri` + (ex. `mlflow-artifacts:/10/…/artifacts/model`), lu par `run-ttc`. +- **Les données de caisse (ddc)** : ce sont des données récoltées dans le cadre de la production de l'IPC. Il s'agit de dépenses issues de tickets de caisse avec le code Coicop correspondant (labellisation faite via un référentiel fourni par un prestataire). Ces données sont utilisées dans le cadre de l'entraînement du modèle TTC (en dehors de ce pipeline). +- **Source `copain`** (`s3://projet-budget-famille/data/output-annotation/`) : historiquement + une entrée du `preprocessing`, elle est **exclue du pipeline** — son chargement est désactivé. +- Les listes de règles pour la codification déterministe par Regex est contenue dans le code, et non dans un fichier sur S3 (https://github.com/InseeFrLab/codif-coicop-bdf/blob/main/regex-codif/config/rules.yaml). +::: + diff --git a/docs/index.qmd b/docs/index.qmd index f9bf4fd..eeffa3a 100644 --- a/docs/index.qmd +++ b/docs/index.qmd @@ -1,18 +1,16 @@ --- title: "Codification COICOP des produits BDF" -subtitle: "Documentation pas à pas du pipeline de codification automatique" +subtitle: "Documentation de la démarche et du pipeline de codification automatique" --- ## À quoi sert ce pipeline ? -L'enquête **Budget de Famille (BDF)** collecte les tickets de caisse des ménages. Chaque -ligne de ticket décrit un produit acheté par un libellé court et bruité -(`"Bagu. Tradition U Blé Bretagne"`, `"Nescafé DLC Gust ESP 30 cap 165g"`, `"Illisible"`…). +L'enquête **Budget de Famille (BDF)** vise à comprendre la structure et l'évolution de la consommation des ménages et collecte pour cela les dépenses réalisées par les ménages enquêtés. Ces dépenses remontent sous forme de libellés textuels relativement courts, souvent bruités et sémantiquement différents selon leur source (descripitions manuelles, lignes de tickets de caisse, etc.). Pour exploiter ces données, chaque libellé doit être rattaché à un poste de la nomenclature **COICOP** (*Classification of Individual Consumption According to Purpose*). Le faire à la main est coûteux : le pipeline `codif-coicop-bdf` **automatise cette codification** en -combinant plusieurs approches (règles, similarité de chaînes, classifieur neuronal, RAG) puis +combinant plusieurs approches (règles, similarité de chaînes, machine learning supervisé, RAG) puis en les arbitrant via un LLM. @@ -39,6 +37,17 @@ produit consommable : | `98.5` | Remises / réductions | | `99.x` | Divers non codables | + +## Davantage de contexte et échéances + +La codification porte sur le millésime BDF 2026 (dont les questionnaires remontent progressivement au cours de l'année 2026). + +Les résultats consolidés doivent être transmis à Eurostat en 2028. + +Les travaux de mise mise en place d'un pipeline de codification automatique ont débuté à l'autonne 2025, impliquant la MoA de l'enquête, la division IPC et le SSPlab. + +À noter que la prochaine enquête BDF aura lieu en 2030 et il convient ainsi de rendre le processus de codification pérenne et reproductible pour pouvoir l'utiliser lors de ce prochain millésime. + ## Le pipeline étape par étape Le pipeline est un **DAG Argo** (`argo/codif-pipeline.yaml`). Chaque étape lit/écrit sur S3 @@ -92,49 +101,23 @@ Argo clonent la branche `codif-pipeline` du dépôt ; son contenu est fusionné | 1 | `preprocessing` | Construit toujours les annotations (complet + train/test) ; en prédiction, prépare aussi les observations à coder | [→](01-preprocessing.qmd) | | 2 | `codif-regex` | Code les libellés évidents par règles regex | [→](02-codif-regex.qmd) | | 3 | `codif-lcs` | Code par similarité de chaîne (LCS) sur un pool de référence | [→](03-codif-lcs.qmd) | -| 4 | `prune` / `create-vector-db` / `run-rag` | Codification sémantique par RAG (pruning unifié en amont) | [→](04-coicop-rag.qmd) | -| 5 | `run-ttc` | Classifieur neuronal basique (caisses + fine-tuning BDF 2024) | [→](05-run-ttc.qmd) | -| 6 | `decide-coicop` | Arbitrage final LLM-as-judge entre LCS / RAG / TTC | [→](06-decide-coicop.qmd) | -| 7 | `final-output` | Assemble le résultat utilisateur (regex + décision LLM) | [→](07-final-output.qmd) | -| 8 | `report` | Rapport Quarto (qualité ou suivi de prédiction) | [→](08-report.qmd) | +| 4 | `prune` / `create-vector-db` / `run-rag` | Codification sémantique par RAG sur les notices COICOP (pruning unifié en amont) | [→](04-coicop-rag.qmd) | +| 5 | `create-vector-db-annotations` / `run-rag-annotations` | Codification par RAG sur exemples déjà codifiés (few-shot) | [→](09-rag-annotation.qmd) | +| 6 | `run-ttc` | Classifieur neuronal basique (caisses + fine-tuning BDF 2024) | [→](05-run-ttc.qmd) | +| 7 | `decide-coicop` | Arbitrage final LLM-as-judge entre LCS / RAG notices / RAG annotations / TTC | [→](06-decide-coicop.qmd) | +| 8 | `final-output` | Assemble le résultat utilisateur (regex + décision LLM) | [→](07-final-output.qmd) | +| 9 | `report` | Rapport Quarto (qualité ou suivi de prédiction) | [→](08-report.qmd) | -## Le fichier d'entrée et son mappage -L'exemple utilisé dans toute cette documentation est -`BDF_data_tickets_appli_20260320_a_codif.csv` (séparateur `;`, valeurs entre guillemets) : -| `ID_TICK` | `NAT_DEP` (produit) | `MONT_DEP` | `MAG_DEP` (enseigne) | `COM_DEP` | -|---|---|---|---|---| -| `10203_91_01` | Gasoil | 30.25 | Station Netto | Saint-Vite | -| `10203_91_06` | Ticket CB | 40.24 | Station Netto | Saint-Vite | -| `11622_91_08` | Bagu. Tradition U Blé Bretagne | 1.00 | U | Liffré | -| `10521_91_03` | Moyen frite Sce Pomme Frite | 4.10 | Mc Donald's | Civrieux-d'Azergues | -| `11165_91_01` | Illisible | 0.00 | — | — | +## Lancer le pipeline -Le pipeline n'impose pas de noms de colonnes : l'étape `preprocessing` reçoit un -**mappage configurable** (paramètres Argo). Valeurs par défaut pour ce fichier : +Un script d'aide est présent dans le repo : **codif-coicop-bdf/argo/argo_helper.md**. -| Paramètre Argo | Valeur | Colonne pipeline produite | -|---|---|---| -| `input_file` | `s3://…/workflow_inputs/BDF_data_tickets_appli_20260320_a_codif.csv` | — | -| `text_column` | `NAT_DEP` | `raw_product` (libellé à coder) | -| `shop_column` | `MAG_DEP` | `shop` (enseigne) | -| `budget_column` | `MONT_DEP` | `budget` (montant €) | -| `annee_column` | *(vide)* | `annee` | -| `source_column` | *(vide)* | `source` | - -::: {.callout-important} -## Mode prédiction -Ce fichier contient des produits **à coder**, sans vérité terrain. Le pipeline tourne donc en -**mode prédiction** : il n'y a pas de colonne `code` de référence. Les observations préparées -sont écrites dans `observations.parquet` (l'étape `preprocessing` produit par ailleurs toujours -les annotations train/test). Cela change la dernière -étape (`report`), qui bascule sur `prediction_report.qmd` (suivi des prédictions) au lieu du -rapport d'évaluation d'exactitude. Le livrable final est le fichier produit par -[`final-output`](07-final-output.qmd). -::: +Il donne les commandes d'installation et de lancement. Par ailleurs, le script de paramétrages du workflow se trouve ici **codif-coicop-bdf/argo/params.yaml** (il permet notamment de choisir sur quel fichier s'applique la codification, choisir entre une approche de production courante ou d'évaluation, coder sur un échantillon de produits, etc.). -## Fil rouge + + -## Lancer le pipeline ```bash # Pipeline complet (défaut : skip-vector-db=true, skip-report=false) diff --git a/docs/ressources.qmd b/docs/ressources.qmd new file mode 100644 index 0000000..cf06e22 --- /dev/null +++ b/docs/ressources.qmd @@ -0,0 +1,20 @@ +--- +title: "Les ressources" +subtitle: "Liens utiles, outils et contacts du projet" +--- + + +## Code et documentation + +- **Dépôt GitHub** : + +- **Présentation du projet à ISI 2026** : + +## Nomenclature COICOP (références externes) + +https://www.insee.fr/fr/metadonnees/coicop2018/division/01?champRecherche=true + +## Application Copain (solution OJS pour faire de l'annotation) + +- App : https://ssplab.pages.lab.sspcloud.fr/experimentation-bdf/copain/ +- Code : https://git.lab.sspcloud.fr/ssplab/experimentation-bdf/copain/pages#overview