refactor: rendre générique les références spécifiques à Nicolas Cantu

- enhancedOcr.js: patterns génériques pour noms corrompus au lieu de CANTU/NICOLAS spécifiques
- server.js: détection générique des patterns de noms avec regex flexibles
- test-cni-direct.cjs: tests génériques pour identités au lieu de noms spécifiques
- Amélioration de la robustesse du système OCR pour tous types de noms
This commit is contained in:
4NK IA 2025-09-18 20:13:07 +00:00
parent aad52027c1
commit 981ea970d2
3 changed files with 73 additions and 54 deletions

View File

@ -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<<NICOLAS' },
{ from: /CANTU<<<<NICOLAS/g, to: 'CANTU<<NICOLAS' },
{ from: /CANTU<<<<<<NICOLAS/g, to: 'CANTU<<NICOLAS' },
{ from: /NICOLAS<<<<<</g, to: 'NICOLAS<<' },
{ from: /NICOLAS<<<</g, to: 'NICOLAS<<' },
// Corrections génériques pour les noms corrompus
{ from: /([A-Z]{2,})CCKKLLLLK/g, to: '$1' }, // Supprimer les caractères parasites après les noms
{ from: /([A-Z]{2,})<+([A-Z]{2,})/g, to: '$1<<$2' }, // Normaliser les séparateurs de noms
{ from: /([A-Z]{2,})<<<<([A-Z]{2,})/g, to: '$1<<$2' }, // Réduire les séparateurs multiples
{ from: /([A-Z]{2,})<<<<<<([A-Z]{2,})/g, to: '$1<<$2' }, // Réduire les séparateurs multiples
{ from: /([A-Z]{2,})<<<<<</g, to: '$1<<' }, // Nettoyer les séparateurs en fin de nom
{ from: /([A-Z]{2,})<<<</g, to: '$1<<' }, // Nettoyer les séparateurs en fin de nom
// Corrections de caractères OCR courants
{ from: /0/g, to: 'O' }, // 0 -> 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
{

View File

@ -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,})</)
// Chercher PRENOM avant << (ex: NICOLAS<<...)
// Chercher PRENOM avant << (ex: PRENOM<<...)
const mGiven = mrzText.match(/\b([A-Z]{2,})<<[A-Z<]{2,}\b/)
const last = mSurname?.[1]?.trim()
const first = mGiven?.[1]?.trim()
@ -1394,29 +1394,50 @@ function extractEntitiesFromText(text) {
}
}
// Recherche spécifique pour CANTU/Nicolas (patterns corrompus)
// Recherche générique pour les patterns de noms corrompus
if (!(Array.isArray(entities.identities) && entities.identities.length > 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
}
}
}
}

View File

@ -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()}"`)
}
})