confluent/docs/TRAVAIL_RACINES_FRANCAISES.md
StillHammer bbd8d5f9c9 Amélioration majeure du système de traduction Confluent
- Prompt système strict avec Chain-of-Thought obligatoire
- Retrait des racines en dur du prompt (context skimming pur)
- Amélioration logique fallback (activation si <50% couverture)
- Ajout lexique : loup, frère, manger + fichier famille
- Debug endpoint /api/debug/prompt pour inspection
- Documentation complète système racines françaises

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 12:18:55 +08:00

11 KiB
Raw Blame History

Travail : Système de Racines Françaises

Objectif

Améliorer le matching des mots français conjugués/accordés en utilisant un système de racines françaises au lieu de se fier uniquement à la lemmatisation automatique.

Problème actuel

  • "manger" trouve "mukis"
  • "mangé" ne trouve RIEN
  • "vu" ne trouve pas "voir"
  • "pris" ne trouve pas "prendre"

Le lemmatizer actuel est trop basique et rate beaucoup de formes conjuguées.

Solution : Double approche

1. Système de racines automatique (pour verbes réguliers)

Principe : Extraire les 4 premières lettres d'un mot comme "racine"

Exemples qui marchent :

  • "manger", "mangé", "mange", "mangeait" → racine "mang" → trouve "mukis"
  • "donner", "donné", "donne", "donnait" → racine "donn" → trouve "kitan"
  • "aller", "allé", "allait" → racine "alle" → trouve "tekis"

Code à ajouter :

/**
 * Extrait la racine française d'un mot (4 premières lettres)
 * Minimum 4 lettres pour éviter les faux positifs
 * @param {string} word - Mot français
 * @returns {string|null} - Racine ou null si mot trop court
 */
function extractFrenchRoot(word) {
  if (word.length < 4) return null;
  return word.slice(0, 4).toLowerCase();
}

2. Exceptions manuelles (verbes irréguliers + racines courtes)

Principe : Ajouter toutes les formes conjuguées dans le champ synonymes_fr du lexique

Exemples qui NE marchent PAS avec racines automatiques :

Racines trop courtes

  • "voir" → racine "voir" (4 lettres OK) MAIS "vu", "vus" → racine "vu" (2 lettres )
  • "être" → racine impossible (formes trop différentes)
  • "avoir" → racine impossible (formes trop différentes)

Verbes irréguliers

  • "prendre" → racine "pren" mais "pris", "prit" ont racine "pris"
  • "faire" → racine "fair" mais "fait", "faite" ont racine "fait"

Solution : Ajouter manuellement dans synonymes_fr


TRAVAIL 1 : Modification du code (contextAnalyzer.js)

Fichier : ConfluentTranslator/contextAnalyzer.js

Modifications à faire :

A. Ajouter la fonction extractFrenchRoot()

/**
 * Extrait la racine française d'un mot (4 premières lettres minimum)
 * Pour matcher des conjugaisons : manger/mangé/mange → "mang"
 * @param {string} word - Mot français (déjà en lowercase)
 * @returns {string|null} - Racine de 4 lettres ou null si trop court
 */
function extractFrenchRoot(word) {
  if (word.length < 4) return null;
  return word.slice(0, 4);
}

B. Modifier searchWord() pour utiliser les racines

Emplacement : ligne ~124

Ajouter après la ligne 126 :

const results = [];
const lemmas = simpleLemmatize(word);
const root = extractFrenchRoot(word); // NOUVEAU

Ajouter après la ligne 146 (après matching sur synonymes lemmatisés) :

    // NOUVEAU: Correspondance sur racine française (4 lettres)
    else if (root && key.toLowerCase().startsWith(root)) {
      score = 0.75;
    }
    // NOUVEAU: Correspondance sur racine dans synonymes
    else if (root && entry.synonymes_fr?.some(syn => syn.toLowerCase().startsWith(root))) {
      score = 0.70;
    }

Code final de searchWord() :

