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

392 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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** :
```javascript
/**
* 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()
```javascript
/**
* 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** :
```javascript
const results = [];
const lemmas = simpleLemmatize(word);
const root = extractFrenchRoot(word); // NOUVEAU
```
**Ajouter après la ligne 146 (après matching sur synonymes lemmatisés)** :
```javascript
// 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()** :
```javascript
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)
```javascript
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)
```json
"voir": {
"traductions": [...],
"synonymes_fr": ["observer", "regarder", "voit", "vois", "vu", "vus", "vue", "vues", "voyait", "voyais", "voyant", "verra", "verras", "verront"]
}
```
**2. prendre**
```json
"prendre": {
"traductions": [...],
"synonymes_fr": ["pris", "prit", "prise", "prises", "prend", "prends", "prenait", "prenais", "prenant", "prendra", "prendras", "prendront"]
}
```
**3. faire**
```json
"faire": {
"traductions": [...],
"synonymes_fr": ["créer", "fait", "faits", "faite", "faites", "fais", "faisait", "faisais", "faisant", "fera", "feras", "feront"]
}
```
**4. manger** (nouveau verbe, déjà ajouté)
```json
"manger": {
"traductions": [...],
"synonymes_fr": ["mange", "manges", "mangé", "mangée", "mangés", "mangées", "mangeait", "mangeais", "mangeant", "mangera", "mangeras", "mangeront"]
}
```
**5. aller**
```json
"aller": {
"traductions": [...],
"synonymes_fr": ["va", "vas", "vais", "allé", "allée", "allés", "allées", "allait", "allais", "allant", "ira", "iras", "iront"]
}
```
**6. donner**
```json
"donner": {
"traductions": [...],
"synonymes_fr": ["donne", "donnes", "donné", "donnée", "donnés", "données", "donnait", "donnais", "donnant", "donnera", "donneras", "donneront"]
}
```
**7. dire**
```json
"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**
```json
"être": {
"traductions": [...],
"synonymes_fr": ["est", "es", "suis", "sont", "été", "était", "étais", "étant", "sera", "seras", "seront", "fut", "fus"]
}
```
**9. avoir**
```json
"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**
```json
"savoir": {
"traductions": [...],
"synonymes_fr": ["connaître", "sait", "sais", "su", "sue", "sus", "sues", "savait", "savais", "sachant", "saura", "sauras", "sauront"]
}
```
**11. chasser**
```json
"chasser": {
"traductions": [...],
"synonymes_fr": ["traquer", "chasse", "chasses", "chassé", "chassée", "chassés", "chassées", "chassait", "chassais", "chassant", "chassera", "chasseras", "chasseront"]
}
```
**12. transmettre**
```json
"transmettre": {
"traductions": [...],
"synonymes_fr": ["enseigner", "transmet", "transmets", "transmis", "transmise", "transmises", "transmettait", "transmettais", "transmettant", "transmettra", "transmettras", "transmettront"]
}
```
**13. garder**
```json
"garder": {
"traductions": [...],
"synonymes_fr": ["protéger", "garde", "gardes", "gardé", "gardée", "gardés", "gardées", "gardait", "gardais", "gardant", "gardera", "garderas", "garderont"]
}
```
**14. porter**
```json
"porter": {
"traductions": [...],
"synonymes_fr": ["transporter", "porte", "portes", "porté", "portée", "portés", "portées", "portait", "portais", "portant", "portera", "porteras", "porteront"]
}
```
**15. apprendre**
```json
"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
```bash
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
```bash
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
```bash
# 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.
```