orc-renaming/README.md

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