function searchWord(word, dictionnaire) {
  const results = [];
  const lemmas = simpleLemmatize(word);
  const root = extractFrenchRoot(word); // NOUVEAU

  for (const [key, entry] of Object.entries(dictionnaire)) {
    let score = 0;

    // Correspondance exacte sur le mot français
    if (key === word || entry.mot_francais?.toLowerCase() === word) {
      score = 1.0;
    }
    // Correspondance sur formes lemmatisées
    else if (lemmas.some(lemma => key === lemma || entry.mot_francais?.toLowerCase() === lemma)) {
      score = 0.95;
    }
    // Correspondance sur synonymes
    else if (entry.synonymes_fr?.some(syn => syn.toLowerCase() === word)) {
      score = 0.9;
    }
    // Correspondance sur synonymes lemmatisés
    else if (entry.synonymes_fr?.some(syn => lemmas.includes(syn.toLowerCase()))) {
      score = 0.85;
    }
    // NOUVEAU: Correspondance sur racine française (4 lettres)
    else if (root && key.toLowerCase().startsWith(root)) {
      score = 0.75;
    }
    // NOUVEAU: Correspondance sur racine dans synonymes
    else if (root && entry.synonymes_fr?.some(syn => syn.toLowerCase().startsWith(root))) {
      score = 0.70;
    }

    if (score > 0) {
      results.push({
        mot_francais: entry.mot_francais || key,
        traductions: entry.traductions || [],
        score,
        source: entry.source_files || []
      });
    }
  }

  return results;
}

C. Exporter la nouvelle fonction

Emplacement : ligne ~387 (module.exports)

module.exports = {
  tokenizeFrench,
  calculateMaxEntries,
  simpleLemmatize,
  extractFrenchRoot, // NOUVEAU
  searchWord,
  findRelevantEntries,
  expandContext,
  extractRoots,
  analyzeContext
};

TRAVAIL 2 : Compléter les exceptions dans le lexique

Objectif : Ajouter manuellement les formes conjuguées des verbes irréguliers dans synonymes_fr

Fichiers à modifier :

ancien-confluent/lexique/06-actions.json

Verbes à compléter (par priorité)

Priorité 1 : Verbes très courants

1. voir (déjà présent)

"voir": {
  "traductions": [...],
  "synonymes_fr": ["observer", "regarder", "voit", "vois", "vu", "vus", "vue", "vues", "voyait", "voyais", "voyant", "verra", "verras", "verront"]
}

2. prendre

"prendre": {
  "traductions": [...],
  "synonymes_fr": ["pris", "prit", "prise", "prises", "prend", "prends", "prenait", "prenais", "prenant", "prendra", "prendras", "prendront"]
}

3. faire

"faire": {
  "traductions": [...],
  "synonymes_fr": ["créer", "fait", "faits", "faite", "faites", "fais", "faisait", "faisais", "faisant", "fera", "feras", "feront"]
}

4. manger (nouveau verbe, déjà ajouté)

"manger": {
  "traductions": [...],
  "synonymes_fr": ["mange", "manges", "mangé", "mangée", "mangés", "mangées", "mangeait", "mangeais", "mangeant", "mangera", "mangeras", "mangeront"]
}

5. aller

"aller": {
  "traductions": [...],
  "synonymes_fr": ["va", "vas", "vais", "allé", "allée", "allés", "allées", "allait", "allais", "allant", "ira", "iras", "iront"]
}

6. donner

"donner": {
  "traductions": [...],
  "synonymes_fr": ["donne", "donnes", "donné", "donnée", "donnés", "données", "donnait", "donnais", "donnant", "donnera", "donneras", "donneront"]
}

7. dire

"dire": {
  "traductions": [...],
  "synonymes_fr": ["parler", "dit", "dits", "dite", "dites", "dis", "disait", "disais", "disant", "dira", "diras", "diront"]
}

Priorité 2 : Verbes auxiliaires (très irréguliers)

8. être

"être": {
  "traductions": [...],
  "synonymes_fr": ["est", "es", "suis", "sont", "été", "était", "étais", "étant", "sera", "seras", "seront", "fut", "fus"]
}

9. avoir

"avoir": {
  "traductions": [...],
  "synonymes_fr": ["a", "as", "ai", "ont", "eu", "eue", "eus", "eues", "avait", "avais", "ayant", "aura", "auras", "auront"]
}

Priorité 3 : Autres verbes courants

10. savoir

"savoir": {
  "traductions": [...],
  "synonymes_fr": ["connaître", "sait", "sais", "su", "sue", "sus", "sues", "savait", "savais", "sachant", "saura", "sauras", "sauront"]
}

