From 96fdacf0b71431ffd4431d2117c4d3364ed5118e Mon Sep 17 00:00:00 2001
From: FWao
+ {{ + t( + 'result.pdf.forced_notice', + { count: session.pdfExportForced.count }, + session.pdfExportForced.count, + ) + }} +
{{ session.pdfExportBlock.message }}
+{{ t('result.pdf.export_anyway_hint') }}
+
{{ session.pdfPreviewError }}
@@ -572,8 +616,6 @@ import { usePopover } from '@/composables/usePopover'
import { useResultLifetime } from '@/composables/useResultLifetime'
import { useToast } from '@/composables/useToast'
import { useFileDownload } from '@/composables/useFileDownload'
-import { anonymizeApi } from '@/services/anonymizeApi'
-import { extractPdfExportErrorMessage } from '@/utils/errors'
import type { MatchRange } from '@/utils/textSegments'
import { getBannerClass } from '@/utils/statusStyles'
import { entityTypeLabel, sourceTypeLabel } from '@/utils/entityLabels'
@@ -584,7 +626,7 @@ const { t } = useI18n()
const session = useSessionStore()
const settings = useSettingsStore()
const toast = useToast()
-const { downloadBlob, downloadFromApi } = useFileDownload()
+const { downloadBlob } = useFileDownload()
/** The ACTIVE document of the batch — everything below renders its state. */
const doc = computed(() => session.activeDocument)
@@ -998,38 +1040,27 @@ const exportingPdf = ref(false)
*/
async function downloadRedactedPdf() {
const entry = doc.value
- const file = entry?.file
- const requestId = entry?.result?.request_id
- if (!entry || !file || requestId === undefined || exportingPdf.value) return
+ if (!entry || entry.file === null || entry.result === null || exportingPdf.value) return
if (entry.pdfPreviewBlob !== null && !entry.pdfPreviewLoading) {
downloadBlob(entry.pdfPreviewBlob, exportFilename('pdf'))
return
}
- const overrides = [...entry.overrides.values()]
exportingPdf.value = true
try {
- await downloadFromApi(
- () =>
- anonymizeApi.exportPdf(
- file,
- requestId,
- overrides,
- entry.policy,
- entry.rules,
- entry.redactAreas,
- // These matter only on a backend cache miss, where the document is
- // re-extracted and re-transformed: without them the fallback would
- // skip the forced OCR, use another OCR profile, and write German
- // placeholders.
- entry.forceOcr,
- entry.ocrProfile,
- entry.outputLanguage,
- settings.redactionBars,
- ),
- exportFilename('pdf'),
- )
- } catch (err) {
- toast.error(await extractPdfExportErrorMessage(err))
+ // The same request the preview panel makes (overrides, areas, OCR profile
+ // and output language included), so a refusal lands where the "export
+ // anyway" button is instead of in a dead-end toast.
+ await session.refreshPdfPreview()
+ if (entry.pdfPreviewBlob !== null) {
+ downloadBlob(entry.pdfPreviewBlob, exportFilename('pdf'))
+ return
+ }
+ if (entry.pdfExportBlock !== null) {
+ session.activatePanel('pdf')
+ toast.error(entry.pdfExportBlock.message)
+ } else if (entry.pdfPreviewError !== null) {
+ toast.error(entry.pdfPreviewError)
+ }
} finally {
exportingPdf.value = false
}
diff --git a/frontend/locales/de.json b/frontend/locales/de.json
index 8156544..1c66177 100644
--- a/frontend/locales/de.json
+++ b/frontend/locales/de.json
@@ -236,7 +236,11 @@
"reconstructed": "Rekonstruiertes Dokument – Layout angenähert, Originalpixel werden verworfen.",
"generating": "PDF wird erzeugt …",
"preview_title": "Geschwärztes PDF (Vorschau)",
- "no_preview": "Keine Vorschau verfügbar."
+ "no_preview": "Keine Vorschau verfügbar.",
+ "export_anyway": "Trotzdem exportieren",
+ "export_anyway_hint": "Das PDF zeigt dann dieselben Stellen wie der anonymisierte Text.",
+ "forced_notice": "Dieses PDF wurde trotz eines offenen Prüfbefunds erzeugt: 1 geschwärzter Text ist darin weiterhin sichtbar. | Dieses PDF wurde trotz eines offenen Prüfbefunds erzeugt: {count} geschwärzte Texte sind darin weiterhin sichtbar.",
+ "export_more": "und {count} weitere"
},
"entities": {
"section_label": "Erkannte Entitäten",
@@ -420,7 +424,13 @@
"backend_unreachable": "Server nicht erreichbar. Bitte prüfen Sie, ob das Backend läuft.",
"pdf_export_failed": "PDF-Export fehlgeschlagen. Bitte versuchen Sie es erneut.",
"pdf_export_detail": "PDF-Export fehlgeschlagen: {detail}",
- "unauthorized": "Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an."
+ "unauthorized": "Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",
+ "export": {
+ "pdf_export_residual_explained": "PDF nicht erzeugt: {count} geschwärzte Textstelle(n) kommen auch außerhalb der geschwärzten Passagen vor und blieben im PDF sichtbar – genau wie im anonymisierten Text.",
+ "pdf_export_residual_unexplained": "Prüfung fehlgeschlagen: Eine Schwärzung wurde im PDF nicht angewendet. Das PDF wurde nicht erzeugt.",
+ "pdf_export_not_located": "Prüfung fehlgeschlagen: Nicht alle geschwärzten Inhalte konnten im PDF gefunden werden. Das PDF wurde nicht erzeugt.",
+ "pdf_export_area_residual": "Prüfung fehlgeschlagen: Unter einem geschwärzten Bereich ist noch Text vorhanden. Das PDF wurde nicht erzeugt."
+ }
},
"toast": {
"copy_success": "Anonymisierter Text in die Zwischenablage kopiert.",
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 7bf38d1..3968c60 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -236,7 +236,11 @@
"reconstructed": "Reconstructed document – layout approximated, the original pixels are discarded.",
"generating": "Generating PDF …",
"preview_title": "Redacted PDF (preview)",
- "no_preview": "No preview available."
+ "no_preview": "No preview available.",
+ "export_anyway": "Export anyway",
+ "export_anyway_hint": "The PDF will then show the same passages as the anonymized text.",
+ "forced_notice": "This PDF was created despite an unresolved finding: 1 redacted text is still visible in it. | This PDF was created despite an unresolved finding: {count} redacted texts are still visible in it.",
+ "export_more": "and {count} more"
},
"entities": {
"section_label": "Detected entities",
@@ -420,7 +424,13 @@
"backend_unreachable": "Server unreachable. Please check whether the backend is running.",
"pdf_export_failed": "PDF export failed. Please try again.",
"pdf_export_detail": "PDF export failed: {detail}",
- "unauthorized": "Your session has expired. Please sign in again."
+ "unauthorized": "Your session has expired. Please sign in again.",
+ "export": {
+ "pdf_export_residual_explained": "PDF not created: {count} redacted text(s) also occur outside the redacted passages and would stay visible in the PDF — exactly as they do in the anonymized text.",
+ "pdf_export_residual_unexplained": "Verification failed: a redaction was not applied in the PDF. The PDF was not created.",
+ "pdf_export_not_located": "Verification failed: not all redacted content could be located in the PDF. The PDF was not created.",
+ "pdf_export_area_residual": "Verification failed: text is still present under a blacked-out area. The PDF was not created."
+ }
},
"toast": {
"copy_success": "Anonymized text copied to the clipboard.",
diff --git a/frontend/locales/es.json b/frontend/locales/es.json
index acd51fb..fce6e67 100644
--- a/frontend/locales/es.json
+++ b/frontend/locales/es.json
@@ -236,7 +236,11 @@
"reconstructed": "Documento reconstruido: diseño aproximado, los píxeles originales se descartan.",
"generating": "Generando el PDF …",
"preview_title": "PDF censurado (vista previa)",
- "no_preview": "No hay vista previa disponible."
+ "no_preview": "No hay vista previa disponible.",
+ "export_anyway": "Exportar de todos modos",
+ "export_anyway_hint": "El PDF mostrará entonces los mismos pasajes que el texto anonimizado.",
+ "forced_notice": "Este PDF se creó a pesar de un hallazgo sin resolver: 1 texto redactado sigue visible en él. | Este PDF se creó a pesar de un hallazgo sin resolver: {count} textos redactados siguen visibles en él.",
+ "export_more": "y {count} más"
},
"entities": {
"section_label": "Entidades detectadas",
@@ -420,7 +424,13 @@
"backend_unreachable": "Servidor no accesible. Compruebe si el backend está en marcha.",
"pdf_export_failed": "La exportación a PDF ha fallado. Inténtelo de nuevo.",
"pdf_export_detail": "La exportación a PDF ha fallado: {detail}",
- "unauthorized": "Su sesión ha caducado. Vuelva a iniciar sesión."
+ "unauthorized": "Su sesión ha caducado. Vuelva a iniciar sesión.",
+ "export": {
+ "pdf_export_residual_explained": "PDF no creado: {count} texto(s) redactado(s) aparecen también fuera de los pasajes redactados y quedarían visibles en el PDF, igual que en el texto anonimizado.",
+ "pdf_export_residual_unexplained": "Verificación fallida: una redacción no se aplicó en el PDF. El PDF no se creó.",
+ "pdf_export_not_located": "Verificación fallida: no se pudo localizar todo el contenido redactado en el PDF. El PDF no se creó.",
+ "pdf_export_area_residual": "Verificación fallida: todavía hay texto bajo un área tachada. El PDF no se creó."
+ }
},
"toast": {
"copy_success": "Texto anonimizado copiado al portapapeles.",
diff --git a/frontend/locales/fr.json b/frontend/locales/fr.json
index 995cbc6..a99f0e0 100644
--- a/frontend/locales/fr.json
+++ b/frontend/locales/fr.json
@@ -236,7 +236,11 @@
"reconstructed": "Document reconstruit – mise en page approximative, les pixels d’origine sont supprimés.",
"generating": "Génération du PDF …",
"preview_title": "PDF caviardé (aperçu)",
- "no_preview": "Aucun aperçu disponible."
+ "no_preview": "Aucun aperçu disponible.",
+ "export_anyway": "Exporter quand même",
+ "export_anyway_hint": "Le PDF affichera alors les mêmes passages que le texte anonymisé.",
+ "forced_notice": "Ce PDF a été créé malgré un constat non résolu : 1 texte caviardé y reste visible. | Ce PDF a été créé malgré un constat non résolu : {count} textes caviardés y restent visibles.",
+ "export_more": "et {count} de plus"
},
"entities": {
"section_label": "Entités détectées",
@@ -420,7 +424,13 @@
"backend_unreachable": "Serveur injoignable. Veuillez vérifier que le backend fonctionne.",
"pdf_export_failed": "L’export PDF a échoué. Veuillez réessayer.",
"pdf_export_detail": "L’export PDF a échoué : {detail}",
- "unauthorized": "Votre session a expiré. Veuillez vous reconnecter."
+ "unauthorized": "Votre session a expiré. Veuillez vous reconnecter.",
+ "export": {
+ "pdf_export_residual_explained": "PDF non créé : {count} texte(s) caviardé(s) apparaissent aussi en dehors des passages caviardés et resteraient visibles dans le PDF — exactement comme dans le texte anonymisé.",
+ "pdf_export_residual_unexplained": "Échec de la vérification : un caviardage n'a pas été appliqué dans le PDF. Le PDF n'a pas été créé.",
+ "pdf_export_not_located": "Échec de la vérification : tous les contenus caviardés n'ont pas pu être localisés dans le PDF. Le PDF n'a pas été créé.",
+ "pdf_export_area_residual": "Échec de la vérification : du texte subsiste sous une zone noircie. Le PDF n'a pas été créé."
+ }
},
"toast": {
"copy_success": "Texte anonymisé copié dans le presse-papiers.",
diff --git a/frontend/services/anonymizeApi.ts b/frontend/services/anonymizeApi.ts
index a68001b..1297979 100644
--- a/frontend/services/anonymizeApi.ts
+++ b/frontend/services/anonymizeApi.ts
@@ -159,6 +159,7 @@ export const anonymizeApi = {
ocrProfile?: string | null,
outputLanguage?: OutputLanguage | null,
redactionBars?: boolean,
+ force?: boolean,
): Promise