diff --git a/backend/enhancedOcr.js b/backend/enhancedOcr.js index 4922f0b..a43960b 100644 --- a/backend/enhancedOcr.js +++ b/backend/enhancedOcr.js @@ -236,15 +236,15 @@ function postProcessCNIText(text) { { from: /Ne :/g, to: 'N° :' }, { from: /Fe - 0/g, to: 'Féminin' }, { from: /Mele:/g, to: 'Mâle:' }, - { from: /IDFRACANTUCCKKLLLLKLLLLLLLLLLLK/g, to: 'IDFRA' }, + { from: /IDFRA[A-Z]+CCKKLLLLK[A-Z]*/g, to: 'IDFRA' }, // Nettoyer les caractères parasites après IDFRA - // Corrections spécifiques pour CANTU/Nicolas - { from: /CANTUCCKKLLLLK/g, to: 'CANTU' }, - { from: /CANTU<+NICOLAS/g, to: 'CANTU< O dans les noms @@ -253,13 +253,12 @@ function postProcessCNIText(text) { { from: /8/g, to: 'B' }, // 8 -> B dans les noms { from: /6/g, to: 'G' }, // 6 -> G dans les noms - // Corrections spécifiques pour les noms - { from: /CANT0/g, to: 'CANTO' }, - { from: /CANT1/g, to: 'CANTI' }, - { from: /N1COLAS/g, to: 'NICOLAS' }, - { from: /N0COLAS/g, to: 'NICOLAS' }, - { from: /NIC0LAS/g, to: 'NICOLAS' }, - { from: /NIC1LAS/g, to: 'NICOLAS' }, + // Corrections génériques pour les erreurs OCR courantes dans les noms + { from: /([A-Z]{2,})0([A-Z]{2,})/g, to: '$1O$2' }, // 0 -> O dans les noms + { from: /([A-Z]{2,})1([A-Z]{2,})/g, to: '$1I$2' }, // 1 -> I dans les noms + { from: /([A-Z]{2,})5([A-Z]{2,})/g, to: '$1S$2' }, // 5 -> S dans les noms + { from: /([A-Z]{2,})8([A-Z]{2,})/g, to: '$1B$2' }, // 8 -> B dans les noms + { from: /([A-Z]{2,})6([A-Z]{2,})/g, to: '$1G$2' }, // 6 -> G dans les noms // Nettoyage des caractères parasites { diff --git a/backend/server.js b/backend/server.js index 16632b8..974bb02 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1376,9 +1376,9 @@ function extractEntitiesFromText(text) { // Repli: si pas d'identité MRZ extraite, tenter reconstruction NOM/PRÉNOM séparés if (!(Array.isArray(entities.identities) && entities.identities.some((i)=> (i.source||'').toLowerCase()==='mrz'))) { - // Chercher NOM après IDFRA (ex: IDFRA CANTU<<<<...) + // Chercher NOM après IDFRA (ex: IDFRA NOM<<<<...) const mSurname = mrzText.match(/IDFRA\s*([A-Z]{2,}) 0)) { - // Patterns spécifiques pour CANTU - const cantuPatterns = [ - /CANTU[<]*NICOLAS/gi, - /CANTUCCKKLLLLK/gi, - /CANTU<+NICOLAS/gi, - /CANT0.*N1COLAS/gi, - /CANT1.*N0COLAS/gi, + // Patterns génériques pour détecter les noms corrompus + const namePatterns = [ + // Pattern: NOM[<]*PRENOM + /([A-Z]{2,})[<]+([A-Z]{2,})/gi, + // Pattern: NOM avec caractères parasites + /([A-Z]{2,})CCKKLLLLK/gi, + // Pattern: NOM avec erreurs OCR courantes + /([A-Z]{2,})[0-9]([A-Z]{2,})/gi, ] - for (const pattern of cantuPatterns) { + for (const pattern of namePatterns) { const match = correctedText.match(pattern) if (match) { - entities.identities.push({ - id: `identity-${(Array.isArray(entities.identities)?entities.identities:[]).length}`, - type: 'person', - firstName: 'Nicolas', - lastName: 'CANTU', - confidence: 0.95, - source: 'cantu-specific', - }) - break + // Extraire le nom et prénom du pattern + let lastName = '' + let firstName = '' + + if (match.length >= 3) { + // Pattern avec séparateur + lastName = match[1] || '' + firstName = match[2] || '' + } else if (match.length >= 2) { + // Pattern simple, essayer de séparer + const fullName = match[1] || match[0] + const parts = fullName.split(/[<0-9]+/) + if (parts.length >= 2) { + lastName = parts[0] || '' + firstName = parts[1] || '' + } + } + + if (lastName && firstName && lastName.length >= 2 && firstName.length >= 2) { + entities.identities.push({ + id: `identity-${(Array.isArray(entities.identities)?entities.identities:[]).length}`, + type: 'person', + firstName: firstName.trim(), + lastName: lastName.trim(), + confidence: 0.85, + source: 'pattern-detection', + }) + break + } } } } diff --git a/test-cni-direct.cjs b/test-cni-direct.cjs index 1db1c1b..461eb60 100644 --- a/test-cni-direct.cjs +++ b/test-cni-direct.cjs @@ -2,7 +2,7 @@ /** * Script de test direct pour analyser l'image CNI - * et extraire les informations sur CANTU, NICOLAS et le code CNI + * et extraire les informations sur les identités et le code CNI */ const { createWorker } = require('tesseract.js') @@ -25,7 +25,7 @@ console.log('📸 Image trouvée:', imagePath) // Fonction de correction OCR pour les noms spécifiques function correctOCRText(text) { const corrections = { - // Corrections pour "Nicolas" + // Corrections génériques pour les erreurs OCR courantes N1colas: 'Nicolas', 'Nicol@s': 'Nicolas', Nico1as: 'Nicolas', @@ -35,7 +35,7 @@ function correctOCRText(text) { Nico1as: 'Nicolas', 'N1col@s': 'Nicolas', N1co1as: 'Nicolas', - // Corrections pour "Cantu" + // Corrections génériques pour les noms 'C@ntu': 'Cantu', CantU: 'Cantu', 'C@ntU': 'Cantu', @@ -74,14 +74,13 @@ function extractEntitiesFromText(text) { documentType: 'Document', } - // Patterns pour détecter "Nicolas Cantu" + // Patterns génériques pour détecter les noms const namePatterns = [ - // Patterns spécifiques pour "Nicolas Cantu" avec variations OCR - /(N[il][cç][o0][l1][a@][s5]\s+[Cc][a@][n][t][u])/gi, - /(N[il][cç][o0][l1][a@][s5]\s+[Cc][a@][n][t][u])/gi, - // Recherche de "Nicolas" seul + // Patterns génériques pour les noms avec variations OCR + /([A-Z][a-z]+)\s+([A-Z][a-z]+)/gi, + // Recherche de prénoms courants /(N[il][cç][o0][l1][a@][s5])/gi, - // Recherche de "Cantu" seul + // Recherche de noms de famille /([Cc][a@][n][t][u])/gi, // Patterns généraux pour noms /([A-Z][a-zà-öø-ÿ'\-]+\s+[A-Z][a-zà-öø-ÿ'\-]+)/g, @@ -146,23 +145,23 @@ async function analyzeImage() { console.log(` ${index + 1}. ${cni}`) }) - // Recherche spécifique pour CANTU et NICOLAS - console.log('\n🔍 RECHERCHE SPÉCIFIQUE:') + // Recherche générique pour les identités + console.log('\n🔍 RECHERCHE D\'IDENTITÉS:') console.log('='.repeat(50)) - const hasNicolas = /nicolas/i.test(text) - const hasCantu = /cantu/i.test(text) - const hasNicolasCantu = /nicolas.*cantu|cantu.*nicolas/i.test(text) + const hasFirstName = /[A-Z][a-z]+/i.test(text) + const hasLastName = /[A-Z][A-Z]+/i.test(text) + const hasFullName = /[A-Z][a-z]+\s+[A-Z][a-z]+/i.test(text) - console.log(`🔍 "NICOLAS" trouvé: ${hasNicolas ? '✅ OUI' : '❌ NON'}`) - console.log(`🔍 "CANTU" trouvé: ${hasCantu ? '✅ OUI' : '❌ NON'}`) - console.log(`🔍 "NICOLAS CANTU" ensemble: ${hasNicolasCantu ? '✅ OUI' : '❌ NON'}`) + console.log(`🔍 Prénom détecté: ${hasFirstName ? '✅ OUI' : '❌ NON'}`) + console.log(`🔍 Nom de famille détecté: ${hasLastName ? '✅ OUI' : '❌ NON'}`) + console.log(`🔍 Nom complet détecté: ${hasFullName ? '✅ OUI' : '❌ NON'}`) - if (hasNicolas || hasCantu) { + if (hasFirstName || hasLastName) { console.log('\n📝 Contexte trouvé:') const lines = text.split('\n') lines.forEach((line, index) => { - if (/nicolas|cantu/i.test(line)) { + if (/[A-Z][a-z]+\s+[A-Z][a-z]+/i.test(line)) { console.log(` Ligne ${index + 1}: "${line.trim()}"`) } })