Files
ai.bewerbung---vectorize-do…/README.md
T
cbazza 4bf034b2a5 Add sync_missing_docs.py: Dokumentenabgleich job_matching -> apply4jobs.de
- Vergleicht profile_documents (NAS) gegen anythingllm_vectors (apply4jobs.de) per filename/title
- Embeddings werden für die Zielseite neu berechnet (multilingual-e5-small, 384 Dim),
  da OpenAI-1536-Dim-Vektoren aus job_matching inkompatibel sind
- diff/sync Subcommands, --dry-run, --workspace-id, --force (Update/Re-Sync bestehender Titel)
- JM_DB_HOST auf Tailscale-IP umgestellt (100.81.64.115) für Erreichbarkeit außerhalb des Heimnetzes
- README um Tool 4 ergänzt und Hetzner->DO-Umzug dokumentiert
2026-07-28 17:25:40 +02:00

12 KiB
Raw Blame History

RAG Ingestion Tools

Lokale Python-Tools zum Importieren von Dokumenten in pgvector-Vektordatenbanken. Vier eigenständige Scripts für unterschiedliche Zielplattformen und Anwendungsfälle, plus zwei gemeinsame Module für Extraktion und KI-Normalisierung.


Übersicht & Zielplattformen

Tool Wofür? Zielplattform Verbindung .env-Datei
ingest_V2.py Fremde Dokumente, Scans, Bilder — mit automatischer Strukturierung apply4jobs.de · anythingllm DB SSH-Tunnel .env.ingest
ingest_anythingllm.py Eigene, bereits strukturierte Dokumente (Templates) apply4jobs.de · anythingllm DB SSH-Tunnel .env.ingest
ingest_job_matching.py Stellenanzeigen & Profil-Dokumente für Job-Matching NAS · job_matching DB Direkt (Port 5433) .env.job_matching
sync_missing_docs.py Dokumentenabgleich: fehlende/aktualisierte Profil-Dokumente von job_matching nach apply4jobs.de spiegeln NAS → apply4jobs.de Direkt + SSH-Tunnel .env.ingest + .env.job_matching

Wann welches Tool?

  • Du hast ein fremdes CV, einen Scan oder ein Bildingest_V2.py (OCR + KI-Normalisierung)
  • Du hast ein eigenes, fertiges Markdown-Dokument (z.B. ausgefülltes Template) → ingest_anythingllm.py
  • Du willst Stellenanzeigen oder Profil-Dokumente für Job-Matching einpflegen → ingest_job_matching.py
  • Du willst, dass Dokumente aus der Job-Matching-Plattform auch in der apply4jobs.de-RAG-DB verfügbar sind (Profil-Kern, Skill-Matrix, Projektbeschreibungen etc.) → sync_missing_docs.py

Dateistruktur

rag-ingestion/
├── ingest_V2.py             Vollpipeline v2: OCR + KI-Normalisierung (→ apply4jobs.de)
├── ingest_anythingllm.py    Einfaches Script v1: nur MD/TXT/PDF (→ apply4jobs.de)
├── ingest_job_matching.py   Job-Matching Script: direkt auf NAS (→ NAS Port 5433)
├── sync_missing_docs.py     Abgleich job_matching → apply4jobs.de (fehlende/geänderte Dokumente spiegeln)
│
├── extractor.py             Modul: Text-Extraktion + OCR (wird von ingest_V2 genutzt)
├── normalizer.py            Modul: KI-Normalisierung via Claude (wird von ingest_V2 genutzt)
│
├── architektur/
│   └── ocr_rag_pipeline.svg Architektur-Diagramm der ingest_V2 Pipeline
│
├── templates/
│   ├── *_TEMPLATE.md        Ziel-Strukturvorlagen (leer)
│   └── ausgefuellt/         Ausgefüllte Referenzbeispiele (Few-Shot für KI, nicht in Git)
│
├── .env.ingest              Secrets für ingest_V2.py + ingest_anythingllm.py (nicht in Git)
├── .env.job_matching        Secrets für ingest_job_matching.py (nicht in Git)
└── .env.example             Vorlage für .env.ingest

Tool 1: ingest_V2.py — Vollpipeline mit OCR + KI-Normalisierung

Verwendungszweck: Verarbeitung beliebiger Fremddokumente — gescannte PDFs, Bilder, DOCX-Dateien, fremde CVs — die zunächst per OCR extrahiert und dann via Claude KI automatisch in die einheitliche Template-Struktur transformiert werden.

Zielplattform: pgvector-Datenbank (anythingllm) für ai.apply4jobs.de via SSH-Tunnel.

