From 65fa45d8f36cf58a24fed12321d1f289ea773e58 Mon Sep 17 00:00:00 2001 From: nBiqoz Date: Tue, 24 Jun 2025 00:30:05 +0200 Subject: [PATCH] goooood --- app/api/process-document/route.ts | 179 ++++++------------------------ app/page.tsx | 101 ++++++----------- 2 files changed, 74 insertions(+), 206 deletions(-) diff --git a/app/api/process-document/route.ts b/app/api/process-document/route.ts index 2ab70b5..e11dd00 100644 --- a/app/api/process-document/route.ts +++ b/app/api/process-document/route.ts @@ -8,37 +8,29 @@ export async function POST(req: NextRequest) { try { const formData = await req.formData(); const file = formData.get("file") as File | null; - console.log("📁 Fichier reçu:", file?.name, file?.type); - if (!file) { - console.log("❌ Aucun fichier reçu"); return NextResponse.json( { error: "Aucun fichier reçu." }, { status: 400 } ); } + console.log("📁 Fichier reçu:", file.name, "| Type:", file.type); let fileContent = ""; const fileType = file.type; - console.log("🔍 Type de fichier:", fileType); + // --- LOGIQUE D'EXTRACTION DE TEXTE (INCHANGÉE) --- if (fileType === "application/pdf") { console.log("📄 Traitement PDF en cours..."); try { const buffer = Buffer.from(await file.arrayBuffer()); - console.log("📊 Taille du buffer:", buffer.length); - const data = await pdf(buffer); fileContent = data.text; - console.log( - "✅ Extraction PDF rĂ©ussie, longueur du texte:", - fileContent.length - ); + console.log("✅ Extraction PDF rĂ©ussie, longueur:", fileContent.length); } catch (pdfError) { - console.error("❌ Erreur PDF:", pdfError); return NextResponse.json( { - error: `Erreur lors du traitement du PDF: ${ + error: `Erreur traitement PDF: ${ pdfError instanceof Error ? pdfError.message : "Erreur inconnue" }`, }, @@ -55,14 +47,13 @@ export async function POST(req: NextRequest) { const result = await mammoth.extractRawText({ arrayBuffer }); fileContent = result.value; console.log( - "✅ Extraction Word rĂ©ussie, longueur du texte:", + "✅ Extraction Word rĂ©ussie, longueur:", fileContent.length ); } catch (wordError) { - console.error("❌ Erreur Word:", wordError); return NextResponse.json( { - error: `Erreur lors du traitement du document Word: ${ + error: `Erreur traitement Word: ${ wordError instanceof Error ? wordError.message : "Erreur inconnue" }`, }, @@ -78,10 +69,9 @@ export async function POST(req: NextRequest) { fileContent.length ); } catch (textError) { - console.error("❌ Erreur texte:", textError); return NextResponse.json( { - error: `Erreur lors de la lecture du fichier texte: ${ + error: `Erreur lecture texte: ${ textError instanceof Error ? textError.message : "Erreur inconnue" }`, }, @@ -90,7 +80,6 @@ export async function POST(req: NextRequest) { } } - // VĂ©rification du contenu extrait if (!fileContent || fileContent.trim().length === 0) { console.log("⚠ Contenu vide dĂ©tectĂ©"); return NextResponse.json( @@ -99,83 +88,20 @@ export async function POST(req: NextRequest) { ); } - console.log("🔍 Contenu extrait, longueur:", fileContent.length); + // ========================================================================= + // CONFIGURATION PRESIDIO ANALYZER (SIMPLIFIÉE) + // ========================================================================= + // Toute la configuration (recognizers, allow_list, etc.) est maintenant dans le default.yaml du service. + // L'API a juste besoin d'envoyer le texte et la langue. const analyzerConfig = { text: fileContent, language: "fr", - ad_hoc_recognizers: [ - { - name: "BelgianNRNRecognizer", - supported_entity: "BE_NATIONAL_REGISTER_NUMBER", - supported_language: "fr", - patterns: [ - { - name: "NRN_Pattern", - regex: - "\\b(?:[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01]))-?\\d{3}\\.?\\d{2}\\b", - score: 1.0, - }, - ], - context: ["registre national", "nrn", "niss"], - }, - { - name: "BelgianEnterpriseRecognizer", - supported_entity: "BE_ENTERPRISE_NUMBER", - supported_language: "fr", - patterns: [ - { - name: "BTW_Pattern", - regex: "\\bBE\\s?0\\d{3}\\.\\d{3}\\.\\d{3}\\b", - score: 0.95, - }, - ], - context: ["entreprise", "btw", "tva"], - }, - { - name: "IBANRecognizer", - supported_entity: "IBAN", - supported_language: "fr", - patterns: [ - { - name: "IBAN_Pattern", - regex: "\\b[A-Z]{2}\\d{2}\\s?(?:\\d{4}\\s?){4,7}\\d{1,4}\\b", - score: 0.95, - }, - ], - context: ["iban", "compte", "bancaire"], - }, - { - name: "PhoneRecognizer", - supported_entity: "PHONE_NUMBER", - supported_language: "fr", - patterns: [ - { - name: "Phone_Pattern", - regex: - "\\b(?:(?:\\+|00)(?:32|33|352)|0)\\s?[1-9](?:[\\s.-]?\\d{2}){3,4}\\b", - score: 0.8, - }, - ], - context: ["tĂ©lĂ©phone", "tel", "mobile", "gsm"], - }, - { - name: "EmailRecognizer", - supported_entity: "EMAIL_ADDRESS", - supported_language: "fr", - patterns: [ - { - name: "Email_Pattern", - regex: "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b", - score: 1.0, - }, - ], - context: ["email", "courriel", "adresse Ă©lectronique"], - }, - ], + // Plus de ad_hoc_recognizers ici ! }; console.log("🔍 Appel Ă  Presidio Analyzer..."); + // Mettez votre URL externe ici, ou utilisez le nom de service Docker si appropriĂ© const presidioAnalyzerUrl = "http://ocs00s000ssow8kssossocco.51.68.233.212.sslip.io/analyze"; @@ -189,29 +115,28 @@ export async function POST(req: NextRequest) { }); console.log("📊 Statut Analyzer:", analyzeResponse.status); - if (!analyzeResponse.ok) { const errorBody = await analyzeResponse.text(); - console.error("❌ Erreur Analyzer:", errorBody); return NextResponse.json( - { - error: `Erreur de l'analyseur Presidio (${analyzeResponse.status}): ${errorBody}`, - }, + { error: `Erreur Analyzer: ${errorBody}` }, { status: 500 } ); } - let analyzerResults; - try { - analyzerResults = await analyzeResponse.json(); - console.log("✅ Analyzer rĂ©ussi, rĂ©sultats:", analyzerResults.length); - } catch (jsonError) { - console.error("❌ Erreur parsing JSON Analyzer:", jsonError); - return NextResponse.json( - { error: "Erreur lors du parsing de la rĂ©ponse de l'analyseur" }, - { status: 500 } - ); - } + const analyzerResults = await analyzeResponse.json(); + console.log("✅ Analyzer a trouvĂ©", analyzerResults.length, "entitĂ©s."); + + // ========================================================================= + // CONFIGURATION PRESIDIO ANONYMIZER + // ========================================================================= + + // L'Anonymizer lira la config d'anonymisation du default.yaml de l'Analyzer + // ou vous pouvez dĂ©finir des transformations spĂ©cifiques ici si besoin. + // Pour commencer, on envoie juste les rĂ©sultats de l'analyse. + const anonymizerConfig = { + text: fileContent, + analyzer_results: analyzerResults, + }; console.log("🔍 Appel Ă  Presidio Anonymizer..."); const presidioAnonymizerUrl = @@ -223,64 +148,34 @@ export async function POST(req: NextRequest) { "Content-Type": "application/json", Accept: "application/json", }, - body: JSON.stringify({ - text: fileContent, - analyzer_results: analyzerResults, - }), + body: JSON.stringify(anonymizerConfig), }); console.log("📊 Statut Anonymizer:", anonymizeResponse.status); - if (!anonymizeResponse.ok) { const errorBody = await anonymizeResponse.text(); - console.error("❌ Erreur Anonymizer:", errorBody); return NextResponse.json( - { - error: `Erreur de l'anonymiseur Presidio (${anonymizeResponse.status}): ${errorBody}`, - }, + { error: `Erreur Anonymizer: ${errorBody}` }, { status: 500 } ); } - let anonymizerResult; - try { - anonymizerResult = await anonymizeResponse.json(); - console.log("✅ Anonymizer rĂ©ussi"); - } catch (jsonError) { - console.error("❌ Erreur parsing JSON Anonymizer:", jsonError); - return NextResponse.json( - { error: "Erreur lors du parsing de la rĂ©ponse de l'anonymiseur" }, - { status: 500 } - ); - } + const anonymizerResult = await anonymizeResponse.json(); + console.log("✅ Anonymisation rĂ©ussie."); const result = { anonymizedText: anonymizerResult.text, piiCount: analyzerResults.length, }; - console.log("✅ Traitement terminĂ© avec succĂšs"); - return NextResponse.json(result, { - status: 200, - headers: { - "Content-Type": "application/json", - }, - }); + return NextResponse.json(result, { status: 200 }); } catch (err: unknown) { console.error("❌ Erreur gĂ©nĂ©rale:", err); - const errorMessage = - err instanceof Error - ? err.message - : "Une erreur inconnue est survenue sur le serveur."; - return NextResponse.json( - { error: errorMessage }, { - status: 500, - headers: { - "Content-Type": "application/json", - }, - } + error: err instanceof Error ? err.message : "Erreur serveur inconnue.", + }, + { status: 500 } ); } } diff --git a/app/page.tsx b/app/page.tsx index 15f41c2..81e62f5 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -18,18 +18,8 @@ import { Lock, Shield, Clock, - User, - AtSign, - MapPin, - Cake, - Home as HomeIcon, - Venus, - Phone, - Building, - Fingerprint, - CreditCard, - Check, Eye, + TestTube, } from "lucide-react"; import PresidioModal from "./components/PresidioModal"; @@ -51,23 +41,6 @@ interface ProcessedFile { anonymizedText?: string; } -interface AnonymizationOptions { - [key: string]: boolean; -} - -const piiOptions = [ - { id: "name", label: "Nom & PrĂ©nom", icon: User }, - { id: "email", label: "Email", icon: AtSign }, - { id: "location", label: "Lieu", icon: MapPin }, - { id: "birthdate", label: "Date de naissance", icon: Cake }, - { id: "address", label: "Adresse", icon: HomeIcon }, - { id: "gender", label: "Genre / Sexe", icon: Venus }, - { id: "phone", label: "TĂ©lĂ©phone", icon: Phone }, - { id: "organization", label: "Entreprise", icon: Building }, - { id: "idNumber", label: "N° Identification", icon: Fingerprint }, - { id: "financial", label: "DonnĂ©es financiĂšres", icon: CreditCard }, -]; - export default function Home() { const [file, setFile] = useState(null); const [isProcessing, setIsProcessing] = useState(false); @@ -75,19 +48,12 @@ export default function Home() { const [isDragOver, setIsDragOver] = useState(false); const [history, setHistory] = useState([]); const [error, setError] = useState(null); - const [anonymizationOptions, setAnonymizationOptions] = - useState( - piiOptions.reduce((acc, option) => ({ ...acc, [option.id]: true }), {}) - ); const [showPresidioModal, setShowPresidioModal] = useState(false); const [anonymizedResult, setAnonymizedResult] = useState<{ text: string; piiCount: number; } | null>(null); - const handleOptionChange = (id: string) => - setAnonymizationOptions((prev) => ({ ...prev, [id]: !prev[id] })); - const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files?.length) { setFile(e.target.files[0]); @@ -180,6 +146,29 @@ export default function Home() { } }; + const loadTestDocument = () => { + try { + // CrĂ©er un document de test avec des donnĂ©es PII fictives + const testContent = `Rapport pour la sociĂ©tĂ© belge "Solution Globale SPRL" (BCE : BE 0987.654.321). +Contact principal : M. Luc Dubois, nĂ© le 15/03/1975. +Son numĂ©ro de registre national est le 75.03.15-123.45. +Adresse : Avenue des Arts 56, 1000 Bruxelles. +TĂ©lĂ©phone : +32 2 555 12 34. Email : luc.dubois@solutionglobale.be. +Le paiement de la facture a Ă©tĂ© effectuĂ© par carte VISA 4979 1234 5678 9012. +Le remboursement sera versĂ© sur le compte IBAN BE12 3456 7890 1234, code SWIFT : GEBABEBB.`; + + const testBlob = new Blob([testContent], { type: "text/plain" }); + const testFile = new File([testBlob], "document-test.txt", { + type: "text/plain", + }); + + setFile(testFile); + setError(null); + } catch { + setError("Erreur lors du chargement du document de test"); + } + }; + const processFile = async () => { if (!file) return; @@ -198,6 +187,7 @@ export default function Home() { }, ...prev, ]); + setFile(null); try { @@ -444,36 +434,19 @@ export default function Home() { )} -
-

- Options d'Anonymisation -

-
- {piiOptions.map((option) => ( - - ))} -
+ + {/* Bouton pour charger un document de test */} +
+
+ {isProcessing && (