ok error
This commit is contained in:
@@ -8,13 +8,35 @@ export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const formData = await req.formData();
|
||||
const file = formData.get("file") as File | null;
|
||||
// ✅ Validation améliorée du fichier
|
||||
if (!file) {
|
||||
return NextResponse.json(
|
||||
{ error: "Aucun fichier reçu." },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
console.log("📁 Fichier reçu:", file.name, "| Type:", file.type);
|
||||
|
||||
// Vérifications supplémentaires
|
||||
if (file.size === 0) {
|
||||
return NextResponse.json(
|
||||
{ error: "Le fichier est vide (0 bytes)." },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) { // 50MB
|
||||
return NextResponse.json(
|
||||
{ error: "Le fichier est trop volumineux (max 50MB)." },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log("📁 Fichier reçu:", {
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
size: `${(file.size / 1024 / 1024).toFixed(2)} MB`,
|
||||
lastModified: new Date(file.lastModified).toISOString()
|
||||
});
|
||||
|
||||
let fileContent = "";
|
||||
const fileType = file.type;
|
||||
@@ -22,25 +44,56 @@ export async function POST(req: NextRequest) {
|
||||
// --- LOGIQUE D'EXTRACTION DE TEXTE ---
|
||||
if (fileType === "application/pdf") {
|
||||
console.log("📄 Traitement PDF en cours...");
|
||||
console.log("📊 Taille du fichier:", file.size, "bytes");
|
||||
|
||||
try {
|
||||
const buffer = Buffer.from(await file.arrayBuffer());
|
||||
console.log("📦 Buffer créé, taille:", buffer.length);
|
||||
|
||||
const data = await pdf(buffer);
|
||||
fileContent = data.text || "";
|
||||
console.log("✅ Extraction PDF réussie, longueur:", fileContent.length);
|
||||
|
||||
// ✅ Vérification supplémentaire
|
||||
console.log("✅ Extraction PDF réussie, longueur:", fileContent.length);
|
||||
console.log("📄 Nombre de pages:", data.numpages);
|
||||
console.log("ℹ️ Info PDF:", data.info?.Title || "Titre non disponible");
|
||||
|
||||
// ✅ Vérification améliorée
|
||||
if (!fileContent.trim()) {
|
||||
console.log("⚠️ PDF vide ou non lisible");
|
||||
console.log("⚠️ PDF vide - Détails:", {
|
||||
pages: data.numpages,
|
||||
metadata: data.metadata,
|
||||
info: data.info,
|
||||
extractedLength: fileContent.length
|
||||
});
|
||||
|
||||
// Détecter si c'est un PDF scanné
|
||||
const isScanned = data.info?.Creator?.includes('RICOH') ||
|
||||
data.info?.Creator?.includes('Canon') ||
|
||||
data.info?.Creator?.includes('HP') ||
|
||||
data.info?.Producer?.includes('Scanner') ||
|
||||
(data.numpages > 0 && fileContent.length < 50);
|
||||
|
||||
const errorMessage = isScanned
|
||||
? `Ce PDF semble être un document scanné (créé par: ${data.info?.Creator}). Les documents scannés contiennent des images de texte, pas du texte extractible.\n\n💡 Solutions :\n- Utilisez un PDF créé depuis Word/Google Docs\n- Appliquez l'OCR avec Adobe Acrobat\n- Recréez le document au lieu de le scanner`
|
||||
: `Le PDF ne contient pas de texte extractible.\n\nCela peut être dû à :\n- PDF scanné (image uniquement)\n- PDF protégé\n- PDF avec texte en images\n- Nombre de pages: ${data.numpages}`;
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: "Le PDF ne contient pas de texte extractible ou est protégé." },
|
||||
{ error: errorMessage },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
} catch (pdfError) {
|
||||
console.error("❌ Erreur PDF détaillée:", pdfError);
|
||||
console.error("❌ Erreur PDF détaillée:", {
|
||||
message: pdfError instanceof Error ? pdfError.message : "Erreur inconnue",
|
||||
stack: pdfError instanceof Error ? pdfError.stack : undefined,
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
fileType: file.type
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `Erreur traitement PDF: ${pdfError instanceof Error ? pdfError.message : "Erreur inconnue"}. Vérifiez que le PDF n'est pas protégé ou corrompu.`,
|
||||
error: `Impossible de traiter ce PDF (${file.name}). Erreur: ${pdfError instanceof Error ? pdfError.message : "Erreur inconnue"}. Vérifiez que le PDF n'est pas protégé, corrompu ou scanné.`,
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
|
||||
@@ -54,7 +54,9 @@ export const useAnonymization = ({
|
||||
const textToProcess = sourceText || fileContent || "";
|
||||
|
||||
if (!textToProcess.trim()) {
|
||||
setError("Veuillez saisir du texte à anonymiser ou télécharger un fichier");
|
||||
setError(
|
||||
"Veuillez saisir du texte à anonymiser ou télécharger un fichier"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,11 @@ export const useAnonymization = ({
|
||||
const formData = new FormData();
|
||||
|
||||
if (uploadedFile) {
|
||||
console.log("📁 Traitement fichier:", uploadedFile.name);
|
||||
console.log("📁 Traitement fichier:", {
|
||||
name: uploadedFile.name,
|
||||
type: uploadedFile.type,
|
||||
size: uploadedFile.size
|
||||
});
|
||||
formData.append("file", uploadedFile);
|
||||
} else {
|
||||
console.log("📝 Traitement texte saisi");
|
||||
@@ -79,13 +85,45 @@ export const useAnonymization = ({
|
||||
}
|
||||
|
||||
console.log("🔍 Appel à /api/process-document avec Presidio...");
|
||||
console.log("📦 FormData préparée:", Array.from(formData.entries()));
|
||||
|
||||
const response = await fetch("/api/process-document", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
console.log("📡 Réponse reçue:", {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: Object.fromEntries(response.headers.entries())
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur API: ${response.status}`);
|
||||
let errorMessage = `Erreur HTTP: ${response.status}`;
|
||||
|
||||
try {
|
||||
const responseText = await response.text();
|
||||
console.log("📄 Contenu de l'erreur:", responseText);
|
||||
|
||||
if (responseText.trim()) {
|
||||
try {
|
||||
const errorData = JSON.parse(responseText);
|
||||
if (errorData.error) {
|
||||
errorMessage = errorData.error;
|
||||
console.log("✅ Message détaillé récupéré:", errorMessage);
|
||||
}
|
||||
} catch (jsonError) {
|
||||
console.error("❌ Erreur parsing JSON:", jsonError); // ✅ Utiliser la variable
|
||||
console.error("❌ Réponse non-JSON:", responseText);
|
||||
errorMessage = `Erreur ${response.status}: Réponse invalide du serveur`;
|
||||
}
|
||||
}
|
||||
} catch (readError) {
|
||||
console.error("❌ Impossible de lire la réponse:", readError);
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const data: ProcessDocumentResponse = await response.json();
|
||||
@@ -98,30 +136,34 @@ export const useAnonymization = ({
|
||||
if (data.anonymizedText) {
|
||||
console.log("✅ Anonymisation réussie avec Presidio");
|
||||
setOutputText(data.anonymizedText);
|
||||
|
||||
|
||||
// Extraire les mappings depuis les résultats Presidio (plus d'erreur 'any')
|
||||
if (data.analyzerResults && data.text) {
|
||||
const mappings: EntityMapping[] = data.analyzerResults.map((entity: PresidioAnalyzerResult, index: number) => ({
|
||||
originalValue: data.text!.substring(entity.start, entity.end),
|
||||
anonymizedValue: `[${entity.entity_type}${index + 1}]`,
|
||||
entityType: entity.entity_type,
|
||||
startIndex: entity.start,
|
||||
endIndex: entity.end
|
||||
}));
|
||||
const mappings: EntityMapping[] = data.analyzerResults.map(
|
||||
(entity: PresidioAnalyzerResult, index: number) => ({
|
||||
originalValue: data.text!.substring(entity.start, entity.end),
|
||||
anonymizedValue: `[${entity.entity_type}${index + 1}]`,
|
||||
entityType: entity.entity_type,
|
||||
startIndex: entity.start,
|
||||
endIndex: entity.end,
|
||||
})
|
||||
);
|
||||
setEntityMappings(mappings);
|
||||
console.log("📋 Entités détectées:", mappings.length);
|
||||
console.log("🔍 Détails des entités:", mappings);
|
||||
}
|
||||
} else if (data.text) {
|
||||
console.log("⚠️ Fallback: Presidio non disponible, texte original retourné");
|
||||
console.log(
|
||||
"⚠️ Fallback: Presidio non disponible, texte original retourné"
|
||||
);
|
||||
setOutputText(data.text);
|
||||
setError("Presidio temporairement indisponible. Texte non anonymisé.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur anonymisation:", error);
|
||||
console.error("❌ Erreur anonymisation complète:", error);
|
||||
setError(
|
||||
error instanceof Error
|
||||
? `Erreur Presidio: ${error.message}`
|
||||
? error.message
|
||||
: "Erreur lors de l'anonymisation avec Presidio"
|
||||
);
|
||||
} finally {
|
||||
@@ -130,4 +172,4 @@ export const useAnonymization = ({
|
||||
};
|
||||
|
||||
return { anonymizeData, isProcessing };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -47,7 +47,29 @@ export const useFileHandler = ({
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur HTTP: ${response.status}`);
|
||||
// ✅ Récupérer le message d'erreur détaillé du serveur
|
||||
let errorMessage = `Erreur HTTP: ${response.status}`;
|
||||
|
||||
try {
|
||||
const responseText = await response.text();
|
||||
console.log("🔍 Réponse brute du serveur:", responseText);
|
||||
|
||||
try {
|
||||
const errorData = JSON.parse(responseText);
|
||||
if (errorData.error) {
|
||||
errorMessage = errorData.error;
|
||||
console.log("✅ Message détaillé récupéré:", errorMessage);
|
||||
}
|
||||
} catch (jsonError) {
|
||||
console.error("❌ Erreur parsing JSON:", jsonError);
|
||||
console.error("❌ Réponse non-JSON:", responseText);
|
||||
errorMessage = `Erreur ${response.status}: ${responseText || 'Réponse invalide du serveur'}`;
|
||||
}
|
||||
} catch (readError) {
|
||||
console.error("❌ Impossible de lire la réponse:", readError);
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
33
app/page.tsx
33
app/page.tsx
@@ -131,12 +131,12 @@ export default function Home() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error Message */}
|
||||
{/* Error Message - Version améliorée */}
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 rounded-xl p-3 sm:p-4 mx-2 sm:mx-0">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-start space-x-3">
|
||||
<svg
|
||||
className="w-4 h-4 sm:w-5 sm:h-5 text-red-500 flex-shrink-0"
|
||||
className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -148,7 +148,32 @@ export default function Home() {
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<p className="text-red-700 text-xs sm:text-sm font-medium break-words">{error}</p>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-red-800 text-sm font-semibold mb-2">
|
||||
{error.includes('scanné') ? '📄 PDF Scanné Détecté' :
|
||||
error.includes('HTTP') ? '🚨 Erreur de Traitement' :
|
||||
'⚠️ Erreur'}
|
||||
</h3>
|
||||
<div className="text-red-700 text-xs sm:text-sm leading-relaxed">
|
||||
{error.split('\n').map((line, index) => (
|
||||
<div key={index} className={index > 0 ? 'mt-2' : ''}>
|
||||
{line.startsWith('💡') ? (
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mt-3">
|
||||
<div className="text-blue-800 font-medium text-sm">
|
||||
{line}
|
||||
</div>
|
||||
</div>
|
||||
) : line.startsWith('-') ? (
|
||||
<div className="ml-4 text-blue-700">
|
||||
• {line.substring(1).trim()}
|
||||
</div>
|
||||
) : (
|
||||
<div>{line}</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user