OCR am Scanner nachrüsten
Den Text amtlicher Dokumente nebenbei der lokalen KI hinzufügen...
Weil meine Tintenpatronen früher ständig eingetrocknet sind, habe ich mir vor einiger Zeit ein Multifunktionsgerät zum Drucken, Scannen und Faxen angeschafft. Und wie so oft habe ich dabei gespart – nur um später festzustellen, was fehlt: Die gescannten Dokumente sind nicht durchsuchbar. Kein Wunder, denn die PDFs enthalten lediglich Bilder, aber keinen erkannten Text.
Eine Idee
Es soll mich nichts davon abhalten, diese Funktionalität nachzubauen.

Da der Scanner die Dokumente in einem freigegebenen Ordner speichert (Synology vielleicht?), der auch meiner Nextcloud als externer Speicher zur Verfügung steht, kann ich diesen Speicherort überwachen und nach neuen Dateien suchen. Dafür nutze ich ein kleines Skript, das automatisch im Hintergrund läuft.
Das Script
Mein Script überwacht das Verzeichnis /mnt/Storage/Scanner/pdf
, in dem mein Scanner per Samba neu eingescannte Dokumente ablegt.
#!/bin/bash
# Anzahl der AI-Threads und das zu verwendende Modell
AI_THREADS=16
AI_MODEL="llama3.2"
# Überwachtes Verzeichnis für neue PDF-Dateien
WATCH_DIR="/mnt/Storage/scanner/pdf"
# Inotify überwacht das Verzeichnis auf neu erstellte oder geänderte PDF-Dateien
inotifywait -m -e close_write --format "%w%f" "$WATCH_DIR" | while read NEW_FILE
do
# Prüfen, ob es sich um eine nicht bereits verarbeitete PDF-Datei handelt
if [[ "$NEW_FILE" == *.pdf && "$NEW_FILE" != *_ocr.pdf && "$NEW_FILE" != .* ]]; then
echo "Neue Datei erkannt: $NEW_FILE"
# Erstellungsdatum und Uhrzeit als Dateinamenformat setzen
FILEDATE=$(stat -c %y "$NEW_FILE" | awk '{gsub("[-:]","",$1); split($2, t, "."); gsub(":","",t[1]); print $1"_"t[1]}')
# Temporäre Datei für das OCR-verarbeitete PDF
TEMP_FILE="${NEW_FILE%.pdf}_ocr.pdf"
# OCR mit bestmöglicher Erkennungsrate auf Deutsch und Englisch
ocrmypdf --force-ocr -l deu+eng --rotate-pages --deskew --clean --output-type pdfa "$NEW_FILE" "$TEMP_FILE"
# Falls die OCR-Verarbeitung erfolgreich war, fortfahren
if [[ $? -eq 0 ]]; then
# Extrahiere den Text aus der OCR-verarbeiteten PDF
pdf_text=$(pdftotext -layout "$TEMP_FILE" -)
# Escape den extrahierten Text für die JSON-Verarbeitung mit jq
pdf_text_escaped=$(jq -Rs . <<< "$pdf_text")
# AI-Prompt zur Generierung einer kurzen deutschen Überschrift
PROMPT="Gegeben sei folgender Text: ${pdf_text_escaped}
Finde eine deutsche Überschrift mit maximal drei Wörtern für diesen Text.
Keine weiteren Ausgaben oder Erklärungen. Nur die Überschrift."
# Erstelle den JSON-Payload für die AI-Anfrage
payload=$(jq -n \
--arg thread "$AI_THREADS" \
--arg model "$AI_MODEL" \
--arg prompt "$PROMPT" \
'{ num_thread: $thread, model: $model, prompt: $prompt, stream: false }')
# Sende die Anfrage an die AI und extrahiere die Antwort als Dateitag
FILETAGS=$(curl -s http://ai:11434/api/generate -d "$payload" | jq -r .response | \
sed -e 's/[^[:alpha:]]//g; s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g; s/ß/ss/g; s/ /_/g')
# Originaldatei entfernen und neue Datei umbenennen
rm "$NEW_FILE"
NEW_FILE="${WATCH_DIR}/${FILEDATE}_${FILETAGS}.pdf"
mv "$TEMP_FILE" "$NEW_FILE"
echo "OCR abgeschlossen und Datei umbenannt: $NEW_FILE"
else
echo "Fehler bei OCR für $NEW_FILE"
rm -f "$TEMP_FILE"
fi
fi
done
Wann immer dort eine neue Datei auftaucht, wird versucht den Text zu erkennen und dem PDF hinzuzufügen.
Erklärung der Optionen von inotifywait:
-m
(monitor)
Bleibt im Überwachungsmodus und wartet kontinuierlich auf Ereignisse, anstatt nach dem ersten Ereignis zu beenden.-e close_write
Überwacht speziell das Ereignisclose_write
, das auftritt, wenn eine Datei, die zum Schreiben geöffnet war, geschlossen wird. Das ist nützlich, um Änderungen an Dateien zu erfassen, z. B. wenn eine Anwendung eine Datei schreibt und danach den Zugriff darauf beendet.--format "%w%f"
Gibt an, wie das Ausgabeformat aussehen soll:%w
steht für das überwachte Verzeichnis (Watch-Directory).%f
steht für den Dateinamen innerhalb des überwachten Verzeichnisses.- Zusammen ergibt das den vollständigen Pfad der Datei, die geändert wurde.
"$WATCH_DIR"
Die Variable$WATCH_DIR
enthält das Verzeichnis, das überwacht werden soll.
Erklärung der Optionen von ocrmypdf:
--force-ocr
- Erzwingt eine Texterkennung für jede Seite, selbst wenn das PDF bereits durchsuchbaren Text enthält.
- Der vorhandene Text wird entfernt und durch den neuen OCR-Text ersetzt.
-l deu,eng
- Legt die Sprache für die OCR-Erkennung auf Deutsch und Englisch (
deu,eng
) fest.
- Legt die Sprache für die OCR-Erkennung auf Deutsch und Englisch (
--rotate-pages
- Erkennt automatisch die richtige Ausrichtung von Seiten und dreht sie falls nötig.
--deskew
- Richtet schief eingescannten Text gerade aus (Deskeewing).
- Nützlich für gescannte Dokumente, die leicht schräg sind.
--clean
- Führt eine Bildbereinigung durch, um Rauschen und Artefakte aus Scans zu entfernen.
- Verbessert die Lesbarkeit und OCR-Erkennung.
--output-type pdfa
- Erstellt ein PDF/A-Dokument (archivtaugliches Format).
- PDF/A sichert langfristige Lesbarkeit, indem es eingebettete Schriftarten und andere Anforderungen erfüllt.
Das Skript kombiniert das Erstellungsdatum der Datei mit einer KI-generierten Überschrift, um einen strukturierten Dateinamen zu erzeugen:
Beispiel:
- Originaldatei:
Scan_0001.pdf
- Nach der Verarbeitung:
20250213_153045_Umsatzsteuererklärung_2024.pdf
Den gleichen Überwachungsmechanismus setze ich auch für amtliche Dokumente ein, die in einen anderen Ordner gescant werden. Hier gehe ich jedoch noch einen Schritt weiter: Der Text wird in Tokens umgewandelt und in einer QuadrantDB abgelegt. Dadurch kann ich später gezielt Fragen an meine Dokumente stellen – etwa: "Wie hat sich meine Grundsteuer in den letzten zehn Jahren entwickelt? Erstelle dazu eine Tabelle in Markdown."
Autostart
Damit beim Start meines LXC-Containers gleich das Überwachungs-Script mitgestartet wird, packe ich diese Zeile in die /etc/crontab
:
@reboot root /usr/local/bin/check_pdf_ocr > /dev/null 2>&1 &
Mit diesem kleinen Script merkt ein Anwender nicht, dass im Hintergrund das PDF-Dokument mit einem neuen Text-Layer angereichert wurde.
Fazit
Mit ein paar cleveren technischen Kniffen habe ich mir zusätzlichen Komfort geschaffen. Einerseits konnte ich eine fehlende Funktion nachrüsten, andererseits entstand dabei ein praktischer Nebeneffekt: Amtliche Schreiben werden nun automatisch in die Datenbank meiner KI überführt und können dort in Ruhe verarbeitet und analysiert werden.