Hinweis (Stand 2026-07): Server + Domain wurden von Hetzner auf einen Digital-Ocean- Droplet umgezogen. SSH_HOST in .env.ingest muss auf die aktuelle DO-IP zeigen — die alte Hetzner-IP (46.225.225.226) ist nicht mehr gültig.

Benötigt: extractor.py und normalizer.py im gleichen Verzeichnis.

Architektur

OCR → RAG Ingestion Pipeline

Unterstützte Formate

.md .txt .pdf .docx .png .jpg .jpeg .tif .tiff .bmp .webp

Voraussetzungen

# System-Tools (einmalig)
brew install tesseract tesseract-lang poppler

# Python-Pakete
pip install -r requirements.txt

# .env.ingest konfigurieren
cp .env.example .env.ingest
nano .env.ingest   # ANTHROPIC_API_KEY eintragen

Verwendung

# Einzelne Datei importieren (mit KI-Normalisierung)
python ingest_V2.py file ~/Downloads/fremdes_cv.pdf

# Dry-Run: erst testen, nichts in DB schreiben
python ingest_V2.py file ~/Desktop/scan.png --dry-run

# Dry-Run + normalisiertes Markdown automatisch speichern (<dateiname>_normalized.md)
python ingest_V2.py file ~/Downloads/cv.pdf --dry-run

# Dry-Run + normalisiertes Markdown in bestimmte Datei speichern
python ingest_V2.py file ~/Downloads/cv.pdf --dry-run --output ~/Desktop/cv_normalisiert.md

# Ohne KI-Normalisierung (für bereits strukturierte Dokumente)
python ingest_V2.py file ~/templates/ausgefuellt/mein_cv.md --no-normalize

# Ganzes Verzeichnis importieren
python ingest_V2.py dir ~/Dokumente/bewerbungsunterlagen/ --force

# Ordner live beobachten (neue Dateien automatisch verarbeiten)
python ingest_V2.py watch ~/Desktop/scan-eingang/

Datenbank verwalten

# Alle importierten Dokumente anzeigen
# Zeigt: Titel, Dokumenttyp, Qualitäts-Score, Format, Anzahl Chunks, Datum
python ingest_V2.py list

# Ausgabe-Beispiel:
#   Titel                                         Typ             Score    Fmt  Chunks  Datum
#   ──────────────────────────────────────────────────────────────────────────────────────────
#   Arbeitszeugnis Sopra Financial Technology...  arbeitszeugnis    95%   .pdf       3  2026-04-28

# Einzelnes Dokument löschen (alle Chunks)
# Hinweis: Titel = exakter Dateiname wie beim Import
python ingest_V2.py delete "Arbeitszeugnis Sopra Financial Technology GmbH.pdf"

Flags

Flag Beschreibung
--force Bestehende Chunks überschreiben
--no-normalize KI-Normalisierung überspringen
--dry-run Nur extrahieren + normalisieren, nicht in DB speichern
--output <pfad> Normalisiertes Markdown als Datei speichern (nur mit --dry-run)
--quality-min 0.5 Mindest-Qualitäts-Score (0.01.0, Standard: 0.0)

KI-Normalisierung (normalizer.py)

  • Typ-Erkennung: Claude Haiku (günstig + schnell)
  • Transformation: Claude Sonnet
  • Fehlende Felder werden mit [FEHLT] markiert, nie halluziniert
  • Qualitäts-Score: 0.01.0 (Anteil befüllter Pflichtfelder)

Erkannte Typen: arbeitszeugnis, cv, lebenslauf, anschreiben, projektbeschreibung, karriereziele, technologie, zertifikate, referenzen, elevatorpitch, rahmenbedingungen, zielstellen

OCR-Pipeline (extractor.py)

  1. pypdf versucht Text zu extrahieren
  2. Weniger als 150 Zeichen → OCR-Fallback via Tesseract (300 DPI)
  3. Bilder (PNG, JPG etc.) → direkt OCR

Tool 2: ingest_anythingllm.py — Einfaches Ingestion-Script (v1)

Verwendungszweck: Schnelles Einpflegen von eigenen, bereits fertig strukturierten Dokumenten — z.B. ausgefüllte Templates, eigene Markdown-Dateien oder einfache PDFs die keiner OCR oder KI-Normalisierung bedürfen.

Zielplattform: pgvector-Datenbank (anythingllm) für ai.apply4jobs.de via SSH-Tunnel. Gleiche Zieldatenbank wie ingest_V2.py — unterschiedlicher Verarbeitungsweg.

Unterstützte Formate

.md .txt .pdf

Verwendung

python ingest_anythingllm.py file ~/Dokumente/Lebenslauf.md
python ingest_anythingllm.py file ~/Dokumente/Lebenslauf.md --force
python ingest_anythingllm.py dir ~/Dokumente/bewerbung/
python ingest_anythingllm.py list

