253 lines
8.2 KiB
Markdown
253 lines
8.2 KiB
Markdown
# 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
|
|
|
|
```text
|
|
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:
|
|
|
|
```yaml
|
|
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
|
|
|
|
1. Die oberste Ebene von `input_folder` wird nach PDFs durchsucht.
|
|
2. Jede Datei wird lokal in einem temporären Arbeitsverzeichnis verarbeitet.
|
|
3. Regeln suchen Rechnungsmerkmale, Datum, Betreff, Topics, Firmen und Immobilien.
|
|
4. 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.
|
|
5. Bleibt dessen Ergebnis unsicher, wird optional ein größeres Fallback-Modell genutzt.
|
|
6. Nur vollständige Ergebnisse oberhalb von `confidence_threshold` werden automatisch
|
|
nach `output_folder` geladen.
|
|
7. Unsichere Ergebnisse landen mit dem Präfix `PRUEFEN_` in `review_folder`.
|
|
8. Nach erfolgreichem Upload wird das Original optional nach `archive_folder`
|
|
verschoben.
|
|
9. `protokoll.xlsx` wird 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```yaml
|
|
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`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```yaml
|
|
processing:
|
|
state_directory: "/var/lib/orc-renaming"
|
|
work_directory: "/var/lib/orc-renaming/work"
|
|
```
|
|
|
|
Danach als `root`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
systemctl list-timers orc-renaming.timer
|
|
journalctl -u orc-renaming.service
|
|
```
|
|
|
|
## Entwicklung
|
|
|
|
```bash
|
|
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
|