4NK_IA_front/src/services/backendApi.ts
Nicolas Cantu 81df52b785 backend
2025-09-16 01:18:45 +02:00

234 lines
6.8 KiB
TypeScript

/**
* Service API pour communiquer avec le backend
* Remplace le traitement local par des appels au serveur backend
*/
import type { ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3001'
export interface BackendExtractionResult {
success: boolean
documentId: string
fileName: string
fileSize: number
mimeType: string
processing: {
ocr: {
text: string
confidence: number
wordCount: number
}
ner: {
identities: any[]
addresses: any[]
cniNumbers: any[]
dates: any[]
documentType: string
}
globalConfidence: number
}
extractedData: {
documentType: string
identities: any[]
addresses: any[]
cniNumbers: any[]
dates: any[]
}
timestamp: string
}
export interface BackendTestFiles {
success: boolean
files: Array<{
name: string
size: number
type: string
lastModified: string
}>
}
/**
* Extrait le texte et les entités d'un document via le backend
*/
export async function extractDocumentBackend(
_documentId: string,
file?: File,
hooks?: { onOcrProgress?: (progress: number) => void; onLlmProgress?: (progress: number) => void }
): Promise<ExtractionResult> {
console.log('🚀 [BACKEND] Début de l\'extraction via le backend...')
if (!file) {
throw new Error('Aucun fichier fourni pour l\'extraction')
}
// Simuler la progression OCR
if (hooks?.onOcrProgress) {
hooks.onOcrProgress(0.1)
console.log('⏳ [BACKEND] Envoi du fichier au backend...')
}
const formData = new FormData()
formData.append('document', file)
try {
const response = await fetch(`${BACKEND_URL}/api/extract`, {
method: 'POST',
body: formData
})
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`)
}
const result = await response.json()
// Vérifier si c'est le nouveau format JSON standard
if (!result.document || !result.classification || !result.extraction) {
throw new Error('Format de réponse backend invalide')
}
console.log('✅ [BACKEND] Extraction terminée avec succès')
// Convertir le résultat backend vers le format frontend
const extractionResult: ExtractionResult = {
documentId: result.document.id,
text: result.extraction.text.raw,
language: result.classification.language,
documentType: result.classification.documentType,
identities: result.extraction.entities.persons.map((person: any) => ({
id: person.id,
type: 'person',
firstName: person.firstName,
lastName: person.lastName,
confidence: person.confidence || 0.9
})),
addresses: result.extraction.entities.addresses.map((address: any) => ({
id: address.id,
street: address.street,
city: address.city,
postalCode: address.postalCode,
country: address.country || 'France',
confidence: address.confidence || 0.9
})),
properties: [],
contracts: [],
signatures: result.extraction.entities.contractual?.signatures?.map((sig: any) => sig.signatory || 'Signature détectée') || [],
confidence: result.metadata.quality.globalConfidence,
confidenceReasons: [
`OCR: ${Math.round(result.metadata.quality.textExtractionConfidence * 100)}% de confiance`,
`Texte extrait: ${result.extraction.text.characterCount} caractères`,
`Entités trouvées: ${result.extraction.entities.persons.length} personnes, ${result.extraction.entities.companies.length} sociétés, ${result.extraction.entities.addresses.length} adresses`,
`Type détecté: ${result.classification.documentType}`,
`Traitement backend: ${result.document.uploadTimestamp}`
]
}
// Extraction terminée
console.log('🎉 [BACKEND] Extraction terminée avec succès:', {
documentType: extractionResult.documentType,
identitiesCount: extractionResult.identities.length,
addressesCount: extractionResult.addresses.length,
confidence: extractionResult.confidence
})
return extractionResult
} catch (error) {
console.error('❌ [BACKEND] Erreur lors de l\'extraction:', error)
throw error
}
}
/**
* Récupère la liste des fichiers de test depuis le backend
*/
export async function getTestFilesBackend(): Promise<BackendTestFiles> {
try {
const response = await fetch(`${BACKEND_URL}/api/test-files`)
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`)
}
const result: BackendTestFiles = await response.json()
console.log('📁 [BACKEND] Fichiers de test récupérés:', result.files.length)
return result
} catch (error) {
console.error('❌ [BACKEND] Erreur lors de la récupération des fichiers de test:', error)
throw error
}
}
// Cache pour le health check
let backendHealthCache: { isHealthy: boolean; timestamp: number } | null = null
const HEALTH_CHECK_CACHE_DURATION = 5000 // 5 secondes
/**
* Vérifie la santé du backend avec cache
*/
export async function checkBackendHealth(): Promise<boolean> {
const now = Date.now()
// Utiliser le cache si disponible et récent
if (backendHealthCache && (now - backendHealthCache.timestamp) < HEALTH_CHECK_CACHE_DURATION) {
return backendHealthCache.isHealthy
}
try {
const response = await fetch(`${BACKEND_URL}/api/health`)
const result = await response.json()
const isHealthy = result.status === 'OK'
console.log('🏥 [BACKEND] Health check:', result.status)
// Mettre en cache le résultat
backendHealthCache = { isHealthy, timestamp: now }
return isHealthy
} catch (error) {
console.error('❌ [BACKEND] Backend non accessible:', error)
// Mettre en cache le résultat négatif
backendHealthCache = { isHealthy: false, timestamp: now }
return false
}
}
// API mock pour compatibilité avec l'ancien système
export const backendDocumentApi = {
extract: extractDocumentBackend,
analyze: async (documentId: string): Promise<AnalysisResult> => {
// Pour l'instant, retourner une analyse basique
return {
documentId,
documentType: 'Document',
isCNI: false,
credibilityScore: 0.8,
summary: 'Analyse en cours...',
recommendations: []
}
},
getContext: async (documentId: string): Promise<ContextResult> => {
return {
documentId,
lastUpdated: new Date(),
georisquesData: {},
cadastreData: {}
}
},
getConseil: async (documentId: string): Promise<ConseilResult> => {
return {
documentId,
analysis: 'Analyse en cours...',
recommendations: [],
risks: [],
nextSteps: [],
generatedAt: new Date()
}
}
}