Ajout système raffinement LLM CF→FR + extension lexique nourriture
Nouvelles fonctionnalités: - Endpoint /api/translate/conf2fr/llm avec raffinement LLM - Prompt cf2fr-refinement.txt expliquant structure Confluent - Test test-llm-refinement.bat pour validation Améliorations lexique: - Ajout lexique 23-nourriture.json (vocabulaire alimentaire) - Ajout lexique 24-habitat.json (habitat et construction) - Correction "generation" → noviuaita (nouvelles générations) - Ajout "cuisiner" → mukunekas (composition muk-u-nekas) - Fix Ariaska → Aliaska dans prompts Tests et outils: - Tests de coverage et reverse translation - Convertisseur de nombres - Debug lemmatisation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e93c2f485b
commit
5c03390aaf
@ -7,12 +7,51 @@
|
||||
* 3. Expansion sémantique (niveau 1: synonymes directs)
|
||||
* 4. Calcul dynamique du nombre max d'entrées selon longueur
|
||||
* 5. Fallback racines si aucun terme trouvé
|
||||
* 6. Conversion automatique des nombres français → Confluent
|
||||
*/
|
||||
|
||||
const { convertFrenchNumber, isNumber } = require('./numberConverter');
|
||||
|
||||
/**
|
||||
* FONCTION CENTRALE DE NORMALISATION
|
||||
* Normalise un texte français: lowercase + ligatures + accents + contractions
|
||||
* UTILISER CETTE FONCTION PARTOUT pour garantir la cohérence
|
||||
*
|
||||
* @param {string} text - Texte français à normaliser
|
||||
* @returns {string} - Texte normalisé (sans accents, contractions expansées)
|
||||
*/
|
||||
function normalizeFrenchText(text) {
|
||||
// ÉTAPE 1: Lowercase + ligatures
|
||||
let result = text
|
||||
.toLowerCase()
|
||||
.replace(/œ/g, 'oe') // Ligature œ → oe (cœur → coeur)
|
||||
.replace(/æ/g, 'ae'); // Ligature æ → ae
|
||||
|
||||
// ÉTAPE 2: Normaliser et retirer les accents
|
||||
result = result
|
||||
.normalize('NFD') // Décompose les caractères accentués
|
||||
.replace(/[\u0300-\u036f]/g, ''); // Retire les diacritiques (é→e, è→e, ê→e, etc.)
|
||||
|
||||
// ÉTAPE 3: Expanser les contractions françaises (l', d', n', etc.)
|
||||
// IMPORTANT: Capture TOUTES les apostrophes: ' (droite U+0027), ' (courbe gauche U+2018), ' (courbe droite U+2019)
|
||||
result = result
|
||||
.replace(/l[''']/g, 'le ') // l'enfant → le enfant
|
||||
.replace(/d[''']/g, 'de ') // d'eau → de eau
|
||||
.replace(/n[''']/g, 'ne ') // n'est → ne est
|
||||
.replace(/j[''']/g, 'je ') // j'ai → je ai
|
||||
.replace(/m[''']/g, 'me ') // m'a → me a
|
||||
.replace(/t[''']/g, 'te ') // t'a → te a
|
||||
.replace(/s[''']/g, 'se ') // s'est → se est
|
||||
.replace(/c[''']/g, 'ce ') // c'est → ce est
|
||||
.replace(/qu[''']/g, 'que '); // qu'il → que il
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenize un texte français
|
||||
* - Utilise normalizeFrenchText() pour la normalisation
|
||||
* - Détecte expressions figées (il y a, y a-t-il, etc.)
|
||||
* - Lowercase
|
||||
* - Retire ponctuation
|
||||
* - Split sur espaces
|
||||
* - Retire mots vides très courants (le, la, les, un, une, des, de, du)
|
||||
@ -21,41 +60,24 @@
|
||||
*/
|
||||
function tokenizeFrench(text) {
|
||||
// Mots vides à retirer (articles, prépositions très courantes)
|
||||
// NOTE: Les pronoms personnels (je, tu, il, elle, etc.) ne sont PAS des stopwords
|
||||
// car ils ont une traduction en Confluent (miki, sinu, tani, etc.)
|
||||
const stopWords = new Set([
|
||||
'le', 'la', 'les', 'un', 'une', 'des', 'de', 'du', 'd',
|
||||
'au', 'aux', 'à', 'et', 'ou', 'où', 'est', 'sont',
|
||||
'ne', 'je', 'me', 'te', 'se', 'ce', 'que', 'il', 'elle'
|
||||
'au', 'aux', 'a', 'et', 'ou', 'ou', 'est', 'sont',
|
||||
'ne', 'me', 'te', 'se', 'ce', 'que'
|
||||
]);
|
||||
|
||||
// ÉTAPE 1: Normaliser et nettoyer le texte
|
||||
// ORDRE IMPORTANT: lowercase → ligatures → accents → contractions
|
||||
let processedText = text
|
||||
.toLowerCase()
|
||||
.replace(/œ/g, 'oe') // Ligature œ → oe (cœur → coeur)
|
||||
.replace(/æ/g, 'ae') // Ligature æ → ae
|
||||
.normalize('NFD') // Décompose les caractères accentués
|
||||
.replace(/[\u0300-\u036f]/g, ''); // Retire les diacritiques (é→e, è→e, ê→e, etc.)
|
||||
// ÉTAPE 1: Utiliser la fonction centrale de normalisation
|
||||
let processedText = normalizeFrenchText(text);
|
||||
|
||||
// ÉTAPE 1.5: Nettoyer les contractions françaises (l', d', n', etc.)
|
||||
// APRÈS normalisation pour que "l'été" devienne "l'ete" puis "le ete"
|
||||
processedText = processedText
|
||||
.replace(/l['']/g, 'le ') // l'enfant → le enfant
|
||||
.replace(/d['']/g, 'de ') // d'eau → de eau
|
||||
.replace(/n['']/g, 'ne ') // n'est → ne est
|
||||
.replace(/j['']/g, 'je ') // j'ai → je ai
|
||||
.replace(/m['']/g, 'me ') // m'a → me a
|
||||
.replace(/t['']/g, 'te ') // t'a → te a
|
||||
.replace(/s['']/g, 'se ') // s'est → se est
|
||||
.replace(/c['']/g, 'ce ') // c'est → ce est
|
||||
.replace(/qu['']/g, 'que '); // qu'il → que il
|
||||
|
||||
// Expressions existentielles → "exister"
|
||||
// ÉTAPE 2: Expressions existentielles → "exister"
|
||||
processedText = processedText
|
||||
.replace(/il\s+y\s+a(?:vait)?/g, 'exister') // il y a, il y avait
|
||||
.replace(/y\s+a-t-il/g, 'exister') // y a-t-il
|
||||
.replace(/ne\s+y\s+a-t-il\s+pas/g, 'exister'); // n'y a-t-il pas (déjà décontracté)
|
||||
|
||||
// ÉTAPE 2: Tokenisation normale
|
||||
// ÉTAPE 3: Tokenisation - retirer ponctuation et splitter
|
||||
return processedText
|
||||
.replace(/[^\w\s]/g, ' ') // Remplacer ponctuation par espaces
|
||||
.split(/\s+/)
|
||||
@ -252,6 +274,33 @@ function findRelevantEntries(words, lexique, maxEntries, normalizedText = '') {
|
||||
|
||||
// Chercher chaque mot
|
||||
for (const word of words) {
|
||||
// ÉTAPE 1: Vérifier si c'est un nombre
|
||||
const numberConversion = convertFrenchNumber(word);
|
||||
|
||||
if (numberConversion) {
|
||||
// C'est un nombre - créer une entrée virtuelle
|
||||
const numberEntry = {
|
||||
mot_francais: word,
|
||||
traductions: [{
|
||||
confluent: numberConversion.confluent,
|
||||
type: numberConversion.type
|
||||
}],
|
||||
score: 1.0,
|
||||
source_file: 'number_system'
|
||||
};
|
||||
|
||||
foundEntries.set(word, numberEntry);
|
||||
wordsFound.push({
|
||||
input: word,
|
||||
found: word,
|
||||
confluent: numberConversion.confluent,
|
||||
type: numberConversion.type,
|
||||
score: 1.0
|
||||
});
|
||||
continue; // Passer au mot suivant
|
||||
}
|
||||
|
||||
// ÉTAPE 2: Recherche normale dans le lexique
|
||||
const results = searchWord(word, lexique.dictionnaire, normalizedText);
|
||||
|
||||
if (results.length > 0) {
|
||||
@ -464,6 +513,7 @@ function analyzeContext(text, lexique, options = {}) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
normalizeFrenchText, // FONCTION CENTRALE - utiliser partout !
|
||||
tokenizeFrench,
|
||||
calculateMaxEntries,
|
||||
simpleLemmatize,
|
||||
|
||||
109
ConfluentTranslator/debug-lemmatization.js
Normal file
109
ConfluentTranslator/debug-lemmatization.js
Normal file
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* DEBUG COMPLET - PROBLÈME DE LEMMATISATION
|
||||
*
|
||||
* Objectif: Comprendre EXACTEMENT où le traitement casse les mots accentués
|
||||
*/
|
||||
|
||||
const { tokenizeFrench } = require('./contextAnalyzer');
|
||||
|
||||
console.log('\n' + '='.repeat(70));
|
||||
console.log('DEBUG COMPLET - LEMMATISATION ACCENTS');
|
||||
console.log('='.repeat(70) + '\n');
|
||||
|
||||
// Cas problématiques reportés
|
||||
const problemes = [
|
||||
'mémoire', // → m + moire
|
||||
'échos', // → chos
|
||||
'légume', // → l + gume
|
||||
'épice', // → pice
|
||||
'lumière', // → lumi + re
|
||||
'fenêtre', // → fen + tre
|
||||
];
|
||||
|
||||
console.log('1. TEST TOKENIZATION ACTUELLE:\n');
|
||||
problemes.forEach(mot => {
|
||||
const tokens = tokenizeFrench(mot);
|
||||
const status = tokens.length === 1 && tokens[0].length > 2 ? '✅' : '❌';
|
||||
console.log(` ${status} "${mot}" → [${tokens.map(t => `"${t}"`).join(', ')}]`);
|
||||
});
|
||||
|
||||
console.log('\n' + '-'.repeat(70));
|
||||
console.log('2. ANALYSE ÉTAPE PAR ÉTAPE:\n');
|
||||
|
||||
function analyzeStep(mot) {
|
||||
console.log(`\n Mot: "${mot}"`);
|
||||
console.log(` Code points: ${[...mot].map(c => 'U+' + c.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')).join(' ')}`);
|
||||
|
||||
// Étape 1: lowercase
|
||||
let step1 = mot.toLowerCase();
|
||||
console.log(` 1. toLowerCase: "${step1}"`);
|
||||
|
||||
// Étape 2: ligatures
|
||||
let step2 = step1.replace(/œ/g, 'oe').replace(/æ/g, 'ae');
|
||||
console.log(` 2. Ligatures: "${step2}"`);
|
||||
|
||||
// Étape 3: NFD normalize
|
||||
let step3 = step2.normalize('NFD');
|
||||
console.log(` 3. NFD: "${step3}" (length: ${step3.length})`);
|
||||
console.log(` Code points: ${[...step3].map(c => 'U+' + c.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')).join(' ')}`);
|
||||
|
||||
// Étape 4: Retirer diacritiques
|
||||
let step4 = step3.replace(/[\u0300-\u036f]/g, '');
|
||||
console.log(` 4. Sans diacritiques: "${step4}"`);
|
||||
|
||||
// Étape 5: Contractions (ne devrait rien faire ici)
|
||||
let step5 = step4
|
||||
.replace(/l[''']/g, 'le ')
|
||||
.replace(/d[''']/g, 'de ')
|
||||
.replace(/n[''']/g, 'ne ')
|
||||
.replace(/j[''']/g, 'je ')
|
||||
.replace(/m[''']/g, 'me ')
|
||||
.replace(/t[''']/g, 'te ')
|
||||
.replace(/s[''']/g, 'se ')
|
||||
.replace(/c[''']/g, 'ce ')
|
||||
.replace(/qu[''']/g, 'que ');
|
||||
console.log(` 5. Après contractions: "${step5}"`);
|
||||
|
||||
// Étape 6: Retirer ponctuation
|
||||
let step6 = step5.replace(/[^\w\s]/g, ' ');
|
||||
console.log(` 6. Sans ponctuation: "${step6}"`);
|
||||
|
||||
// Étape 7: Split
|
||||
let step7 = step6.split(/\s+/).filter(w => w.length > 0);
|
||||
console.log(` 7. Tokens: [${step7.map(t => `"${t}"`).join(', ')}]`);
|
||||
|
||||
return step7;
|
||||
}
|
||||
|
||||
problemes.forEach(mot => analyzeStep(mot));
|
||||
|
||||
console.log('\n' + '-'.repeat(70));
|
||||
console.log('3. TEST AVEC CONTEXTE (apostrophes):\n');
|
||||
|
||||
const contextTests = [
|
||||
"l'échos",
|
||||
"l'épice",
|
||||
"la mémoire",
|
||||
"les légumes",
|
||||
"la lumière",
|
||||
"la fenêtre"
|
||||
];
|
||||
|
||||
contextTests.forEach(phrase => {
|
||||
const tokens = tokenizeFrench(phrase);
|
||||
console.log(` "${phrase}" → [${tokens.map(t => `"${t}"`).join(', ')}]`);
|
||||
});
|
||||
|
||||
console.log('\n' + '-'.repeat(70));
|
||||
console.log('4. VÉRIFICATION REGEX \\w AVEC ACCENTS:\n');
|
||||
|
||||
const testW = 'é';
|
||||
console.log(` Le caractère "é" matche \\w ? ${/\w/.test(testW) ? 'OUI' : 'NON'}`);
|
||||
console.log(` Le caractère "é" matche [^\\w\\s] ? ${/[^\w\s]/.test(testW) ? 'OUI (sera remplacé!)' : 'NON'}`);
|
||||
|
||||
const testE = 'e';
|
||||
console.log(` Le caractère "e" matche \\w ? ${/\w/.test(testE) ? 'OUI' : 'NON'}`);
|
||||
|
||||
console.log('\n' + '='.repeat(70));
|
||||
console.log('FIN DEBUG');
|
||||
console.log('='.repeat(70) + '\n');
|
||||
@ -44,9 +44,9 @@ function loadLexiqueFromDir(lexiqueDir) {
|
||||
try {
|
||||
const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
||||
|
||||
if (content.dictionnaire) {
|
||||
// Fusionner les entrées
|
||||
for (const [motFr, data] of Object.entries(content.dictionnaire)) {
|
||||
// Fonction helper pour merger des entrées
|
||||
const mergeEntries = (entries, sectionName = 'dictionnaire') => {
|
||||
for (const [motFr, data] of Object.entries(entries)) {
|
||||
const key = normalizeText(motFr);
|
||||
|
||||
if (!result.dictionnaire[key]) {
|
||||
@ -68,7 +68,8 @@ function loadLexiqueFromDir(lexiqueDir) {
|
||||
if (!exists) {
|
||||
result.dictionnaire[key].traductions.push({
|
||||
...trad,
|
||||
source_file: file
|
||||
source_file: file,
|
||||
source_section: sectionName
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -98,6 +99,16 @@ function loadLexiqueFromDir(lexiqueDir) {
|
||||
result.dictionnaire[key].source_files.push(file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Charger la section "dictionnaire" si elle existe
|
||||
if (content.dictionnaire) {
|
||||
mergeEntries(content.dictionnaire, 'dictionnaire');
|
||||
}
|
||||
|
||||
// Charger la section "pronoms" si elle existe (pour 02-racines-standards.json)
|
||||
if (content.pronoms) {
|
||||
mergeEntries(content.pronoms, 'pronoms');
|
||||
}
|
||||
|
||||
result.meta.files_loaded.push(file);
|
||||
|
||||
121
ConfluentTranslator/numberConverter.js
Normal file
121
ConfluentTranslator/numberConverter.js
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Convertisseur de nombres français → Confluent (base 12)
|
||||
*
|
||||
* Système basé sur la documentation SYSTEME_NUMERIQUE_BASE12.md
|
||||
*/
|
||||
|
||||
// Table de conversion pour les nombres de base (0-12)
|
||||
const BASE_NUMBERS = {
|
||||
// Mots français
|
||||
'zero': { confluent: 'zaro', value: 0 },
|
||||
'zéro': { confluent: 'zaro', value: 0 },
|
||||
'un': { confluent: 'iko', value: 1 },
|
||||
'une': { confluent: 'iko', value: 1 },
|
||||
'deux': { confluent: 'diku', value: 2 },
|
||||
'trois': { confluent: 'tiru', value: 3 },
|
||||
'quatre': { confluent: 'katu', value: 4 },
|
||||
'cinq': { confluent: 'penu', value: 5 },
|
||||
'six': { confluent: 'seku', value: 6 },
|
||||
'sept': { confluent: 'sivu', value: 7 },
|
||||
'huit': { confluent: 'oktu', value: 8 },
|
||||
'neuf': { confluent: 'novu', value: 9 },
|
||||
'dix': { confluent: 'deku', value: 10 },
|
||||
'onze': { confluent: 'levu', value: 11 },
|
||||
'douze': { confluent: 'tolu', value: 12 },
|
||||
|
||||
// Nombres composés courants
|
||||
'treize': { confluent: 'tolu iko', value: 13 },
|
||||
'quatorze': { confluent: 'tolu diku', value: 14 },
|
||||
'quinze': { confluent: 'tolu tiru', value: 15 },
|
||||
'seize': { confluent: 'tolu katu', value: 16 },
|
||||
|
||||
// Dizaines
|
||||
'vingt': { confluent: 'tolu oktu', value: 20 },
|
||||
'trente': { confluent: 'diku tolu seku', value: 30 },
|
||||
'quarante': { confluent: 'tiru tolu katu', value: 40 },
|
||||
'cinquante': { confluent: 'katu tolu diku', value: 50 },
|
||||
'soixante': { confluent: 'penu tolu', value: 60 },
|
||||
|
||||
// Centaines
|
||||
'cent': { confluent: 'oktu tolu katu', value: 100 },
|
||||
'mille': { confluent: 'seku seku tolu oktu', value: 1000 },
|
||||
|
||||
// Ordinaux
|
||||
'premier': { confluent: 'ena', value: 1 },
|
||||
'première': { confluent: 'ena', value: 1 },
|
||||
'deuxième': { confluent: 'dikuena', value: 2 },
|
||||
'second': { confluent: 'dikuena', value: 2 },
|
||||
'seconde': { confluent: 'dikuena', value: 2 },
|
||||
'troisième': { confluent: 'tiruena', value: 3 },
|
||||
'dernier': { confluent: 'osiana', value: -1 },
|
||||
'dernière': { confluent: 'osiana', value: -1 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Convertit un nombre en français vers Confluent
|
||||
* @param {string} frenchNumber - Nombre en français (normalisé, minuscules)
|
||||
* @returns {object|null} - { confluent: string, value: number, type: 'nombre'|'ordinal' } ou null
|
||||
*/
|
||||
function convertFrenchNumber(frenchNumber) {
|
||||
const normalized = frenchNumber.toLowerCase().trim();
|
||||
|
||||
if (BASE_NUMBERS[normalized]) {
|
||||
const { confluent, value } = BASE_NUMBERS[normalized];
|
||||
const type = ['premier', 'première', 'deuxième', 'second', 'seconde', 'troisième', 'dernier', 'dernière'].includes(normalized)
|
||||
? 'ordinal'
|
||||
: 'nombre';
|
||||
|
||||
return {
|
||||
confluent,
|
||||
value,
|
||||
type,
|
||||
score: 1.0
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Détecte si un mot français est un nombre
|
||||
* @param {string} word - Mot en français
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNumber(word) {
|
||||
const normalized = word.toLowerCase().trim();
|
||||
return BASE_NUMBERS.hasOwnProperty(normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit une liste de mots et identifie les nombres
|
||||
* @param {string[]} words - Liste de mots français
|
||||
* @returns {object[]} - Liste d'objets { word, confluent, isNumber, value }
|
||||
*/
|
||||
function convertNumbersInText(words) {
|
||||
return words.map(word => {
|
||||
const numberConversion = convertFrenchNumber(word);
|
||||
|
||||
if (numberConversion) {
|
||||
return {
|
||||
word,
|
||||
confluent: numberConversion.confluent,
|
||||
isNumber: true,
|
||||
value: numberConversion.value,
|
||||
type: numberConversion.type,
|
||||
score: numberConversion.score
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
word,
|
||||
isNumber: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
convertFrenchNumber,
|
||||
isNumber,
|
||||
convertNumbersInText,
|
||||
BASE_NUMBERS
|
||||
};
|
||||
@ -214,7 +214,7 @@ Les verbes sont des racines de 5 lettres (CVCVC) qui finissent par une consonne.
|
||||
Castes:
|
||||
- Nakukeko (Enfants des Échos): nak-u-keko
|
||||
- Nakuura (Enfants du Courant): nak-u-ura
|
||||
- Ariaska (Ailes-Grises): ar-i-aska
|
||||
- Aliaska (Ailes-Grises): al-i-aska
|
||||
- Akoazana (Faucons Chasseurs): ak-oa-zana
|
||||
- Takitosa (Passes-bien): tak-i-tosa
|
||||
- Oraumi (Voix de l'Aurore): or-a-umi
|
||||
|
||||
89
ConfluentTranslator/prompts/cf2fr-refinement.txt
Normal file
89
ConfluentTranslator/prompts/cf2fr-refinement.txt
Normal file
@ -0,0 +1,89 @@
|
||||
Tu es un expert linguiste spécialisé dans la traduction du Confluent (langue construite) vers le français.
|
||||
|
||||
# CONTEXTE DE LA LANGUE CONFLUENTE
|
||||
|
||||
La langue de la Confluence est une langue construite parlée par une civilisation de chamans vivant au confluent de deux rivières. Cette langue reflète leurs valeurs culturelles : observation, mémoire, transmission et liberté.
|
||||
|
||||
## Structure grammaticale (SOV - Sujet-Objet-Verbe)
|
||||
|
||||
L'ordre des mots est strictement : SUJET + OBJET + VERBE
|
||||
|
||||
**Particules grammaticales:**
|
||||
- `va` = marqueur de SUJET
|
||||
- `vo` = marqueur d'OBJET
|
||||
- `no` = locatif (dans/sur/à)
|
||||
- `na` = génitif (de/du/des - possession)
|
||||
- `se` = coordination (et)
|
||||
- `lo` = opposition/coordination (mais/et)
|
||||
- `ta` = conjonction temporelle (tandis que/pendant que)
|
||||
- `u` = marqueur de PRÉSENT
|
||||
- `ul` = marqueur de CAPACITÉ/POSSIBILITÉ (pouvoir, devoir)
|
||||
- `en` = marqueur de FUTUR
|
||||
|
||||
## Principes de composition
|
||||
|
||||
Les mots confluents sont souvent des compositions de racines avec des liaisons sacrées:
|
||||
- `-i-` = agentivité (celui qui fait)
|
||||
- `-u-` = appartenance (de/du)
|
||||
- `-a-` = relation (avec)
|
||||
- `-eo-` = totalité/éternité
|
||||
|
||||
**Exemples:**
|
||||
- `nakukeko` = nak-u-keko = "enfants des échos"
|
||||
- `aliaska` = al-i-aska = "porteurs de la grue libre" = Ailes-Grises
|
||||
- `uraikota` = ura-i-kota = "confluence de vie" = civilisation
|
||||
- `silimira` = sili-mira = "regard observant" = observation
|
||||
|
||||
## Castes et noms propres (toujours en minuscules)
|
||||
|
||||
- `nakukeko` = Enfants des Échos
|
||||
- `nakuura` = Enfants du Courant
|
||||
- `aliaska` = Ailes-Grises
|
||||
- `akoazana` = Faucons Chasseurs
|
||||
- `takitosa` = Passes-bien
|
||||
- `oraumi` = Voix de l'Aurore
|
||||
- `uraakota` = La Confluence (lieu sacré)
|
||||
- `siliaska` = Le peuple (littéralement "regard libre")
|
||||
|
||||
## Concepts culturels importants
|
||||
|
||||
- **aska** = liberté (racine sacrée)
|
||||
- **veri** = vérité
|
||||
- **memu** = mémoire (concept central)
|
||||
- **kota** = confluence/union
|
||||
- **umi** = esprit/âme
|
||||
- **aita** = ancêtres
|
||||
|
||||
# TA TÂCHE
|
||||
|
||||
On te donne une **traduction mot-à-mot brute** d'un texte confluent vers le français. Cette traduction contient:
|
||||
1. Les particules grammaticales (va, vo, no, etc.)
|
||||
2. Les traductions littérales de chaque mot
|
||||
3. Les alternatives entre parenthèses
|
||||
|
||||
**Tu dois:**
|
||||
1. Comprendre la structure grammaticale SOV
|
||||
2. Identifier les particules et leur rôle
|
||||
3. Reconstituer le sens en français fluide et naturel
|
||||
4. Respecter le contexte culturel de la Confluence
|
||||
5. Produire un texte français élégant et compréhensible
|
||||
|
||||
**Format de sortie:**
|
||||
Retourne UNIQUEMENT le texte français final, sans explication ni métadonnées.
|
||||
|
||||
**Exemple:**
|
||||
|
||||
**Entrée brute:**
|
||||
"va enfants des echos vo confluence voir u"
|
||||
|
||||
**Ta sortie:**
|
||||
"Les Enfants des Échos observent la confluence."
|
||||
|
||||
---
|
||||
|
||||
**IMPORTANT:**
|
||||
- Utilise les majuscules pour les noms propres de castes en français
|
||||
- Garde le sens culturel et spirituel
|
||||
- Transforme la structure SOV en structure française naturelle (SVO)
|
||||
- Élimine les particules grammaticales confluentes (va, vo, no, etc.)
|
||||
- Choisis la meilleure traduction parmi les alternatives proposées selon le contexte
|
||||
@ -566,6 +566,83 @@ app.post('/api/translate/conf2fr', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// NEW: Confluent → French with LLM refinement
|
||||
app.post('/api/translate/conf2fr/llm', async (req, res) => {
|
||||
const { text, variant = 'ancien', provider = 'anthropic', model = 'claude-sonnet-4-20250514' } = req.body;
|
||||
|
||||
if (!text) {
|
||||
return res.status(400).json({ error: 'Missing parameter: text' });
|
||||
}
|
||||
|
||||
const variantKey = variant === 'proto' ? 'proto' : 'ancien';
|
||||
|
||||
if (!confluentIndexes[variantKey]) {
|
||||
return res.status(500).json({ error: `Confluent index for ${variantKey} not loaded` });
|
||||
}
|
||||
|
||||
try {
|
||||
// Step 1: Get raw word-by-word translation
|
||||
const rawTranslation = translateConfluentToFrench(text, confluentIndexes[variantKey]);
|
||||
|
||||
// Step 2: Load refinement prompt
|
||||
const refinementPrompt = fs.readFileSync(path.join(__dirname, 'prompts', 'cf2fr-refinement.txt'), 'utf-8');
|
||||
|
||||
// Step 3: Use LLM to refine translation
|
||||
let refinedText;
|
||||
|
||||
if (provider === 'anthropic') {
|
||||
const anthropic = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
});
|
||||
|
||||
const message = await anthropic.messages.create({
|
||||
model: model,
|
||||
max_tokens: 2048,
|
||||
system: refinementPrompt,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: `Voici la traduction brute mot-à-mot du Confluent vers le français. Transforme-la en français fluide et naturel:\n\n${rawTranslation.translation}`
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
refinedText = message.content[0].text.trim();
|
||||
} else if (provider === 'openai') {
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: model,
|
||||
messages: [
|
||||
{ role: 'system', content: refinementPrompt },
|
||||
{ role: 'user', content: `Voici la traduction brute mot-à-mot du Confluent vers le français. Transforme-la en français fluide et naturel:\n\n${rawTranslation.translation}` }
|
||||
]
|
||||
});
|
||||
|
||||
refinedText = completion.choices[0].message.content.trim();
|
||||
} else {
|
||||
return res.status(400).json({ error: 'Unsupported provider. Use "anthropic" or "openai".' });
|
||||
}
|
||||
|
||||
// Return both raw and refined versions
|
||||
res.json({
|
||||
confluentText: text,
|
||||
rawTranslation: rawTranslation.translation,
|
||||
refinedTranslation: refinedText,
|
||||
wordsTranslated: rawTranslation.wordsTranslated,
|
||||
wordsNotTranslated: rawTranslation.wordsNotTranslated,
|
||||
provider,
|
||||
model
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Confluent→FR LLM refinement error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`ConfluentTranslator running on http://localhost:${PORT}`);
|
||||
console.log(`Loaded: ${lexiques.ancien?.meta?.total_entries || 0} ancien entries, ${lexiques.proto?.meta?.total_entries || 0} proto entries`);
|
||||
|
||||
33
ConfluentTranslator/test-abstract-concepts.js
Normal file
33
ConfluentTranslator/test-abstract-concepts.js
Normal file
@ -0,0 +1,33 @@
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const path = require('path');
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== RECHERCHE CONCEPTS ABSTRAITS ===\n');
|
||||
|
||||
const recherches = [
|
||||
'civilisation', 'observation', 'observer', 'regarder', 'regard',
|
||||
'confluence', 'union', 'peuple', 'culture', 'tradition',
|
||||
'sagesse', 'connaissance', 'memoire', 'mémoire', 'savoir',
|
||||
'libre', 'liberte', 'liberté', 'voir', 'vision'
|
||||
];
|
||||
|
||||
recherches.forEach(mot => {
|
||||
// Normaliser comme le fait le lexiqueLoader
|
||||
const normalized = mot.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
const found = lexiques.ancien.dictionnaire[normalized];
|
||||
if (found?.traductions) {
|
||||
console.log(`✅ ${mot}: ${found.traductions[0].confluent} (${found.traductions[0].type})`);
|
||||
} else {
|
||||
console.log(`❌ ${mot}: NON TROUVÉ`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n=== RACINES LIÉES (sili, aska, ura, kota) ===\n');
|
||||
const racines = ['sili', 'aska', 'ura', 'kota'];
|
||||
racines.forEach(mot => {
|
||||
const found = lexiques.ancien.dictionnaire[mot];
|
||||
if (found?.traductions) {
|
||||
console.log(`${mot}: ${found.mot_francais} - ${found.traductions[0].confluent}`);
|
||||
}
|
||||
});
|
||||
69
ConfluentTranslator/test-api-accents.js
Normal file
69
ConfluentTranslator/test-api-accents.js
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Test API avec caractères accentués
|
||||
*/
|
||||
|
||||
const http = require('http');
|
||||
|
||||
const testText = "La mémoire des échos résonne dans la lumière. Les légumes parfument la fenêtre de notre civilisation.";
|
||||
|
||||
console.log('\n=== TEST API AVEC ACCENTS ===\n');
|
||||
console.log('Texte envoyé:', testText);
|
||||
console.log('');
|
||||
|
||||
const data = JSON.stringify({ text: testText });
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 3000,
|
||||
path: '/api/analyze/coverage',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Content-Length': Buffer.byteLength(data)
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk) => body += chunk);
|
||||
res.on('end', () => {
|
||||
const result = JSON.parse(body);
|
||||
|
||||
console.log('Couverture:', result.coverage + '%');
|
||||
console.log('');
|
||||
|
||||
console.log('=== MOTS TROUVÉS ===');
|
||||
result.found.forEach(w => {
|
||||
console.log(` ✅ "${w.word}" → ${w.confluent}`);
|
||||
});
|
||||
|
||||
console.log('');
|
||||
console.log('=== MOTS MANQUANTS ===');
|
||||
result.missing.forEach(w => {
|
||||
console.log(` ❌ "${w.word}"`);
|
||||
});
|
||||
|
||||
console.log('');
|
||||
|
||||
// Vérifier si les mots accentués sont cassés
|
||||
const brokenWords = result.missing.filter(w =>
|
||||
['m', 'moire', 'chos', 'lumi', 're', 'l', 'gumes', 'fen', 'tre'].includes(w.word)
|
||||
);
|
||||
|
||||
if (brokenWords.length > 0) {
|
||||
console.log('❌ PROBLÈME: Mots cassés détectés !');
|
||||
console.log(' Les accents ne sont pas correctement traités.');
|
||||
brokenWords.forEach(w => console.log(` - "${w.word}"`));
|
||||
} else {
|
||||
console.log('✅ OK: Aucun mot cassé par les accents !');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (e) => {
|
||||
console.error('Erreur:', e.message);
|
||||
console.log('Le serveur est-il en cours d\'exécution sur le port 3000 ?');
|
||||
});
|
||||
|
||||
req.write(data);
|
||||
req.end();
|
||||
34
ConfluentTranslator/test-apostrophe-fix.js
Normal file
34
ConfluentTranslator/test-apostrophe-fix.js
Normal file
@ -0,0 +1,34 @@
|
||||
const { tokenizeFrench } = require('./contextAnalyzer');
|
||||
|
||||
console.log('\n=== TEST FIX APOSTROPHES ===\n');
|
||||
|
||||
const testCases = [
|
||||
// Apostrophe droite (ASCII 39)
|
||||
"l'échos",
|
||||
"d'écouter",
|
||||
"m'a dit",
|
||||
"n'est pas",
|
||||
|
||||
// Apostrophe courbe (Unicode)
|
||||
"l'enfant",
|
||||
"d'eau",
|
||||
|
||||
// Mots avec accents
|
||||
"mémoire",
|
||||
"écouter",
|
||||
"échos"
|
||||
];
|
||||
|
||||
testCases.forEach(test => {
|
||||
const tokens = tokenizeFrench(test);
|
||||
console.log(`Input: "${test}"`);
|
||||
console.log(`Tokens: [${tokens.map(t => `"${t}"`).join(', ')}]`);
|
||||
console.log('');
|
||||
});
|
||||
|
||||
console.log('\n=== TEST PHRASE COMPLÈTE ===\n');
|
||||
const phrase = "Les échos de la mémoire résonnent dans l'esprit des anciens qui écoutent.";
|
||||
const tokens = tokenizeFrench(phrase);
|
||||
console.log(`Input: "${phrase}"`);
|
||||
console.log(`Tokens: [${tokens.map(t => `"${t}"`).join(', ')}]`);
|
||||
console.log(`Count: ${tokens.length} mots`);
|
||||
126
ConfluentTranslator/test-coverage.bat
Normal file
126
ConfluentTranslator/test-coverage.bat
Normal file
@ -0,0 +1,126 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo ===============================================
|
||||
echo CONFLUENT COVERAGE TEST SUITE
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Kill any existing server on port 3000
|
||||
echo [1/4] Arret du serveur existant...
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :3000') do (
|
||||
taskkill //F //PID %%a >nul 2>&1
|
||||
)
|
||||
timeout /t 2 /nobreak >nul
|
||||
|
||||
REM Start server in background
|
||||
echo [2/4] Demarrage du serveur...
|
||||
cd /d "%~dp0"
|
||||
start /B cmd /c "npm start >nul 2>&1"
|
||||
timeout /t 5 /nobreak >nul
|
||||
|
||||
REM Check if server is running
|
||||
curl -s http://localhost:3000/api/stats >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo [ERREUR] Le serveur n'a pas demarre correctement
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [3/4] Execution des tests de coverage...
|
||||
echo.
|
||||
|
||||
REM Create temp files
|
||||
set TEMP_FILE=%TEMP%\coverage_results.json
|
||||
set TEMP_MISSING=%TEMP%\missing_words.txt
|
||||
|
||||
REM Test 1 - Texte court culturel
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"Les enfants des echos observent le courant dans la confluence\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV1=%%a
|
||||
echo === TEST 1 - Texte court culturel === > "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Test 2 - Texte long culturel
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"La civilisation de la Confluence repose sur l'observation, la transmission de la memoire et l'union des castes. Les Enfants des Echos ecoutent les murmures du passe tandis que les Faucons Chasseurs protegent les frontieres.\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV2=%%a
|
||||
echo === TEST 2 - Texte long culturel === >> "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Test 3 - Vocabulaire quotidien
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"manger boire eau nourriture pain viande poisson legume fruit sel epice cuire couteau table feu lumiere maison porte fenetre toit sol mur escalier\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV3=%%a
|
||||
echo === TEST 3 - Vocabulaire quotidien === >> "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Test 4 - Pronoms et verbes
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"je tu il elle nous vous ils regarder voir observer ecouter parler dire penser savoir comprendre aimer vouloir pouvoir devoir faire aller venir\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV4=%%a
|
||||
echo === TEST 4 - Pronoms et verbes === >> "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Test 5 - Adjectifs
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"grand petit haut bas long court chaud froid bon mauvais beau laid fort faible rapide lent clair sombre\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV5=%%a
|
||||
echo === TEST 5 - Adjectifs courants === >> "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Test 6 - Nombres
|
||||
curl -s -X POST http://localhost:3000/api/analyze/coverage -H "Content-Type: application/json" -d "{\"text\": \"un deux trois quatre cinq six sept huit neuf dix cent mille premier dernier\"}" > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"coverage\"" "%TEMP_FILE%"') do set COV6=%%a
|
||||
echo === TEST 6 - Nombres === >> "%TEMP_MISSING%"
|
||||
type "%TEMP_FILE%" | findstr /C:"\"missing\"" >> "%TEMP_MISSING%"
|
||||
echo. >> "%TEMP_MISSING%"
|
||||
|
||||
REM Get stats
|
||||
curl -s http://localhost:3000/api/stats > "%TEMP_FILE%"
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr "\"total_entries\"" "%TEMP_FILE%"') do set ENTRIES=%%a
|
||||
|
||||
echo [4/4] Generation du rapport...
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo RAPPORT DE COVERAGE
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo Lexique charge: %ENTRIES% entrees (ancien)
|
||||
echo.
|
||||
echo TEST 1 - Texte court culturel : %COV1%%%
|
||||
echo TEST 2 - Texte long culturel : %COV2%%%
|
||||
echo TEST 3 - Vocabulaire quotidien : %COV3%%%
|
||||
echo TEST 4 - Pronoms et verbes : %COV4%%%
|
||||
echo TEST 5 - Adjectifs courants : %COV5%%%
|
||||
echo TEST 6 - Nombres : %COV6%%%
|
||||
echo.
|
||||
|
||||
REM Calculate average
|
||||
set /a AVG=(%COV1%+%COV2%+%COV3%+%COV4%+%COV5%+%COV6%)/6
|
||||
echo COVERAGE MOYEN : %AVG%%%
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo MOTS MANQUANTS PAR TEST
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Display missing words with python for better JSON parsing
|
||||
python -c "import json; data=open(r'%TEMP_MISSING%', encoding='utf-8').read().replace('\\', '').replace('}{', '}\n{'); sections=data.split('==='); [print(section.strip()) for section in sections if section.strip()]" 2>nul
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [Parsage JSON echoue - affichage brut]
|
||||
type "%TEMP_MISSING%"
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo Serveur toujours actif sur http://localhost:3000
|
||||
echo Pour arreter: taskkill //F //PID [PID du node.exe]
|
||||
echo.
|
||||
|
||||
REM Clean up temp files
|
||||
del "%TEMP_FILE%" >nul 2>&1
|
||||
del "%TEMP_MISSING%" >nul 2>&1
|
||||
|
||||
endlocal
|
||||
131
ConfluentTranslator/test-coverage.sh
Normal file
131
ConfluentTranslator/test-coverage.sh
Normal file
@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "==============================================="
|
||||
echo " CONFLUENT COVERAGE TEST SUITE"
|
||||
echo "==============================================="
|
||||
echo ""
|
||||
|
||||
# Kill any existing server on port 3000
|
||||
echo "[1/4] Arrêt du serveur existant..."
|
||||
lsof -ti:3000 | xargs kill -9 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Start server in background
|
||||
echo "[2/4] Démarrage du serveur..."
|
||||
cd "$(dirname "$0")"
|
||||
npm start > /dev/null 2>&1 &
|
||||
SERVER_PID=$!
|
||||
sleep 5
|
||||
|
||||
# Check if server is running
|
||||
if ! curl -s http://localhost:3000/api/stats > /dev/null 2>&1; then
|
||||
echo "[ERREUR] Le serveur n'a pas démarré correctement"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[3/4] Exécution des tests de coverage..."
|
||||
echo ""
|
||||
|
||||
# Function to extract coverage
|
||||
get_coverage() {
|
||||
echo "$1" | grep -o '"coverage":[0-9]*' | grep -o '[0-9]*'
|
||||
}
|
||||
|
||||
# Function to extract missing words
|
||||
get_missing() {
|
||||
echo "$1" | python3 -c "import sys, json; data=json.load(sys.stdin); print(', '.join([w['word'] for w in data.get('missing', [])]))" 2>/dev/null || echo "N/A"
|
||||
}
|
||||
|
||||
# Test 1 - Texte court culturel
|
||||
RESULT1=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "Les enfants des echos observent le courant dans la confluence"}')
|
||||
COV1=$(get_coverage "$RESULT1")
|
||||
MISS1=$(get_missing "$RESULT1")
|
||||
|
||||
# Test 2 - Texte long culturel
|
||||
RESULT2=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "La civilisation de la Confluence repose sur l'\''observation, la transmission de la memoire et l'\''union des castes. Les Enfants des Echos ecoutent les murmures du passe tandis que les Faucons Chasseurs protegent les frontieres."}')
|
||||
COV2=$(get_coverage "$RESULT2")
|
||||
MISS2=$(get_missing "$RESULT2")
|
||||
|
||||
# Test 3 - Vocabulaire quotidien
|
||||
RESULT3=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "manger boire eau nourriture pain viande poisson legume fruit sel epice cuire couteau table feu lumiere maison porte fenetre toit sol mur escalier"}')
|
||||
COV3=$(get_coverage "$RESULT3")
|
||||
MISS3=$(get_missing "$RESULT3")
|
||||
|
||||
# Test 4 - Pronoms et verbes
|
||||
RESULT4=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "je tu il elle nous vous ils regarder voir observer ecouter parler dire penser savoir comprendre aimer vouloir pouvoir devoir faire aller venir"}')
|
||||
COV4=$(get_coverage "$RESULT4")
|
||||
MISS4=$(get_missing "$RESULT4")
|
||||
|
||||
# Test 5 - Adjectifs
|
||||
RESULT5=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "grand petit haut bas long court chaud froid bon mauvais beau laid fort faible rapide lent clair sombre"}')
|
||||
COV5=$(get_coverage "$RESULT5")
|
||||
MISS5=$(get_missing "$RESULT5")
|
||||
|
||||
# Test 6 - Nombres
|
||||
RESULT6=$(curl -s -X POST http://localhost:3000/api/analyze/coverage \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "un deux trois quatre cinq six sept huit neuf dix cent mille premier dernier"}')
|
||||
COV6=$(get_coverage "$RESULT6")
|
||||
MISS6=$(get_missing "$RESULT6")
|
||||
|
||||
# Get stats
|
||||
STATS=$(curl -s http://localhost:3000/api/stats)
|
||||
ENTRIES=$(echo "$STATS" | grep -o '"total_entries":[0-9]*' | head -1 | grep -o '[0-9]*')
|
||||
|
||||
echo "[4/4] Génération du rapport..."
|
||||
echo ""
|
||||
echo "==============================================="
|
||||
echo " RAPPORT DE COVERAGE"
|
||||
echo "==============================================="
|
||||
echo ""
|
||||
echo "Lexique chargé: $ENTRIES entrées (ancien)"
|
||||
echo ""
|
||||
echo "TEST 1 - Texte court culturel : ${COV1}%"
|
||||
echo "TEST 2 - Texte long culturel : ${COV2}%"
|
||||
echo "TEST 3 - Vocabulaire quotidien : ${COV3}%"
|
||||
echo "TEST 4 - Pronoms et verbes : ${COV4}%"
|
||||
echo "TEST 5 - Adjectifs courants : ${COV5}%"
|
||||
echo "TEST 6 - Nombres : ${COV6}%"
|
||||
echo ""
|
||||
|
||||
# Calculate average
|
||||
AVG=$(( (COV1 + COV2 + COV3 + COV4 + COV5 + COV6) / 6 ))
|
||||
echo "COVERAGE MOYEN : ${AVG}%"
|
||||
echo ""
|
||||
echo "==============================================="
|
||||
echo " MOTS MANQUANTS PAR TEST"
|
||||
echo "==============================================="
|
||||
echo ""
|
||||
echo "TEST 1 (${COV1}%):"
|
||||
echo " $MISS1"
|
||||
echo ""
|
||||
echo "TEST 2 (${COV2}%):"
|
||||
echo " $MISS2"
|
||||
echo ""
|
||||
echo "TEST 3 (${COV3}%):"
|
||||
echo " $MISS3"
|
||||
echo ""
|
||||
echo "TEST 4 (${COV4}%):"
|
||||
echo " $MISS4"
|
||||
echo ""
|
||||
echo "TEST 5 (${COV5}%):"
|
||||
echo " $MISS5"
|
||||
echo ""
|
||||
echo "TEST 6 (${COV6}%):"
|
||||
echo " $MISS6"
|
||||
echo ""
|
||||
echo "==============================================="
|
||||
echo ""
|
||||
echo "Serveur toujours actif sur http://localhost:3000 (PID: $SERVER_PID)"
|
||||
echo "Pour arrêter: kill $SERVER_PID"
|
||||
echo ""
|
||||
42
ConfluentTranslator/test-cultural-text.js
Normal file
42
ConfluentTranslator/test-cultural-text.js
Normal file
@ -0,0 +1,42 @@
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const { analyzeContext } = require('./contextAnalyzer');
|
||||
const path = require('path');
|
||||
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== TEST TEXTE CULTUREL ===\n');
|
||||
|
||||
const texteTest = `
|
||||
La civilisation de la Confluence est fondée sur l'observation et la mémoire.
|
||||
Notre culture valorise la liberté du regard et la connaissance transmise par les ancêtres.
|
||||
Les Siliaska, peuple du regard libre, préservent la sagesse de la tradition.
|
||||
L'union fait notre force, et la confluence de nos savoirs nous guide.
|
||||
Nous observons le monde avec attention pour voir la vérité.
|
||||
`;
|
||||
|
||||
const result = analyzeContext(texteTest, lexiques.ancien);
|
||||
|
||||
console.log(`Texte: ${result.metadata.wordCount} mots\n`);
|
||||
console.log(`Couverture: ${result.metadata.coveragePercent}%`);
|
||||
console.log(`Trouvés: ${result.metadata.wordsFound.length} / Manquants: ${result.metadata.wordsNotFound.length}\n`);
|
||||
|
||||
console.log('=== CONCEPTS TROUVÉS ===\n');
|
||||
const concepts = ['civilisation', 'confluence', 'observation', 'memoire', 'culture',
|
||||
'liberte', 'regard', 'connaissance', 'ancetres', 'peuple',
|
||||
'sagesse', 'tradition', 'union', 'savoir', 'observer', 'voir'];
|
||||
|
||||
result.metadata.wordsFound.forEach(w => {
|
||||
if (concepts.some(c => w.input.includes(c) || w.found.includes(c))) {
|
||||
console.log(`✅ "${w.input}" → ${w.confluent} (${w.type})`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n=== MOTS MANQUANTS ===');
|
||||
if (result.metadata.wordsNotFound.length > 0) {
|
||||
console.log(result.metadata.wordsNotFound.join(', '));
|
||||
} else {
|
||||
console.log('Aucun !');
|
||||
}
|
||||
|
||||
console.log(`\n📊 Taux de couverture final: ${result.metadata.coveragePercent}%`);
|
||||
34
ConfluentTranslator/test-find-roots.js
Normal file
34
ConfluentTranslator/test-find-roots.js
Normal file
@ -0,0 +1,34 @@
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const path = require('path');
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== RECHERCHE RACINES POUR COMPOSITIONS ===\n');
|
||||
|
||||
// Rechercher les racines nécessaires
|
||||
const recherches = [
|
||||
'manger', 'nourriture', 'eau', 'boire', 'pierre', 'lumiere', 'abri',
|
||||
'monter', 'ouvrir', 'ouverture', 'place', 'plante', 'aromate',
|
||||
'gouffre', 'humide'
|
||||
];
|
||||
|
||||
recherches.forEach(mot => {
|
||||
const found = lexiques.ancien.dictionnaire[mot];
|
||||
if (found && found.traductions) {
|
||||
console.log(`✅ ${mot}: ${found.traductions[0].confluent} (${found.traductions[0].type})`);
|
||||
} else {
|
||||
console.log(`❌ ${mot}: NON TROUVÉ`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n=== VÉRIFIER EXISTANTS ===\n');
|
||||
const aVerifier = ['manque', 'boire', 'fruit', 'legume', 'aromate', 'table', 'lumiere', 'fenetre', 'toit', 'mur', 'escalier'];
|
||||
|
||||
aVerifier.forEach(mot => {
|
||||
const found = lexiques.ancien.dictionnaire[mot];
|
||||
if (found && found.traductions) {
|
||||
console.log(`⚠️ ${mot} EXISTE DÉJÀ: ${found.traductions[0].confluent}`);
|
||||
} else {
|
||||
console.log(`✅ ${mot}: À CRÉER`);
|
||||
}
|
||||
});
|
||||
28
ConfluentTranslator/test-lemma-new.js
Normal file
28
ConfluentTranslator/test-lemma-new.js
Normal file
@ -0,0 +1,28 @@
|
||||
const { simpleLemmatize } = require('./contextAnalyzer');
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const path = require('path');
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== TEST LEMMATISATION NOUVEAUX MOTS ===\n');
|
||||
|
||||
const tests = ['fruits', 'légumes', 'aromates', 'monte', 'ouvrons', 'murs', 'toits'];
|
||||
|
||||
tests.forEach(mot => {
|
||||
const lemmas = simpleLemmatize(mot);
|
||||
console.log(`${mot} → lemmes: [${lemmas.join(', ')}]`);
|
||||
|
||||
let found = false;
|
||||
for (const lemma of lemmas) {
|
||||
const entry = lexiques.ancien.dictionnaire[lemma];
|
||||
if (entry?.traductions) {
|
||||
console.log(` ✅ trouvé: ${lemma} → ${entry.traductions[0].confluent}`);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
console.log(' ❌ NON TROUVÉ');
|
||||
}
|
||||
console.log('');
|
||||
});
|
||||
109
ConfluentTranslator/test-llm-refinement.bat
Normal file
109
ConfluentTranslator/test-llm-refinement.bat
Normal file
@ -0,0 +1,109 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo ===============================================
|
||||
echo CONFLUENT LLM REFINEMENT TEST
|
||||
echo (CF to FR with AI improvement)
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Kill any existing server on port 3000
|
||||
echo [1/3] Arret du serveur existant...
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :3000') do (
|
||||
taskkill //F //PID %%a >nul 2>&1
|
||||
)
|
||||
timeout /t 2 /nobreak >nul
|
||||
|
||||
REM Start server in background
|
||||
echo [2/3] Demarrage du serveur...
|
||||
cd /d "%~dp0"
|
||||
start /B cmd /c "npm start >nul 2>&1"
|
||||
timeout /t 5 /nobreak >nul
|
||||
|
||||
REM Check if server is running
|
||||
curl -s http://localhost:3000/api/stats >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo [ERREUR] Le serveur n'a pas demarre correctement
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [3/3] Test de traduction avec LLM refinement...
|
||||
echo.
|
||||
|
||||
REM Create temp file
|
||||
set TEMP_FILE=%TEMP%\llm_refinement.json
|
||||
|
||||
REM ===============================================
|
||||
REM TEXTE ORIGINAL EN FRANCAIS (reference):
|
||||
REM "Les enfants des echos observent la confluence.
|
||||
REM Ils ecoutent les murmures du passe et transmettent la memoire aux nouvelles generations.
|
||||
REM Les faucons chasseurs protegent les frontieres tandis que les ailes-grises volent dans le ciel sombre.
|
||||
REM La civilisation repose sur l'observation, la transmission et l'union des castes.
|
||||
REM Nous devons comprendre et aimer notre peuple pour preserver la liberte et la verite."
|
||||
REM ===============================================
|
||||
|
||||
REM Texte en Confluent a traduire
|
||||
set "CF_TEXT=Va Nakukeko vo uraakota mirak u. Va tanisu vo temak vosak tikam u se vo memu no noviuaita kisun u. Va Akoazana vo bosa zakis u ta va Aliaska no kumu zeru aliuk u. Va uraikota no silimira se kisunuaita se kotauneki kota tokas u. Va mikisu vo na siliaska sekam ul se koris ul se vo aska se veri nekas u."
|
||||
|
||||
echo ===============================================
|
||||
echo TEXTE CONFLUENT A TRADUIRE:
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo %CF_TEXT%
|
||||
echo.
|
||||
echo ===============================================
|
||||
|
||||
REM Call the LLM refinement API
|
||||
echo.
|
||||
echo Appel de l'API avec LLM (cela peut prendre quelques secondes)...
|
||||
echo.
|
||||
|
||||
curl -s -X POST http://localhost:3000/api/translate/conf2fr/llm ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"text\": \"%CF_TEXT%\", \"provider\": \"anthropic\", \"model\": \"claude-sonnet-4-20250514\"}" > "%TEMP_FILE%"
|
||||
|
||||
REM Check if the request succeeded
|
||||
if errorlevel 1 (
|
||||
echo [ERREUR] La requete API a echoue
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ===============================================
|
||||
echo RESULTAT DE LA TRADUCTION:
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Parse and display the results
|
||||
python -c "import json, sys; data=json.load(open(r'%TEMP_FILE%', encoding='utf-8')); print('=== TRADUCTION BRUTE (mot-a-mot) ==='); print(data.get('rawTranslation', 'N/A')[:500] + '...'); print(); print('=== TRADUCTION RAFFINEE (LLM) ==='); print(data.get('refinedTranslation', 'N/A')); print(); print('PROVIDER:', data.get('provider', 'N/A')); print('MODEL:', data.get('model', 'N/A')); print('MOTS TRADUITS:', data.get('wordsTranslated', 0)); print('MOTS NON TRADUITS:', data.get('wordsNotTranslated', 0))" 2>nul
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [Parsage JSON echoue - affichage brut]
|
||||
type "%TEMP_FILE%"
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo COMPARAISON AVEC L'ORIGINAL:
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo ORIGINAL FR:
|
||||
echo "Les enfants des echos observent la confluence.
|
||||
echo Ils ecoutent les murmures du passe et transmettent
|
||||
echo la memoire aux nouvelles generations. Les faucons
|
||||
echo chasseurs protegent les frontieres tandis que les
|
||||
echo ailes-grises volent dans le ciel sombre. La
|
||||
echo civilisation repose sur l'observation, la transmission
|
||||
echo et l'union des castes. Nous devons comprendre et aimer
|
||||
echo notre peuple pour preserver la liberte et la verite."
|
||||
echo.
|
||||
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo Serveur toujours actif sur http://localhost:3000
|
||||
echo Pour arreter: taskkill //F //PID [PID du node.exe]
|
||||
echo.
|
||||
|
||||
REM Clean up temp file
|
||||
del "%TEMP_FILE%" >nul 2>&1
|
||||
|
||||
endlocal
|
||||
@ -1,32 +1,55 @@
|
||||
/**
|
||||
* Test de couverture lexicale sur textes longs
|
||||
* UTILISE LES FONCTIONS CENTRALISÉES de contextAnalyzer.js
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { normalizeFrenchText, tokenizeFrench, simpleLemmatize } = require('./contextAnalyzer');
|
||||
|
||||
// Load all lexicon files
|
||||
const lexiqueDir = path.join(__dirname, '../ancien-confluent/lexique');
|
||||
const lexiqueFiles = fs.readdirSync(lexiqueDir).filter(f => f.endsWith('.json'));
|
||||
const lexiqueFiles = fs.readdirSync(lexiqueDir).filter(f => f.endsWith('.json') && !f.startsWith('_'));
|
||||
|
||||
const fullLexique = new Map();
|
||||
|
||||
// Helper to normalize text (lowercase + strip accents)
|
||||
function normalize(text) {
|
||||
return text.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
}
|
||||
|
||||
lexiqueFiles.forEach(file => {
|
||||
const content = JSON.parse(fs.readFileSync(path.join(lexiqueDir, file), 'utf8'));
|
||||
if (content.dictionnaire) {
|
||||
Object.entries(content.dictionnaire).forEach(([key, value]) => {
|
||||
// Add both original and normalized versions
|
||||
fullLexique.set(key.toLowerCase(), value);
|
||||
fullLexique.set(normalize(key), value);
|
||||
try {
|
||||
const content = JSON.parse(fs.readFileSync(path.join(lexiqueDir, file), 'utf8'));
|
||||
|
||||
if (value.synonymes_fr) {
|
||||
value.synonymes_fr.forEach(syn => {
|
||||
fullLexique.set(syn.toLowerCase(), value);
|
||||
fullLexique.set(normalize(syn), value);
|
||||
});
|
||||
}
|
||||
});
|
||||
// Charger le dictionnaire principal
|
||||
if (content.dictionnaire) {
|
||||
Object.entries(content.dictionnaire).forEach(([key, value]) => {
|
||||
// Normaliser la clé avec la fonction centrale
|
||||
const normalizedKey = normalizeFrenchText(key).trim();
|
||||
fullLexique.set(normalizedKey, value);
|
||||
|
||||
// Ajouter aussi les synonymes
|
||||
if (value.synonymes_fr) {
|
||||
value.synonymes_fr.forEach(syn => {
|
||||
const normalizedSyn = normalizeFrenchText(syn).trim();
|
||||
fullLexique.set(normalizedSyn, value);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Charger aussi la section "pronoms" si elle existe
|
||||
if (content.pronoms) {
|
||||
Object.entries(content.pronoms).forEach(([key, value]) => {
|
||||
const normalizedKey = normalizeFrenchText(key).trim();
|
||||
fullLexique.set(normalizedKey, value);
|
||||
|
||||
if (value.synonymes_fr) {
|
||||
value.synonymes_fr.forEach(syn => {
|
||||
const normalizedSyn = normalizeFrenchText(syn).trim();
|
||||
fullLexique.set(normalizedSyn, value);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Erreur chargement ${file}:`, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@ -53,35 +76,35 @@ const longTexts = [
|
||||
console.log('\n=== LONG TEXT COVERAGE TEST ===\n');
|
||||
console.log(`Lexique size: ${fullLexique.size} entries\n`);
|
||||
|
||||
// Common French articles and prepositions to ignore in coverage
|
||||
const stopWords = new Set(['le', 'la', 'les', 'un', 'une', 'des', 'du', 'de', 'au', 'aux', 'a', 'l', 'd', 'c', 's', 'n', 't', 'qu', 'j', 'm']);
|
||||
|
||||
let globalFound = 0;
|
||||
let globalTotal = 0;
|
||||
const allMissing = new Set();
|
||||
|
||||
longTexts.forEach(({ title, text }) => {
|
||||
const words = text.toLowerCase()
|
||||
.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/['']/g, ' ')
|
||||
.split(/[\s,;:.!?()«»""-]+/)
|
||||
.filter(w => w.length > 0);
|
||||
|
||||
// Filter out stopwords before checking
|
||||
const contentWords = words.filter(w => !stopWords.has(w));
|
||||
// UTILISER LA FONCTION CENTRALE tokenizeFrench()
|
||||
const words = tokenizeFrench(text);
|
||||
|
||||
const found = [];
|
||||
const missing = [];
|
||||
|
||||
contentWords.forEach(word => {
|
||||
words.forEach(word => {
|
||||
// Chercher le mot directement
|
||||
if (fullLexique.has(word)) {
|
||||
found.push(word);
|
||||
} else {
|
||||
// Try lemmatization for -ment adverbs
|
||||
const withoutMent = word.replace(/ment$/, '');
|
||||
if (fullLexique.has(withoutMent)) {
|
||||
found.push(word);
|
||||
} else {
|
||||
// Essayer avec la lemmatisation
|
||||
const lemmas = simpleLemmatize(word);
|
||||
let foundViaLemma = false;
|
||||
|
||||
for (const lemma of lemmas) {
|
||||
if (fullLexique.has(lemma)) {
|
||||
found.push(word);
|
||||
foundViaLemma = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundViaLemma) {
|
||||
missing.push(word);
|
||||
allMissing.add(word);
|
||||
}
|
||||
@ -89,12 +112,12 @@ longTexts.forEach(({ title, text }) => {
|
||||
});
|
||||
|
||||
globalFound += found.length;
|
||||
globalTotal += contentWords.length;
|
||||
globalTotal += words.length;
|
||||
|
||||
const coverage = contentWords.length > 0 ? ((found.length / contentWords.length) * 100).toFixed(1) : 100;
|
||||
const coverage = words.length > 0 ? ((found.length / words.length) * 100).toFixed(1) : 100;
|
||||
const status = parseFloat(coverage) >= 95 ? '✅' : parseFloat(coverage) >= 70 ? '⚠️' : '❌';
|
||||
|
||||
console.log(`${status} ${coverage}% - ${title} (${found.length}/${contentWords.length} mots)`);
|
||||
console.log(`${status} ${coverage}% - ${title} (${found.length}/${words.length} mots)`);
|
||||
if (missing.length > 0) {
|
||||
const uniqueMissing = [...new Set(missing)];
|
||||
console.log(` Manquants (${uniqueMissing.length}): ${uniqueMissing.slice(0, 10).join(', ')}${uniqueMissing.length > 10 ? '...' : ''}`);
|
||||
@ -110,11 +133,7 @@ console.log(`\n🔍 MOTS MANQUANTS UNIQUES: ${allMissing.size}\n`);
|
||||
// Count frequency of missing words
|
||||
const missingFrequency = new Map();
|
||||
longTexts.forEach(({ text }) => {
|
||||
const words = text.toLowerCase()
|
||||
.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/['']/g, ' ')
|
||||
.split(/[\s,;:.!?()«»""-]+/)
|
||||
.filter(w => w.length > 0 && !stopWords.has(w));
|
||||
const words = tokenizeFrench(text);
|
||||
|
||||
words.forEach(word => {
|
||||
if (allMissing.has(word)) {
|
||||
|
||||
37
ConfluentTranslator/test-new-vocabulary.js
Normal file
37
ConfluentTranslator/test-new-vocabulary.js
Normal file
@ -0,0 +1,37 @@
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const { analyzeContext } = require('./contextAnalyzer');
|
||||
const path = require('path');
|
||||
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== TEST NOUVEAU VOCABULAIRE ===\n');
|
||||
|
||||
const texteTest = `
|
||||
Les enfants montent l'escalier de pierre pour boire de l'eau fraîche.
|
||||
Sur la table, il y a des fruits, des légumes et des aromates.
|
||||
La lumière entre par la fenêtre et éclaire les murs.
|
||||
Le toit protège la maison de la pluie.
|
||||
Quand il manque de nourriture, nous ouvrons les réserves.
|
||||
`;
|
||||
|
||||
const result = analyzeContext(texteTest, lexiques.ancien);
|
||||
|
||||
console.log(`Texte analysé: ${result.metadata.wordCount} mots\n`);
|
||||
console.log(`Couverture: ${result.metadata.coveragePercent}%`);
|
||||
console.log(`Trouvés: ${result.metadata.wordsFound.length} / Manquants: ${result.metadata.wordsNotFound.length}\n`);
|
||||
|
||||
console.log('=== MOTS TROUVÉS (nouveaux) ===\n');
|
||||
const nouveaux = ['boire', 'fruit', 'legume', 'aromate', 'table', 'fenetre', 'toit', 'mur', 'escalier', 'manque', 'monter', 'ouvrir'];
|
||||
result.metadata.wordsFound.forEach(w => {
|
||||
if (nouveaux.includes(w.input) || nouveaux.includes(w.found)) {
|
||||
console.log(`✅ "${w.input}" → ${w.confluent} (${w.type})`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n=== MOTS MANQUANTS ===\n');
|
||||
if (result.metadata.wordsNotFound.length > 0) {
|
||||
console.log(result.metadata.wordsNotFound.slice(0, 10).join(', '));
|
||||
} else {
|
||||
console.log('Aucun !');
|
||||
}
|
||||
55
ConfluentTranslator/test-pronoun-system.js
Normal file
55
ConfluentTranslator/test-pronoun-system.js
Normal file
@ -0,0 +1,55 @@
|
||||
const { tokenizeFrench, simpleLemmatize } = require('./contextAnalyzer');
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const path = require('path');
|
||||
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== TEST SYSTÈME DE PRONOMS ===\n');
|
||||
|
||||
const tests = [
|
||||
'je parle',
|
||||
'tu parles',
|
||||
'il parle',
|
||||
'elle parle',
|
||||
'nous parlons',
|
||||
'vous parlez',
|
||||
'ils parlent',
|
||||
'elles parlent'
|
||||
];
|
||||
|
||||
tests.forEach(phrase => {
|
||||
const tokens = tokenizeFrench(phrase);
|
||||
console.log(`"${phrase}" → tokens: [${tokens.join(', ')}]`);
|
||||
|
||||
tokens.forEach(token => {
|
||||
const lemmas = simpleLemmatize(token);
|
||||
const found = lexiques.ancien.dictionnaire[token];
|
||||
|
||||
if (found) {
|
||||
const conf = found.traductions[0]?.confluent || '?';
|
||||
console.log(` ✅ "${token}" → ${conf}`);
|
||||
} else {
|
||||
// Vérifier les lemmes
|
||||
let foundLemma = false;
|
||||
for (const lemma of lemmas) {
|
||||
const entry = lexiques.ancien.dictionnaire[lemma];
|
||||
if (entry) {
|
||||
const conf = entry.traductions[0]?.confluent || '?';
|
||||
console.log(` ✅ "${token}" (lemme: "${lemma}") → ${conf}`);
|
||||
foundLemma = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundLemma) {
|
||||
console.log(` ❌ "${token}" → NON TROUVÉ`);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('');
|
||||
});
|
||||
|
||||
console.log('\n=== CONSTRUCTION PRONOMS PLURIELS ===\n');
|
||||
console.log('nous = miki (je) + su (pluriel) = mikisu');
|
||||
console.log('vous = sinu (tu) + su (pluriel) = sinusu');
|
||||
console.log('ils/elles = tani (il/elle) + su (pluriel) = tanisu');
|
||||
51
ConfluentTranslator/test-pronouns.js
Normal file
51
ConfluentTranslator/test-pronouns.js
Normal file
@ -0,0 +1,51 @@
|
||||
const { loadAllLexiques } = require('./lexiqueLoader');
|
||||
const path = require('path');
|
||||
|
||||
const baseDir = path.join(__dirname, '..');
|
||||
const lexiques = loadAllLexiques(baseDir);
|
||||
|
||||
console.log('\n=== RECHERCHE PRONOMS PERSONNELS ===\n');
|
||||
|
||||
const pronouns = ['je', 'tu', 'il', 'elle', 'nous', 'vous', 'ils', 'elles', 'on'];
|
||||
|
||||
pronouns.forEach(pronoun => {
|
||||
const found = [];
|
||||
|
||||
for (const [key, entry] of Object.entries(lexiques.ancien.dictionnaire)) {
|
||||
if (key.toLowerCase() === pronoun || entry.mot_francais?.toLowerCase() === pronoun) {
|
||||
found.push({
|
||||
key,
|
||||
mot: entry.mot_francais,
|
||||
traductions: entry.traductions
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (found.length > 0) {
|
||||
console.log(`✅ ${pronoun}:`);
|
||||
found.forEach(f => {
|
||||
console.log(` - ${f.traductions?.map(t => t.confluent).join(', ') || 'N/A'}`);
|
||||
console.log(` Type: ${f.traductions?.map(t => t.type).join(', ') || 'N/A'}`);
|
||||
});
|
||||
} else {
|
||||
console.log(`❌ ${pronoun}: NON TROUVÉ`);
|
||||
}
|
||||
console.log('');
|
||||
});
|
||||
|
||||
console.log('\n=== RECHERCHE TOUS LES MOTS CONTENANT "tanu" ou "tasu" ===\n');
|
||||
|
||||
for (const [key, entry] of Object.entries(lexiques.ancien.dictionnaire)) {
|
||||
const hasTarget = entry.traductions?.some(t =>
|
||||
t.confluent?.includes('tanu') || t.confluent?.includes('tasu')
|
||||
);
|
||||
|
||||
if (hasTarget) {
|
||||
console.log(`"${entry.mot_francais || key}":`);
|
||||
entry.traductions.forEach(t => {
|
||||
if (t.confluent?.includes('tanu') || t.confluent?.includes('tasu')) {
|
||||
console.log(` → ${t.confluent} (${t.type})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
106
ConfluentTranslator/test-reverse.bat
Normal file
106
ConfluentTranslator/test-reverse.bat
Normal file
@ -0,0 +1,106 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo ===============================================
|
||||
echo CONFLUENT REVERSE TRANSLATION TEST
|
||||
echo (Confluent to French)
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Kill any existing server on port 3000
|
||||
echo [1/3] Arret du serveur existant...
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :3000') do (
|
||||
taskkill //F //PID %%a >nul 2>&1
|
||||
)
|
||||
timeout /t 2 /nobreak >nul
|
||||
|
||||
REM Start server in background
|
||||
echo [2/3] Demarrage du serveur...
|
||||
cd /d "%~dp0"
|
||||
start /B cmd /c "npm start >nul 2>&1"
|
||||
timeout /t 5 /nobreak >nul
|
||||
|
||||
REM Check if server is running
|
||||
curl -s http://localhost:3000/api/stats >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo [ERREUR] Le serveur n'a pas demarre correctement
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [3/3] Test de traduction Confluent to Francais...
|
||||
echo.
|
||||
|
||||
REM Create temp file
|
||||
set TEMP_FILE=%TEMP%\reverse_translation.json
|
||||
|
||||
REM ===============================================
|
||||
REM TEXTE ORIGINAL EN FRANCAIS (reference):
|
||||
REM "Les enfants des echos observent la confluence.
|
||||
REM Ils ecoutent les murmures du passe et transmettent la memoire aux nouvelles generations.
|
||||
REM Les faucons chasseurs protegent les frontieres tandis que les ailes-grises volent dans le ciel sombre.
|
||||
REM La civilisation repose sur l'observation, la transmission et l'union des castes.
|
||||
REM Nous devons comprendre et aimer notre peuple pour preserver la liberte et la verite."
|
||||
REM ===============================================
|
||||
|
||||
REM Texte en Confluent a traduire
|
||||
set "CF_TEXT=Va Nakukeko vo uraakota mirak u. Va tanisu vo temak vosak tikam u se vo memu no noviuaita kisun u. Va Akoazana vo bosa zakis u ta va Aliaska no kumu zeru aliuk u. Va uraikota no silimira se kisunuaita se kotauneki kota tokas u. Va mikisu vo na siliaska sekam ul se koris ul se vo aska se veri nekas u."
|
||||
|
||||
echo ===============================================
|
||||
echo TEXTE CONFLUENT A TRADUIRE:
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo %CF_TEXT%
|
||||
echo.
|
||||
echo ===============================================
|
||||
|
||||
REM Call the Confluent to French translation API
|
||||
curl -s -X POST http://localhost:3000/api/translate/conf2fr ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"text\": \"%CF_TEXT%\"}" > "%TEMP_FILE%"
|
||||
|
||||
REM Check if the request succeeded
|
||||
if errorlevel 1 (
|
||||
echo [ERREUR] La requete API a echoue
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo RESULTAT DE LA TRADUCTION:
|
||||
echo ===============================================
|
||||
echo.
|
||||
|
||||
REM Parse and display the translation
|
||||
python -c "import json, sys; data=json.load(open(r'%TEMP_FILE%', encoding='utf-8')); print('TRADUCTION FRANCAISE:'); print('-' * 47); print(data.get('translation', 'N/A')); print(); print('CONFIANCE:', str(data.get('confidence', 0)) + '%%'); print('MOTS TRADUITS:', data.get('wordsTranslated', 0)); print('MOTS NON TRADUITS:', data.get('wordsNotTranslated', 0))" 2>nul
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [Parsage JSON echoue - affichage brut]
|
||||
type "%TEMP_FILE%"
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ===============================================
|
||||
echo COMPARAISON AVEC L'ORIGINAL:
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo ORIGINAL FR:
|
||||
echo "Les enfants des echos observent la confluence.
|
||||
echo Ils ecoutent les murmures du passe et transmettent
|
||||
echo la memoire aux nouvelles generations. Les faucons
|
||||
echo chasseurs protegent les frontieres tandis que les
|
||||
echo ailes-grises volent dans le ciel sombre. La
|
||||
echo civilisation repose sur l'observation, la transmission
|
||||
echo et l'union des castes. Nous devons comprendre et aimer
|
||||
echo notre peuple pour preserver la liberte et la verite."
|
||||
echo.
|
||||
|
||||
echo ===============================================
|
||||
echo.
|
||||
echo Serveur toujours actif sur http://localhost:3000
|
||||
echo Pour arreter: taskkill //F //PID [PID du node.exe]
|
||||
echo.
|
||||
|
||||
REM Clean up temp file
|
||||
del "%TEMP_FILE%" >nul 2>&1
|
||||
|
||||
endlocal
|
||||
@ -426,29 +426,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ils": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tasu",
|
||||
"type": "pronom",
|
||||
"categorie": "personnel",
|
||||
"note": "Pronom 3ème personne pluriel"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"elles"
|
||||
]
|
||||
},
|
||||
"nous": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tanu",
|
||||
"type": "pronom",
|
||||
"categorie": "personnel",
|
||||
"note": "Pronom 1ère personne pluriel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sa": {
|
||||
"traductions": [
|
||||
{
|
||||
@ -533,6 +510,22 @@
|
||||
"proche",
|
||||
"alentour"
|
||||
]
|
||||
},
|
||||
"tandis": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "ta",
|
||||
"type": "particule",
|
||||
"categorie": "temporel",
|
||||
"note": "Tandis que, pendant que - conjonction temporelle de simultanéité"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"tandis que",
|
||||
"pendant",
|
||||
"pendant que",
|
||||
"alors que"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,6 +618,106 @@
|
||||
"note": "Nouvelle racine - ce qui est caché"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bas": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "baso",
|
||||
"type": "racine",
|
||||
"forme_liee": "bas",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Bas, inférieur (opposé de haut)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"basse",
|
||||
"basses"
|
||||
]
|
||||
},
|
||||
"long": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "lono",
|
||||
"type": "racine",
|
||||
"forme_liee": "lon",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Long, étendu (opposé de court)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"longue",
|
||||
"longs",
|
||||
"longues"
|
||||
]
|
||||
},
|
||||
"chaud": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "suka",
|
||||
"type": "racine",
|
||||
"forme_liee": "suk",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Chaud, chaleureux (lié à feu)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"chaude",
|
||||
"chauds",
|
||||
"chaudes",
|
||||
"chaleur"
|
||||
]
|
||||
},
|
||||
"froid": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "kiso",
|
||||
"type": "racine",
|
||||
"forme_liee": "kis",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Froid, frais, glacé"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"froide",
|
||||
"froids",
|
||||
"froides",
|
||||
"frais",
|
||||
"fraîche"
|
||||
]
|
||||
},
|
||||
"mauvais": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "daku",
|
||||
"type": "racine",
|
||||
"forme_liee": "dak",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Mauvais, négatif (opposé de bon)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"mauvaise",
|
||||
"mauvaises",
|
||||
"mal"
|
||||
]
|
||||
},
|
||||
"clair": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "sora",
|
||||
"type": "racine",
|
||||
"forme_liee": "sor",
|
||||
"domaine": "qualificatif",
|
||||
"note": "Clair, lumineux (lié à lumière)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"claire",
|
||||
"clairs",
|
||||
"claires",
|
||||
"lumineux",
|
||||
"lumineuse"
|
||||
]
|
||||
}
|
||||
},
|
||||
"pronoms": {
|
||||
@ -663,6 +763,45 @@
|
||||
"elle",
|
||||
"iel"
|
||||
]
|
||||
},
|
||||
"nous": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "mikisu",
|
||||
"type": "pronom",
|
||||
"composition": "miki-su",
|
||||
"racines": ["miki", "su"],
|
||||
"personne": "1pl",
|
||||
"note": "Première personne pluriel - miki (je) + su (pluriel)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vous": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "sinusu",
|
||||
"type": "pronom",
|
||||
"composition": "sinu-su",
|
||||
"racines": ["sinu", "su"],
|
||||
"personne": "2pl",
|
||||
"note": "Deuxième personne pluriel - sinu (tu) + su (pluriel)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ils": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tanisu",
|
||||
"type": "pronom",
|
||||
"composition": "tani-su",
|
||||
"racines": ["tani", "su"],
|
||||
"personne": "3pl",
|
||||
"note": "Troisième personne pluriel - tani (il/elle) + su (pluriel)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"elles"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -240,7 +240,14 @@
|
||||
"synonymes_fr": [
|
||||
"parler",
|
||||
"dites",
|
||||
"dit"
|
||||
"dit",
|
||||
"murmurer",
|
||||
"murmure",
|
||||
"murmures",
|
||||
"murmurons",
|
||||
"murmurez",
|
||||
"murmurent",
|
||||
"chuchoter"
|
||||
]
|
||||
},
|
||||
"savoir": {
|
||||
@ -263,7 +270,12 @@
|
||||
"saches",
|
||||
"sachent",
|
||||
"sachions",
|
||||
"sachiez"
|
||||
"sachiez",
|
||||
"comprendre",
|
||||
"comprends",
|
||||
"comprenons",
|
||||
"comprenez",
|
||||
"comprennent"
|
||||
]
|
||||
},
|
||||
"apprendre": {
|
||||
@ -1052,6 +1064,123 @@
|
||||
"envolez",
|
||||
"envolent"
|
||||
]
|
||||
},
|
||||
"aimer": {
|
||||
"racine_fr": "aim",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "koris",
|
||||
"type": "verbe",
|
||||
"racine": "kori",
|
||||
"forme_liee": "kor",
|
||||
"structure": "CVCVC",
|
||||
"domaine": "action_emotion",
|
||||
"note": "Verbe d'amour (du cœur kori)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"aime",
|
||||
"aimes",
|
||||
"aimons",
|
||||
"aimez",
|
||||
"aiment",
|
||||
"aimais",
|
||||
"aimait",
|
||||
"aimions",
|
||||
"aimiez",
|
||||
"aimaient",
|
||||
"aimant",
|
||||
"aimé"
|
||||
]
|
||||
},
|
||||
"pouvoir": {
|
||||
"racine_fr": "pouv",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "polas",
|
||||
"type": "verbe",
|
||||
"racine": "pola",
|
||||
"forme_liee": "pol",
|
||||
"structure": "CVCVC",
|
||||
"domaine": "action_capacite",
|
||||
"note": "Avoir la capacité de"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"peux",
|
||||
"peut",
|
||||
"pouvons",
|
||||
"pouvez",
|
||||
"peuvent",
|
||||
"pouvais",
|
||||
"pouvait",
|
||||
"pouvions",
|
||||
"pouviez",
|
||||
"pouvaient",
|
||||
"pouvant",
|
||||
"pu"
|
||||
]
|
||||
},
|
||||
"devoir": {
|
||||
"racine_fr": "dev",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "nekas",
|
||||
"type": "verbe",
|
||||
"racine": "neka",
|
||||
"forme_liee": "nek",
|
||||
"structure": "CVCVC",
|
||||
"domaine": "action_obligation",
|
||||
"note": "Être obligé de, avoir l'obligation (lié à œuvre/tâche)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"dois",
|
||||
"doit",
|
||||
"devons",
|
||||
"devez",
|
||||
"doivent",
|
||||
"devais",
|
||||
"devait",
|
||||
"devions",
|
||||
"deviez",
|
||||
"devaient",
|
||||
"devant",
|
||||
"dû",
|
||||
"due",
|
||||
"dus",
|
||||
"dues"
|
||||
]
|
||||
},
|
||||
"reposer": {
|
||||
"racine_fr": "repos",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tokas",
|
||||
"type": "verbe",
|
||||
"racine": "toka",
|
||||
"forme_liee": "tok",
|
||||
"structure": "CVCVC",
|
||||
"domaine": "action_fondement",
|
||||
"note": "Reposer sur, être fondé sur (lié à toka=lieu/base)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"repose",
|
||||
"reposes",
|
||||
"reposons",
|
||||
"reposez",
|
||||
"reposent",
|
||||
"reposais",
|
||||
"reposait",
|
||||
"reposions",
|
||||
"reposiez",
|
||||
"reposaient",
|
||||
"reposant",
|
||||
"reposé",
|
||||
"être fondé",
|
||||
"se fonder"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -564,6 +564,108 @@
|
||||
"domaine": "conflit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"civilisation": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "uraikota",
|
||||
"type": "composition",
|
||||
"composition": "ura-i-kota",
|
||||
"sens_litteral": "Confluence-de-vie",
|
||||
"racines": ["ura", "kota"],
|
||||
"liaison": "i",
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Civilisation - l'union des gens qui vivent ensemble (ura=eau/vie + i=agentivité + kota=confluence/union)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"civilisations",
|
||||
"société"
|
||||
]
|
||||
},
|
||||
"observation": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "silimira",
|
||||
"type": "composition",
|
||||
"composition": "sili-mira",
|
||||
"sens_litteral": "Regard-observant",
|
||||
"racines": ["sili", "mirak"],
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Observation - acte de regarder avec attention (sili=regard + mirak=observer)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"observations",
|
||||
"contemplation"
|
||||
]
|
||||
},
|
||||
"culture": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "aitatoka",
|
||||
"type": "composition",
|
||||
"composition": "aita-toka",
|
||||
"sens_litteral": "Lieux-des-ancêtres",
|
||||
"racines": ["aita", "toka"],
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Culture - les lieux/traditions des ancêtres transmis (aita=ancêtres + toka=lieux)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"cultures",
|
||||
"patrimoine"
|
||||
]
|
||||
},
|
||||
"connaissance": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "sekamemu",
|
||||
"type": "composition",
|
||||
"composition": "seka-memu",
|
||||
"sens_litteral": "Savoir-en-mémoire",
|
||||
"racines": ["seka", "memu"],
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Connaissance - le savoir gardé en mémoire (seka=savoir + memu=mémoire)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"connaissances",
|
||||
"science",
|
||||
"érudition"
|
||||
]
|
||||
},
|
||||
"mémoire": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "memu",
|
||||
"type": "racine",
|
||||
"forme_liee": "mem",
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Mémoire - concept central de la civilisation (synonyme normalisé de memoire)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"memoire",
|
||||
"souvenir",
|
||||
"souvenirs"
|
||||
]
|
||||
},
|
||||
"liberté": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "aska",
|
||||
"type": "racine_sacree",
|
||||
"forme_liee": "ask",
|
||||
"domaine": "concept_fondateur",
|
||||
"note": "Liberté - racine sacrée centrale (synonyme normalisé de liberte)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"liberte",
|
||||
"libre",
|
||||
"affranchissement"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,16 +19,29 @@
|
||||
"generation": {
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "temiuaita",
|
||||
"confluent": "noviuaita",
|
||||
"type": "composition",
|
||||
"composition": "tem-i-aita",
|
||||
"sens_litteral": "Temps des ancêtres",
|
||||
"composition": "nov-i-u-aita",
|
||||
"sens_litteral": "Nouveaux (qui deviendront) ancêtres",
|
||||
"racines": [
|
||||
"temi",
|
||||
"nuvi",
|
||||
"aita"
|
||||
],
|
||||
"domaine": "temps"
|
||||
"liaison": "i-u",
|
||||
"structure": "composition",
|
||||
"domaine": "temps",
|
||||
"note": "Nouvelle génération - ceux qui porteront la mémoire (nov=nouveau + i=agentivité + u=appartenance + aita=ancêtres)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"génération",
|
||||
"generations",
|
||||
"générations",
|
||||
"nouvelle generation",
|
||||
"nouvelle génération",
|
||||
"nouvelles generations",
|
||||
"nouvelles générations",
|
||||
"descendants"
|
||||
]
|
||||
},
|
||||
"siecle": {
|
||||
|
||||
463
ancien-confluent/lexique/23-nourriture.json
Normal file
463
ancien-confluent/lexique/23-nourriture.json
Normal file
@ -0,0 +1,463 @@
|
||||
{
|
||||
"_comment": "Vocabulaire alimentaire et culinaire de la Confluence",
|
||||
"_source": "Basé sur civjdr/Background/2024-10-28-le-village.md",
|
||||
"dictionnaire": {
|
||||
"poisson": {
|
||||
"racine_fr": "poiss",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "pisu",
|
||||
"type": "racine",
|
||||
"forme_liee": "pis",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Poisson - source vitale de protéines (même racine que pêcher)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"poissons"
|
||||
]
|
||||
},
|
||||
"gibier": {
|
||||
"racine_fr": "gibier",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "zana",
|
||||
"type": "racine",
|
||||
"forme_liee": "zan",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Gibier chassé (lié à zanak-chasser)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"proie"
|
||||
]
|
||||
},
|
||||
"baie": {
|
||||
"racine_fr": "bai",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "beka",
|
||||
"type": "racine",
|
||||
"forme_liee": "bek",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Baies - fruits sauvages essentiels"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"baies",
|
||||
"petits fruits"
|
||||
]
|
||||
},
|
||||
"tubercule": {
|
||||
"racine_fr": "tubercul",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tuba",
|
||||
"type": "racine",
|
||||
"forme_liee": "tub",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Tubercules, racines comestibles"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"racine",
|
||||
"tubercules"
|
||||
]
|
||||
},
|
||||
"fruit": {
|
||||
"racine_fr": "fruit",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "veka",
|
||||
"type": "racine",
|
||||
"forme_liee": "vek",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Fruits génériques"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"fruits"
|
||||
]
|
||||
},
|
||||
"mollusque": {
|
||||
"racine_fr": "mollusqu",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "molu",
|
||||
"type": "racine",
|
||||
"forme_liee": "mol",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Mollusques, coquillages"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"coquillage",
|
||||
"mollusques"
|
||||
]
|
||||
},
|
||||
"graine": {
|
||||
"racine_fr": "grain",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "seka",
|
||||
"type": "racine",
|
||||
"forme_liee": "sek",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Graines comestibles"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"graines",
|
||||
"semence"
|
||||
]
|
||||
},
|
||||
"galette": {
|
||||
"racine_fr": "galet",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "panu",
|
||||
"type": "racine",
|
||||
"forme_liee": "pan",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Galette, pain plat"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"pain",
|
||||
"crêpe",
|
||||
"galettes"
|
||||
]
|
||||
},
|
||||
"herbe": {
|
||||
"racine_fr": "herb",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "pala",
|
||||
"type": "racine",
|
||||
"forme_liee": "pal",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Herbes aromatiques"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"herbes"
|
||||
]
|
||||
},
|
||||
"aromate": {
|
||||
"racine_fr": "aromat",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "palusuki",
|
||||
"type": "composition",
|
||||
"composition": "pal-u-suki",
|
||||
"sens_litteral": "Herbe du feu (qui brûle le goût)",
|
||||
"racines": ["pala", "suki"],
|
||||
"liaison": "u",
|
||||
"structure": "composition",
|
||||
"domaine": "nourriture",
|
||||
"note": "Aromate, épice - herbe qui réchauffe/brûle (piquant)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"aromates",
|
||||
"epice",
|
||||
"epices",
|
||||
"épice",
|
||||
"épices"
|
||||
]
|
||||
},
|
||||
"morsure-des-ancetres": {
|
||||
"racine_fr": null,
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "aiteopalu",
|
||||
"type": "composition",
|
||||
"composition": "ait-eo-palu",
|
||||
"sens_litteral": "Ancêtre-éternel-qui-brûle",
|
||||
"racines": ["aita", "palu"],
|
||||
"liaison": "eo",
|
||||
"structure": "composition_sacree",
|
||||
"domaine": "nourriture_sacree",
|
||||
"note": "Gingembre sauvage très estimé, épice sacrée - utilise liaison sacrée eo (totalité/éternel)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"gingembre sauvage",
|
||||
"epice sacree"
|
||||
]
|
||||
},
|
||||
"larmes-du-ciel": {
|
||||
"racine_fr": null,
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "zeruosi",
|
||||
"type": "composition",
|
||||
"composition": "zer-u-osi",
|
||||
"sens_litteral": "Ciel-de-mort (larmes célestes)",
|
||||
"racines": ["zeru", "osi"],
|
||||
"liaison": "u",
|
||||
"structure": "composition_sacree",
|
||||
"domaine": "nourriture_sacree",
|
||||
"note": "Plat cérémoniel traditionnel - poisson fumé, gibier, Morsure-des-Ancêtres, herbes et baies. Utilise liaison u (appartenance)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"plat ceremoniel",
|
||||
"plat traditionnel"
|
||||
]
|
||||
},
|
||||
"fumer": {
|
||||
"racine_fr": "fum",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "simus",
|
||||
"type": "verbe",
|
||||
"racine": "simu",
|
||||
"forme_liee": "sim",
|
||||
"structure": "CVCV",
|
||||
"domaine": "technique_culinaire",
|
||||
"note": "Fumer (aliment), technique de conservation"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"fume",
|
||||
"fumes",
|
||||
"fumons",
|
||||
"fumez",
|
||||
"fument",
|
||||
"fumais",
|
||||
"fumait",
|
||||
"fumions",
|
||||
"fumiez",
|
||||
"fumaient",
|
||||
"fumant",
|
||||
"fumé",
|
||||
"fumée"
|
||||
]
|
||||
},
|
||||
"secher": {
|
||||
"racine_fr": "séch",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "sekus",
|
||||
"type": "verbe",
|
||||
"racine": "seku",
|
||||
"forme_liee": "sek",
|
||||
"structure": "CVCV",
|
||||
"domaine": "technique_culinaire",
|
||||
"note": "Sécher (aliment), conservation"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"sécher",
|
||||
"sèche",
|
||||
"sèches",
|
||||
"séchons",
|
||||
"séchez",
|
||||
"sèchent",
|
||||
"séchais",
|
||||
"séchait",
|
||||
"séchions",
|
||||
"séchiez",
|
||||
"séchaient",
|
||||
"séchant",
|
||||
"séché",
|
||||
"sec",
|
||||
"sèche"
|
||||
]
|
||||
},
|
||||
"griller": {
|
||||
"racine_fr": "grill",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "palus",
|
||||
"type": "verbe",
|
||||
"racine": "palu",
|
||||
"forme_liee": "pal",
|
||||
"structure": "CVCV",
|
||||
"domaine": "technique_culinaire",
|
||||
"note": "Griller, cuire sur feu"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"grille",
|
||||
"grilles",
|
||||
"grillons",
|
||||
"grillez",
|
||||
"grillent",
|
||||
"grillais",
|
||||
"grillait",
|
||||
"grillions",
|
||||
"grilliez",
|
||||
"grillaient",
|
||||
"grillant",
|
||||
"grillé",
|
||||
"cuire",
|
||||
"rôtir"
|
||||
]
|
||||
},
|
||||
"cuisiner": {
|
||||
"racine_fr": "cuisin",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "mukunekas",
|
||||
"type": "composition",
|
||||
"composition": "muk-u-nekas",
|
||||
"sens_litteral": "Nourriture-de-faire",
|
||||
"racines": ["muki", "nekas"],
|
||||
"liaison": "u",
|
||||
"structure": "composition",
|
||||
"domaine": "technique_culinaire",
|
||||
"note": "Cuisiner, préparer (faire de la nourriture) - muki + liaison u + nekas"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"cuisine",
|
||||
"cuisines",
|
||||
"cuisinons",
|
||||
"cuisinez",
|
||||
"cuisinent",
|
||||
"cuisinais",
|
||||
"cuisinait",
|
||||
"cuisinions",
|
||||
"cuisiniez",
|
||||
"cuisinaient",
|
||||
"cuisinant",
|
||||
"cuisiné",
|
||||
"preparer la nourriture",
|
||||
"préparer la nourriture"
|
||||
]
|
||||
},
|
||||
"infuser": {
|
||||
"racine_fr": "infus",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "urapis",
|
||||
"type": "composition",
|
||||
"composition": "ura-pis",
|
||||
"sens_litteral": "Eau-tremper",
|
||||
"racines": ["ura", "pisu"],
|
||||
"structure": "composition",
|
||||
"domaine": "technique_culinaire",
|
||||
"note": "Infuser, faire tremper dans l'eau"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"infuse",
|
||||
"infusion",
|
||||
"tremper"
|
||||
]
|
||||
},
|
||||
"reserve": {
|
||||
"racine_fr": "réserv",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "zaku",
|
||||
"type": "racine",
|
||||
"forme_liee": "zak",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Réserves alimentaires (lié à garder/protéger)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"réserves",
|
||||
"provisions",
|
||||
"stock"
|
||||
]
|
||||
},
|
||||
"nourriture": {
|
||||
"racine_fr": "nourritur",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "muki",
|
||||
"type": "racine",
|
||||
"forme_liee": "muk",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Nourriture (racine de manger)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"aliment",
|
||||
"aliments",
|
||||
"repas"
|
||||
]
|
||||
},
|
||||
"boire": {
|
||||
"racine_fr": "boir",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "urapis",
|
||||
"type": "verbe",
|
||||
"racine": "ura",
|
||||
"forme_liee": "ura",
|
||||
"structure": "VCVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Boire - utilise racine sacrée ura (eau)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"bois",
|
||||
"boit",
|
||||
"buvons",
|
||||
"buvez",
|
||||
"boivent",
|
||||
"buvais",
|
||||
"buvait",
|
||||
"buvions",
|
||||
"buviez",
|
||||
"buvaient",
|
||||
"buvant",
|
||||
"bu"
|
||||
]
|
||||
},
|
||||
"legume": {
|
||||
"racine_fr": "légum",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "leva",
|
||||
"type": "racine",
|
||||
"forme_liee": "lev",
|
||||
"structure": "CVCV",
|
||||
"domaine": "nourriture",
|
||||
"note": "Légume, plante comestible cultivée"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"légume",
|
||||
"légumes",
|
||||
"plante comestible"
|
||||
]
|
||||
},
|
||||
"manque": {
|
||||
"racine_fr": "manqu",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "zomuki",
|
||||
"type": "composition",
|
||||
"composition": "zo-muki",
|
||||
"sens_litteral": "Négation-nourriture",
|
||||
"racines": ["zo", "muki"],
|
||||
"structure": "composition",
|
||||
"domaine": "nourriture",
|
||||
"note": "Manque (de nourriture) - zo (négation) + muki (nourriture)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"manquer",
|
||||
"absence",
|
||||
"pénurie"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
164
ancien-confluent/lexique/24-habitat.json
Normal file
164
ancien-confluent/lexique/24-habitat.json
Normal file
@ -0,0 +1,164 @@
|
||||
{
|
||||
"_comment": "Vocabulaire de l'habitat et de l'architecture",
|
||||
"_source": "Extension vocabulaire quotidien",
|
||||
"dictionnaire": {
|
||||
"table": {
|
||||
"racine_fr": "tabl",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "mukisloku",
|
||||
"type": "composition",
|
||||
"composition": "mukis-loku",
|
||||
"sens_litteral": "Lieu-de-manger",
|
||||
"racines": ["mukis", "loku"],
|
||||
"structure": "composition",
|
||||
"domaine": "habitat",
|
||||
"note": "Table - lieu où l'on mange (mukis=manger + loku=lieu)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"tables",
|
||||
"surface pour manger"
|
||||
]
|
||||
},
|
||||
"fenetre": {
|
||||
"racine_fr": "fenêtr",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "soratuva",
|
||||
"type": "composition",
|
||||
"composition": "sora-tuva",
|
||||
"sens_litteral": "Ouverture-de-lumière",
|
||||
"racines": ["sora", "tuva"],
|
||||
"structure": "composition",
|
||||
"domaine": "habitat",
|
||||
"note": "Fenêtre - ouverture qui laisse passer la lumière (sora=lumière + tuva=ouverture)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"fenêtre",
|
||||
"fenêtres",
|
||||
"ouverture"
|
||||
]
|
||||
},
|
||||
"toit": {
|
||||
"racine_fr": "toit",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "zakusumu",
|
||||
"type": "composition",
|
||||
"composition": "zaku-sumu",
|
||||
"sens_litteral": "Protection-haute",
|
||||
"racines": ["zaku", "sumu"],
|
||||
"structure": "composition",
|
||||
"domaine": "habitat",
|
||||
"note": "Toit - protection en hauteur (zaku=protection/réserve + sumu=haut)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"toits",
|
||||
"toiture",
|
||||
"abri"
|
||||
]
|
||||
},
|
||||
"mur": {
|
||||
"racine_fr": "mur",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "karisumu",
|
||||
"type": "composition",
|
||||
"composition": "kari-sumu",
|
||||
"sens_litteral": "Pierre-dressée",
|
||||
"racines": ["kari", "sumu"],
|
||||
"structure": "composition",
|
||||
"domaine": "habitat",
|
||||
"note": "Mur - pierre élevée (kari=pierre + sumu=haut/élevé)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"murs",
|
||||
"paroi",
|
||||
"cloison"
|
||||
]
|
||||
},
|
||||
"escalier": {
|
||||
"racine_fr": "escalier",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "vukukari",
|
||||
"type": "composition",
|
||||
"composition": "vuku-kari",
|
||||
"sens_litteral": "Gouffre-de-pierre",
|
||||
"racines": ["vuku", "kari"],
|
||||
"structure": "composition",
|
||||
"domaine": "habitat",
|
||||
"note": "Escalier - montée de pierre (référence au Gouffre Humide avec ses escaliers dans la roche, vuku=gouffre + kari=pierre)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"escaliers",
|
||||
"marches",
|
||||
"montée"
|
||||
]
|
||||
},
|
||||
"ouvrir": {
|
||||
"racine_fr": "ouvr",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "tuvas",
|
||||
"type": "verbe",
|
||||
"racine": "tuva",
|
||||
"forme_liee": "tuv",
|
||||
"structure": "CVCV",
|
||||
"domaine": "action",
|
||||
"note": "Ouvrir, créer une ouverture"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"ouvre",
|
||||
"ouvres",
|
||||
"ouvrons",
|
||||
"ouvrez",
|
||||
"ouvrent",
|
||||
"ouvrais",
|
||||
"ouvrait",
|
||||
"ouvrions",
|
||||
"ouvriez",
|
||||
"ouvraient",
|
||||
"ouvrant",
|
||||
"ouvert",
|
||||
"ouverture"
|
||||
]
|
||||
},
|
||||
"monter": {
|
||||
"racine_fr": "mont",
|
||||
"traductions": [
|
||||
{
|
||||
"confluent": "sumus",
|
||||
"type": "verbe",
|
||||
"racine": "sumu",
|
||||
"forme_liee": "sum",
|
||||
"structure": "CVCV",
|
||||
"domaine": "action",
|
||||
"note": "Monter, s'élever (même racine que haut)"
|
||||
}
|
||||
],
|
||||
"synonymes_fr": [
|
||||
"monte",
|
||||
"montes",
|
||||
"montons",
|
||||
"montez",
|
||||
"montent",
|
||||
"montais",
|
||||
"montait",
|
||||
"montions",
|
||||
"montiez",
|
||||
"montaient",
|
||||
"montant",
|
||||
"monté",
|
||||
"grimper",
|
||||
"élever"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user