feat: Traitement automatique des fichiers non traités
- Modification de listFolderResults pour détecter les fichiers non traités - Mise en pending automatique des fichiers sans résultats d'extraction - Fonction processDocument pour traiter les fichiers en arrière-plan - Fonction processFileInBackground pour le traitement asynchrone - Fonction removePendingFlag pour nettoyer les flags après traitement - Les fichiers non traités sont maintenant automatiquement traités Fixes: Fichiers non traités mis en pending et traités automatiquement Fixes: Traitement en arrière-plan des fichiers uploadés sans extraction
This commit is contained in:
parent
736637c5cd
commit
328d2584de
@ -267,81 +267,34 @@ function listFolderResults(folderHash) {
|
|||||||
|
|
||||||
// Vérifier si ce fichier n'a pas déjà un résultat en cache
|
// Vérifier si ce fichier n'a pas déjà un résultat en cache
|
||||||
const hasCacheResult = results.some(result => result.fileHash === fileHash)
|
const hasCacheResult = results.some(result => result.fileHash === fileHash)
|
||||||
|
// Vérifier si ce fichier n'est pas déjà en pending
|
||||||
|
const isAlreadyPending = pending.some(p => p.fileHash === fileHash)
|
||||||
|
|
||||||
if (!hasCacheResult) {
|
if (!hasCacheResult && !isAlreadyPending) {
|
||||||
// Créer un résultat minimal pour les fichiers non traités
|
// Mettre le fichier en pending et le traiter automatiquement
|
||||||
const filePath = path.join(uploadsPath, file)
|
const filePath = path.join(uploadsPath, file)
|
||||||
const stats = fs.statSync(filePath)
|
const stats = fs.statSync(filePath)
|
||||||
|
|
||||||
results.push({
|
console.log(`[FOLDER] Fichier non traité détecté, mise en pending: ${file}`)
|
||||||
fileHash,
|
|
||||||
document: {
|
|
||||||
id: `doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
||||||
fileName: file,
|
|
||||||
mimeType: getMimeTypeFromExtension(path.extname(file)),
|
|
||||||
fileSize: stats.size,
|
|
||||||
uploadTimestamp: stats.mtime.toISOString()
|
|
||||||
},
|
|
||||||
classification: {
|
|
||||||
documentType: 'Document',
|
|
||||||
confidence: 0.0,
|
|
||||||
subType: 'Non traité',
|
|
||||||
language: 'fr',
|
|
||||||
pageCount: 1
|
|
||||||
},
|
|
||||||
extraction: {
|
|
||||||
text: {
|
|
||||||
raw: '',
|
|
||||||
processed: '',
|
|
||||||
wordCount: 0,
|
|
||||||
characterCount: 0,
|
|
||||||
confidence: 0.0
|
|
||||||
},
|
|
||||||
entities: {
|
|
||||||
persons: [],
|
|
||||||
companies: [],
|
|
||||||
addresses: [],
|
|
||||||
financial: {
|
|
||||||
amounts: [],
|
|
||||||
totals: {},
|
|
||||||
payment: {}
|
|
||||||
},
|
|
||||||
dates: [],
|
|
||||||
contractual: {
|
|
||||||
clauses: [],
|
|
||||||
signatures: []
|
|
||||||
},
|
|
||||||
references: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
processing: {
|
|
||||||
engine: '4NK_IA_Backend',
|
|
||||||
version: '1.0.0',
|
|
||||||
processingTime: '0ms',
|
|
||||||
ocrEngine: 'none',
|
|
||||||
nerEngine: 'none',
|
|
||||||
preprocessing: {
|
|
||||||
applied: false,
|
|
||||||
reason: 'Fichier non traité'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
quality: {
|
|
||||||
globalConfidence: 0.0,
|
|
||||||
textExtractionConfidence: 0.0,
|
|
||||||
entityExtractionConfidence: 0.0,
|
|
||||||
classificationConfidence: 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
success: false,
|
|
||||||
errors: ['Fichier non traité'],
|
|
||||||
warnings: ['Aucune extraction effectuée'],
|
|
||||||
timestamp: stats.mtime.toISOString()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(`[FOLDER] Fichier non traité ajouté: ${file}`)
|
// Créer le flag pending
|
||||||
|
const pendingData = {
|
||||||
|
fileHash,
|
||||||
|
fileName: file,
|
||||||
|
folderHash,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
status: 'processing'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sauvegarder le flag pending
|
||||||
|
createPendingFlag(folderHash, fileHash, pendingData)
|
||||||
|
|
||||||
|
// Ajouter à la liste des pending
|
||||||
|
pending.push(pendingData)
|
||||||
|
hasPending = true
|
||||||
|
|
||||||
|
// Traiter le fichier en arrière-plan
|
||||||
|
processFileInBackground(filePath, fileHash, folderHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,6 +302,103 @@ function listFolderResults(folderHash) {
|
|||||||
return { results, pending, hasPending }
|
return { results, pending, hasPending }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fonction pour traiter un document (extraction de la logique de /api/extract)
|
||||||
|
async function processDocument(filePath, fileHash) {
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`[PROCESS] Début du traitement: ${filePath}`)
|
||||||
|
|
||||||
|
// Obtenir les informations du fichier
|
||||||
|
const stats = fs.statSync(filePath)
|
||||||
|
const ext = path.extname(filePath)
|
||||||
|
const mimeType = getMimeTypeFromExtension(ext)
|
||||||
|
|
||||||
|
// Créer un objet file similaire à celui de multer
|
||||||
|
const file = {
|
||||||
|
path: filePath,
|
||||||
|
originalname: path.basename(filePath),
|
||||||
|
mimetype: mimeType,
|
||||||
|
size: stats.size
|
||||||
|
}
|
||||||
|
|
||||||
|
let ocrResult
|
||||||
|
let result
|
||||||
|
|
||||||
|
// Si c'est un PDF, extraire le texte directement
|
||||||
|
if (mimeType === 'application/pdf') {
|
||||||
|
console.log(`[PROCESS] Extraction de texte depuis PDF...`)
|
||||||
|
try {
|
||||||
|
ocrResult = await extractTextFromPdf(filePath)
|
||||||
|
console.log(`[PROCESS] Texte extrait du PDF: ${ocrResult.text.length} caractères`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[PROCESS] Erreur lors de l'extraction PDF:`, error.message)
|
||||||
|
throw new Error(`Erreur lors de l'extraction PDF: ${error.message}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pour les images, utiliser l'OCR avec préprocessing
|
||||||
|
ocrResult = await extractTextFromImage(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extraction NER
|
||||||
|
const entities = extractEntitiesFromText(ocrResult.text)
|
||||||
|
|
||||||
|
// Mesure du temps de traitement
|
||||||
|
const processingTime = Date.now() - startTime
|
||||||
|
|
||||||
|
// Génération du format JSON standard
|
||||||
|
result = generateStandardJSON(file, ocrResult, entities, processingTime)
|
||||||
|
|
||||||
|
console.log(`[PROCESS] Traitement terminé en ${processingTime}ms`)
|
||||||
|
return result
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[PROCESS] Erreur lors du traitement:`, error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fonction pour traiter un fichier en arrière-plan
|
||||||
|
async function processFileInBackground(filePath, fileHash, folderHash) {
|
||||||
|
try {
|
||||||
|
console.log(`[BACKGROUND] Début du traitement en arrière-plan: ${filePath}`)
|
||||||
|
|
||||||
|
// Traiter le document
|
||||||
|
const result = await processDocument(filePath, fileHash)
|
||||||
|
|
||||||
|
// Sauvegarder le résultat dans le cache du dossier
|
||||||
|
const success = saveJsonCacheInFolder(folderHash, fileHash, result)
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// Supprimer le flag pending
|
||||||
|
removePendingFlag(folderHash, fileHash)
|
||||||
|
console.log(`[BACKGROUND] Traitement terminé avec succès: ${fileHash}`)
|
||||||
|
} else {
|
||||||
|
console.error(`[BACKGROUND] Erreur lors de la sauvegarde du résultat: ${fileHash}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[BACKGROUND] Erreur lors du traitement en arrière-plan:`, error)
|
||||||
|
// Supprimer le flag pending même en cas d'erreur
|
||||||
|
removePendingFlag(folderHash, fileHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fonction pour supprimer un flag pending
|
||||||
|
function removePendingFlag(folderHash, fileHash) {
|
||||||
|
try {
|
||||||
|
const cachePath = path.join('cache', folderHash)
|
||||||
|
const pendingFile = path.join(cachePath, `${fileHash}.pending`)
|
||||||
|
|
||||||
|
if (fs.existsSync(pendingFile)) {
|
||||||
|
fs.unlinkSync(pendingFile)
|
||||||
|
console.log(`[PENDING] Flag pending supprimé: ${fileHash}`)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[PENDING] Erreur lors de la suppression du flag pending:`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fonction pour vérifier si un fichier existe déjà par hash dans un dossier
|
// Fonction pour vérifier si un fichier existe déjà par hash dans un dossier
|
||||||
function findExistingFileByHash(hash, folderHash) {
|
function findExistingFileByHash(hash, folderHash) {
|
||||||
const folderPath = path.join('uploads', folderHash)
|
const folderPath = path.join('uploads', folderHash)
|
||||||
@ -1138,8 +1188,8 @@ app.post('/api/extract', upload.single('document'), async (req, res) => {
|
|||||||
ocrResult = await extractTextFromImage(req.file.path)
|
ocrResult = await extractTextFromImage(req.file.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extraction NER
|
// Extraction NER
|
||||||
const entities = extractEntitiesFromText(ocrResult.text)
|
const entities = extractEntitiesFromText(ocrResult.text)
|
||||||
|
|
||||||
// Mesure du temps de traitement
|
// Mesure du temps de traitement
|
||||||
const processingTime = Date.now() - startTime
|
const processingTime = Date.now() - startTime
|
||||||
@ -1169,7 +1219,7 @@ app.post('/api/extract', upload.single('document'), async (req, res) => {
|
|||||||
details: error.message
|
details: error.message
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
// Nettoyage du fichier temporaire
|
// Nettoyage du fichier temporaire
|
||||||
if (isDuplicate) {
|
if (isDuplicate) {
|
||||||
// Supprimer le doublon uploadé
|
// Supprimer le doublon uploadé
|
||||||
fs.unlinkSync(duplicatePath)
|
fs.unlinkSync(duplicatePath)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user