11. chasser

"chasser": {
  "traductions": [...],
  "synonymes_fr": ["traquer", "chasse", "chasses", "chassé", "chassée", "chassés", "chassées", "chassait", "chassais", "chassant", "chassera", "chasseras", "chasseront"]
}

12. transmettre

"transmettre": {
  "traductions": [...],
  "synonymes_fr": ["enseigner", "transmet", "transmets", "transmis", "transmise", "transmises", "transmettait", "transmettais", "transmettant", "transmettra", "transmettras", "transmettront"]
}

13. garder

"garder": {
  "traductions": [...],
  "synonymes_fr": ["protéger", "garde", "gardes", "gardé", "gardée", "gardés", "gardées", "gardait", "gardais", "gardant", "gardera", "garderas", "garderont"]
}

14. porter

"porter": {
  "traductions": [...],
  "synonymes_fr": ["transporter", "porte", "portes", "porté", "portée", "portés", "portées", "portait", "portais", "portant", "portera", "porteras", "porteront"]
}

15. apprendre

"apprendre": {
  "traductions": [...],
  "synonymes_fr": ["apprend", "apprends", "appris", "apprise", "apprises", "apprenait", "apprenais", "apprenant", "apprendra", "apprendras", "apprendront"]
}

Tests à faire après modifications

Test 1 : Vérifier les racines automatiques

curl -X POST http://localhost:3000/api/debug/prompt \
  -H "Content-Type: application/json" \
  -d '{"text": "Il mangeait le pain", "target": "ancien"}' | grep -A 5 "wordsFound"

Résultat attendu : "mangeait" → trouve "mukis" via racine "mang"

Test 2 : Vérifier les exceptions manuelles

curl -X POST http://localhost:3000/api/debug/prompt \
  -H "Content-Type: application/json" \
  -d '{"text": "Il a vu et pris", "target": "ancien"}' | grep -A 10 "wordsFound"

Résultat attendu :

  • "vu" → trouve "mirak" via synonymes_fr
  • "pris" → trouve "pasak" via synonymes_fr

Test 3 : Phrase complète

# Même test que le problématique
curl -X POST http://localhost:3000/api/debug/prompt \
  -H "Content-Type: application/json" \
  -d '{"text": "C est le collier du loup qui a mange mon frere", "target": "ancien"}' | python -c "import sys, json; data=json.load(sys.stdin); print('Found:', [w['input'] for w in data['metadata']['wordsFound']])"

Résultat attendu : ["collier", "loup", "mange", "frere"] tous trouvés


Estimation de travail

  • Code (contextAnalyzer.js) : ~30 lignes, 15 minutes
  • Lexique (06-actions.json) : 15 verbes × ~12 formes = ~180 formes à ajouter, 45-60 minutes

Total : ~1h15 de travail


Notes importantes

  1. Lowercase : Tout est déjà en lowercase dans tokenizeFrench(), pas besoin de le refaire
  2. Normalisation des accents : Déjà fait (mangé → mange dans la tokenization)
  3. Ordre de priorité matching :
    • 1.0 = Exacte
    • 0.95 = Lemma
    • 0.9 = Synonyme exact
    • 0.85 = Synonyme lemmatisé
    • 0.75 = Racine sur clé (NOUVEAU)
    • 0.70 = Racine sur synonyme (NOUVEAU)
  4. Longueur minimum racine : 4 lettres pour éviter faux positifs ("il", "du", "un", etc.)

Commandes pour lancer un agent

Si tu veux déléguer le travail lexique à un agent :

Lance un agent general-purpose avec cette tâche :

Complète le fichier ancien-confluent/lexique/06-actions.json en ajoutant les formes conjuguées dans synonymes_fr pour tous les verbes selon le document docs/TRAVAIL_RACINES_FRANCAISES.md section "TRAVAIL 2".

Pour chaque verbe, ajoute dans synonymes_fr :
- Présent : 3ème personne singulier/pluriel
- Passé composé : participe passé (masculin/féminin/pluriel)
- Imparfait : 3ème personne
- Participe présent
- Futur : 3ème personne

Priorité 1 (très courants) en premier, puis Priorité 2, puis Priorité 3.

Vérifie que le JSON reste valide après chaque modification.