8.2 KiB
ORC Renaming
Datenschutzfreundliche Verarbeitung gescannter Eingangspost:
- PDFs per Nextcloud-WebDAV herunterladen
- vorhandenen OCR-Text lokal auslesen
- bei Bedarf die erste PDF-Seite lokal rendern und visuell analysieren
- Rechnungen und Korrespondenz mit Regeln und optional lokalem Ollama klassifizieren
- kontrollierte Dateinamen erzeugen
- Originalname, Ergebnis, Sicherheit und Fehler in SQLite und Excel protokollieren
- Ergebnisse zurück nach Nextcloud übertragen
Die Schreibweise orc-renaming folgt dem Namen des bestehenden Repositorys. Inhaltlich
geht es um OCR-Dokumente.
Dateinamensregeln
yymmdd_RE_Firma-Immobilie.pdf
yymmdd_RE_Firma-priv.pdf
yymmdd_Firma-Topic.pdf
Das verwendete Datum ist bei Rechnungen das Rechnungsdatum, ansonsten das
Brief-/Dokumentdatum. Kann das System ein Pflichtfeld nicht sicher bestimmen, kommt
das Dokument in manuell-pruefen. Eine optionale Privat-Fallback-Regel greift nur,
wenn kein Immobilienmerkmal gefunden wurde und keine Firmenregel dies verbietet.
Sicherheitsprinzip
dry_run ist in der Beispielkonfiguration eingeschaltet. In diesem Modus werden PDFs
heruntergeladen und analysiert, aber keine PDFs auf Nextcloud hochgeladen und keine
Originale verschoben. Für eine einfache Diagnose wird nur protokoll.xlsx nach
Nextcloud geladen, sofern upload_excel_in_dry_run: true gesetzt ist. Das Protokoll
entsteht zusätzlich lokal unter state/protokoll.xlsx.
Erst nach Prüfung der Namensvorschläge sollte in config.yaml stehen:
processing:
dry_run: false
Zugangsdaten gehören ausschließlich in Umgebungsvariablen. Für Nextcloud empfiehlt
sich ein eigenes App-Passwort mit Zugriff nur auf den vorgesehenen Bereich.
Umgebungsvariablen für HTTP-Proxys werden standardmäßig ignoriert (trust_env: false),
damit interne Dokumentdaten nicht unbeabsichtigt über einen Proxy laufen.
Ablauf
- Die oberste Ebene von
input_folderwird nach PDFs durchsucht. - Jede Datei wird lokal in einem temporären Arbeitsverzeichnis verarbeitet.
- Regeln suchen Rechnungsmerkmale, Datum, Betreff, Topics, Firmen und Immobilien.
- Sind Angaben unvollständig oder unsicher, wird zunächst das schnelle lokale Ollama-Modell mit OCR-Text und einem Bild der ersten PDF-Seite befragt.
- Bleibt dessen Ergebnis unsicher, wird optional ein größeres Fallback-Modell genutzt.
- Nur vollständige Ergebnisse oberhalb von
confidence_thresholdwerden automatisch nachoutput_foldergeladen. - Unsichere Ergebnisse landen mit dem Präfix
PRUEFEN_inreview_folder. - Nach erfolgreichem Upload wird das Original optional nach
archive_folderverschoben. protokoll.xlsxwird im Ausgabeordner aktualisiert.
SHA-256-Prüfsummen und SQLite verhindern, dass erfolgreich verarbeitete Inhalte
erneut verarbeitet werden. Bestehende Zieldateien werden nicht überschrieben; bei
Kollisionen wird _02, _03 usw. ergänzt. Eine Prozesssperre verhindert parallele
Läufe auf derselben Installation.
Installation auf einer Linux-VM
Voraussetzungen:
- Debian/Ubuntu oder vergleichbares Linux
- Python 3.11 oder neuer
- Netzwerkzugriff auf Nextcloud
- optional Netzwerkzugriff auf den internen Ollama-Host
git clone https://gitea.muehlberger.net/JMORG/orc-renaming.git
cd orc-renaming
python3 -m venv .venv
.venv/bin/pip install .
cp config.example.yaml config.yaml
cp .env.example .env
config.yaml mit den Nextcloud-Pfaden, Immobilien, Firmen und dem Ollama-Host
ausfüllen. Anschließend das Nextcloud-Passwort setzen:
export NEXTCLOUD_PASSWORD='NEXTCLOUD-APP-PASSWORT'
.venv/bin/orc-renaming --config config.yaml check-config
.venv/bin/orc-renaming --config config.yaml run
Die Shell-History kann Passwörter speichern. Im Dauerbetrieb deshalb die
Environment-Datei aus dem systemd-Beispiel verwenden und auf Dateirechte 0600
setzen.
Ollama
Voreingestellt ist:
ollama:
enabled: true
base_url: "http://ollama.intern:11434"
model: "qwen3.5:4B"
fallback_model: "qwen3.5:9b"
think: false
keep_alive: "10m"
context_tokens: 8192
max_output_tokens: 700
json_repair_attempts: 1
json_repair_model: "qwen3.5:4B"
vision_enabled: true
vision_dpi: 144
vision_image_format: "jpeg"
vision_jpeg_quality: 80
max_text_characters: 16000
Die Anwendung nutzt /api/chat, deaktiviertes Thinking, Temperatur 0 und ein festes
JSON-Schema. Das Schema wird sowohl im API-Feld format als auch ausdrücklich im
Prompt übergeben. Reichen die Regeln nicht aus, wird die erste PDF-Seite mit 144 DPI
als JPEG gerendert und zusammen mit dem OCR-Text an das lokale Ollama übertragen. Der
OCR-Text dient dabei als Ergänzung; das Bild bewahrt Briefkopf, Spalten und räumliche
Zuordnung. Reichen die Regeln bereits für ein vollständiges, sicheres Ergebnis aus,
wird Ollama nicht aufgerufen und es wird auch kein Seitenbild erzeugt.
Antwortet das Modell trotzdem mit Fließtext oder einem fremden JSON-Schema, wird seine
Antwort einmal ohne Bild durch das schnelle json_repair_model in das verbindliche
Schema überführt. Erst wenn auch das nicht zu einem vollständigen, hinreichend sicheren
Ergebnis führt, wird das 9B-Fallback gestartet.
Unvollständige JSON-Antworten werden nicht mehr als technischer Totalausfall behandelt: vorhandene Felder werden mit reduzierter Sicherheit übernommen und mit sicheren Regeltreffern kombiniert.
Wenn der Ollama-Host nicht erreichbar ist, wird die Datei nicht falsch benannt: Unvollständige Ergebnisse gehen in die manuelle Prüfung und der Fehler erscheint im Protokoll.
Stammdaten und Privat-Fallback
Kurze, eindeutige Marker sind robuster gegen OCR-Umbrüche als vollständige Anschriften:
properties:
- id: "WH1"
name: "Wohnhaus Musterstraße"
markers:
- "Musterstraße 12"
- "47110815"
- "DE000123456"
Firmen können eine Standardzuordnung erhalten. Eine immobilientypische Firma kann einen zwingenden Objektmarker verlangen:
companies:
- name: "Hausverwaltung-Muster"
aliases:
- "Hausverwaltung Muster GmbH"
default_scope: "property"
default_property_id: null
require_property_match: true
recipient_markers enthält die normale Privatadresse. Sie ist allein kein Beweis für
private Post, bestätigt aber den konfigurierbaren Fallback, wenn kein Objektmarker
vorhanden ist. private_markers darf deshalb nur exklusive private Vertrags-,
Versicherungs- oder Kundennummern enthalten.
Wiederkehrende Topics können ebenfalls ohne LLM erkannt werden:
topics:
- name: "Eigentuemerversammlung"
markers:
- "Eigentümerversammlung"
- "Einladung zur Eigentümerversammlung"
Das Excelprotokoll dokumentiert neben der Entscheidungsmethode auch, welche LLM-Modelle tatsächlich verwendet wurden.
Docker
Nach dem Anlegen von .env und config.yaml:
mkdir -p state work
sudo chown 10001:10001 state work
docker compose build
docker compose run --rm app
Der Container führt genau einen Lauf aus. Für einen regelmäßigen Betrieb kann ein
systemd-Timer docker compose run --rm app aufrufen. Auf einer kleinen VM ist die
direkte Python-/systemd-Installation meist übersichtlicher.
systemd-Timer
Die Dateien in deploy/systemd/ sind Vorlagen. Sie gehen von folgenden Pfaden aus:
- Anwendung:
/opt/orc-renaming - Konfiguration:
/etc/orc-renaming.yaml - Geheimnisse:
/etc/orc-renaming.env - Zustandsdaten:
/var/lib/orc-renaming
In der produktiven Konfiguration deshalb setzen:
processing:
state_directory: "/var/lib/orc-renaming"
work_directory: "/var/lib/orc-renaming/work"
Danach als root:
useradd --system --home /var/lib/orc-renaming --create-home orc-renaming
install -m 0644 deploy/systemd/orc-renaming.service /etc/systemd/system/
install -m 0644 deploy/systemd/orc-renaming.timer /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now orc-renaming.timer
Status und Logs:
systemctl list-timers orc-renaming.timer
journalctl -u orc-renaming.service
Entwicklung
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/pytest
Noch nicht Teil des ersten MVP:
- OCR für bildbasierte PDFs ohne eingebettete Textebene
- visuelle Analyse einzelner Seiten durch ein multimodales Modell
- Weboberfläche für Freigaben
- automatische Benachrichtigungen