Files
pdf-ocr-hotfolder/AI_AGENT_BRIEFING.md
techadmin 985a33d3f9 feat: Multi-Instanz-Support via systemd Template-Unit (v0.2.0)
- pdf-ocr-hotfolder@<name>.service mit Config pro Instanz
- install.sh als Instanz-Manager: erkennt bestehende, fragt nach weiteren
- Optional eigener Service-User pro Instanz (systemd drop-in)
- update.sh stoppt/startet alle aktiven Instanzen automatisch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 14:31:58 +02:00

6.0 KiB

AI Agent Briefing — PDF OCR Hotfolder

Zuletzt aktualisiert: 2026-04-08 Version: 0.2.0 Status: Multi-Instanz-Support, nicht produktiv getestet

🎯 Projektziel

Eingehende gescannte PDFs werden automatisch durch OCR (ocrmypdf + Tesseract) in durchsuchbare PDFs (optional PDF/A) umgewandelt und nach Wahl in einen Ordner / Nextcloud / per SFTP weitergegeben. Ersetzt das alte Bash-Tool pdf-tool (im Workspace).

📁 Projekt-Struktur

pdf-ocr-hotfolder/
├── pdf_ocr_hotfolder/
│   ├── __init__.py        # Versionsstring
│   ├── __main__.py        # CLI-Entrypoint (argparse, --once, --config)
│   ├── config.py          # TOML-Loader, Dataclasses
│   ├── service.py         # Hauptservice (watchdog + ThreadPool)
│   ├── processor.py       # ocrmypdf + veraPDF
│   └── uploaders.py       # folder, nextcloud (WebDAV), sftp, email
├── systemd/
│   └── pdf-ocr-hotfolder@.service  # systemd Template-Unit (Instanz = %i)
├── config.example.toml
├── install.sh             # Interaktiver Installer
├── update.sh              # Update aus Repo
├── requirements.txt
├── VERSION
├── CHANGELOG.md
└── README.md

🔧 Stack

Komponente Technologie
Sprache Python 3.11+ (für tomllib aus stdlib)
OCR ocrmypdf (als Library, nicht via Subprozess)
Engine Tesseract
Watcher watchdog
HTTP requests (Nextcloud WebDAV)
SFTP paramiko
Email smtplib (stdlib)
Service systemd

🖥️ Installations-Layout (Multi-Instanz)

Pfad Inhalt
/opt/pdf-ocr-hotfolder/ Code + venv (für alle Instanzen gemeinsam)
/etc/pdf-ocr-hotfolder/<instanz>.toml Config pro Instanz (mode 640, root:)
/etc/systemd/system/pdf-ocr-hotfolder@.service Template-Unit
/etc/systemd/system/pdf-ocr-hotfolder@<instanz>.service.d/user.conf Drop-in für abweichenden User (optional)
/var/lib/pdf-ocr-hotfolder/<instanz>/{incoming,working,outgoing,error}/ Daten pro Instanz
/var/log/pdf-ocr-hotfolder/ Logs
/var/backups/pdf-ocr-hotfolder/ Update-Backups

👤 Service-User

  • Basis-Install legt Default-User pdfocr an (als System-User, falls nicht schon vorhanden)
  • Beim Anlegen einer Instanz fragt der Installer nach dem Service-User (default pdfocr)
  • Wird ein abweichender User gewählt, wird ein systemd-Drop-in erstellt (pdf-ocr-hotfolder@<instanz>.service.d/user.conf) mit User=/Group= Override
  • Existierende User (lokal oder AD via SSSD/Winbind) werden übernommen, primäre Gruppe via id -gn ermittelt
  • Bei AD-Usern mit lokaler UID werden Datei-Berechtigungen über die UID gesetzt — transparent

🗂️ Instanz-Management

install.sh ist gleichzeitig Installer und Instanz-Manager:

  • Erster Lauf: Basis-Install + erste Instanz anlegen (Pflicht)
  • Folgender Lauf: Basis-Install wird übersprungen, bestehende Instanzen werden gelistet, weitere Instanzen können ergänzt werden
  • Eingaben pro Instanz: Name ([a-z0-9-]+), Basis-Pfad (default /var/lib/pdf-ocr-hotfolder/<name>), Service-User
  • config.toml wird aus config.example.toml mit sed-substituierten Pfaden generiert
  • Instanz wird sofort enable --now gestartet

Manuelles Löschen einer Instanz:

systemctl disable --now pdf-ocr-hotfolder@<name>
rm /etc/pdf-ocr-hotfolder/<name>.toml
rm -rf /etc/systemd/system/pdf-ocr-hotfolder@<name>.service.d
systemctl daemon-reload
# Datenverzeichnis /var/lib/pdf-ocr-hotfolder/<name> manuell aufräumen

🔄 Update-Verhalten

update.sh:

  1. Ermittelt alle aktiven pdf-ocr-hotfolder@*.service Units
  2. Stoppt diese
  3. Backup nach /var/backups/pdf-ocr-hotfolder/
  4. Kopiert Code + requirements + VERSION + config.example aus dem Repo
  5. pip install --upgrade im venv
  6. Aktualisiert Template-Unit + daemon-reload
  7. Startet alle zuvor aktiven Instanzen wieder
  8. Exit 1 wenn eine Instanz nicht mehr hochkommt

Config-Dateien werden nie überschrieben.

🔄 Verarbeitungs-Flow

  1. watchdog triggert auf Datei-Event in incoming/
  2. _wait_until_stable() wartet, bis Datei nicht mehr wächst (Scanner schreibt mehrmals)
  3. Move nach working/
  4. ocrmypdf.ocr() als Library-Call (kein Subprozess-Start pro PDF — schneller)
  5. Optional: veraPDF-Validierung (CLI-Subprozess)
  6. Move nach outgoing/ als OCR_<originalname>.pdf
  7. Aktive Upload-Targets ausführen (folder/nextcloud/sftp)
  8. Optional E-Mail-Notify

Fehler → Move nach error/, Service läuft weiter (kein exit 1 wie im alten Bash-Tool).

🧠 Performance-Entscheidungen

  • ocrmypdf als Library statt subprocess: spart Python-Interpreter-Start pro PDF
  • ThreadPool mit max_workers (default 2) — selbst wenn selten >1 PDF gleichzeitig kommt, blockiert ein langsamer Scan keinen schnellen
  • --jobs an ocrmypdf: Tesseract parallelisiert Seiten innerhalb eines PDFs
  • skip_text=True: bereits OCR-haltige Seiten werden nicht neu verarbeitet
  • Stabilitäts-Check statt magic-file new (alte Bash-Krücke)
  • veraPDF nur wenn enabled=true (JVM-Start ist teuer)

🛠️ Entwicklung

Lokaler Test ohne Installation:

cd ~/dev/gitea.sonith.de/pdf-ocr-hotfolder
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp config.example.toml /tmp/config.toml
# Pfade in /tmp/config.toml auf Test-Verzeichnisse anpassen
python -m pdf_ocr_hotfolder --config /tmp/config.toml

📋 Roadmap / TODO

  • Tests (pytest) für processor und uploaders
  • Prometheus-Metriken (verarbeitete PDFs, Fehlerquote, Laufzeit)
  • CLI-Subkommandos: pdf-ocr-hotfolder reprocess <error-file>
  • Optional: S3/MinIO Upload-Target
  • Docker-Image für Setups ohne systemd

🔑 Repo

📞 Kontakt

Maintainer: Dominik Höfling (Sonith GmbH)