Tool 3: ingest_job_matching.py — Job-Matching-Datenbank (NAS)

Verwendungszweck: Einpflegen von Stellenanzeigen und Profil-Dokumenten in die dedizierte Job-Matching-Datenbank. Diese Datenbank wird von einem separaten Job-Matching-Workflow genutzt um Stellenanzeigen mit dem eigenen Profil abzugleichen.

Zielplattform: pgvector-Datenbank (job_matching) direkt auf dem NAS (Port 5433) — kein SSH-Tunnel erforderlich.

JM_DB_HOST steht auf die Tailscale-IP 100.81.64.115, damit die Verbindung auch außerhalb des Heimnetzes funktioniert. Im lokalen WLAN geht alternativ auch die LAN-IP 192.168.178.128 (kann sich per DHCP ändern).

Embeddings via OpenAI text-embedding-3-small (1536 Dimensionen, kostenpflichtig).

Verwendung

python ingest_job_matching.py file ~/Dokumente/stellenanzeige.pdf
python ingest_job_matching.py dir ~/Dokumente/stellen/
python ingest_job_matching.py list
python ingest_job_matching.py clear "stellenanzeige.pdf"

Tool 4: sync_missing_docs.py — Dokumentenabgleich job_matching → apply4jobs.de

Verwendungszweck: Job-Matching-Plattform und ai.apply4jobs.de/apply4jobs.de nutzen zwei getrennte pgvector-Datenbanken (NAS vs. DO-Droplet). Dieses Script gleicht sie ab, damit Profil-Dokumente, die in der Job-Matching-Plattform erstellt/hochgeladen wurden (Skill-Matrix, Rahmenbedingungen, Zielstellen-Profil, Muster-Anschreiben, Elevator-Pitch, Projektbeschreibungen, CV, Arbeitszeugnisse etc.), auch für die Webseiten-RAG verfügbar sind.

Matching-Kriterium: filename (job_matching.profile_documents) ↔ metadata->>'title' (anythingllm_vectors).

Embeddings: werden für die Zielseite immer neu berechnet (lokal, multilingual-e5-small, 384 Dim) — die OpenAI-1536-Dim-Vektoren aus job_matching sind mit der 384-Dim-Spalte in anythingllm_vectors nicht kompatibel. Nur der Text wird übernommen.

Voraussetzung: benötigt beide .env-Dateien (.env.ingest für die SSH-Tunnel-Verbindung zum Ziel, .env.job_matching für die Quelle) sowie sentence-transformers (aus requirements.txt).

Verwendung

# Nur anzeigen, welche Dokumente in apply4jobs.de fehlen (kein Schreibzugriff)
python sync_missing_docs.py diff

# Optional auf einen Workspace eingrenzen
python sync_missing_docs.py diff --workspace-id 1

# Fehlende Dokumente übertragen
python sync_missing_docs.py sync --dry-run   # Simulation, nichts wird geschrieben
python sync_missing_docs.py sync              # tatsächlich schreiben

# Auch bereits vorhandene Titel neu einlesen (Update/Re-Sync):
# löscht die alten Chunks in anythingllm_vectors und ersetzt sie mit dem
# aktuellen Stand aus job_matching
python sync_missing_docs.py sync --force
python sync_missing_docs.py sync --force --dry-run

Flags

Flag Beschreibung
--workspace-id <id> Nur Dokumente eines bestimmten Workspace aus job_matching berücksichtigen
--dry-run Nur anzeigen, nichts in die Zieldatenbank schreiben
--force Auch bereits vorhandene Titel neu einlesen (löscht + ersetzt statt nur zu ergänzen)

Gemeinsame Infrastruktur

Embedding-Modelle

Tool Modell Dimensionen Kosten
ingest_V2.py multilingual-e5-small (lokal) 384 kostenlos
ingest_anythingllm.py multilingual-e5-small (lokal) 384 kostenlos
ingest_job_matching.py OpenAI text-embedding-3-small 1536 kostenpflichtig
sync_missing_docs.py multilingual-e5-small (lokal, für Ziel-DB neu berechnet) 384 kostenlos

Umgebungsvariablen

Datei Verwendet von Inhalt
.env.ingest ingest_V2.py, ingest_anythingllm.py, sync_missing_docs.py ANTHROPIC_API_KEY, SSH, DB
.env.job_matching ingest_job_matching.py, sync_missing_docs.py OPENAI_API_KEY, NAS-DB

Setup (komplett, einmalig)

cd ~/Projekte/rag-ingestion
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
brew install tesseract tesseract-lang poppler   # nur für ingest_V2.py
cp .env.example .env.ingest
nano .env.ingest   # ANTHROPIC_API_KEY + SSH + DB-Zugangsdaten eintragen