Compare commits
2 Commits
d26a9f60ab
...
85fe0a73d6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85fe0a73d6 | ||
|
|
eaade3cad2 |
@@ -1435,6 +1435,7 @@ const TYPE_LABELS: Record<string, string> = {
|
|||||||
// Industry/Sector definitions for the regulation map
|
// Industry/Sector definitions for the regulation map
|
||||||
const INDUSTRIES = [
|
const INDUSTRIES = [
|
||||||
{ id: 'all', name: 'Alle Unternehmen', icon: '🏢', description: 'Grundlegende Anforderungen fuer alle' },
|
{ id: 'all', name: 'Alle Unternehmen', icon: '🏢', description: 'Grundlegende Anforderungen fuer alle' },
|
||||||
|
{ id: 'maschinenbau', name: 'Maschinenbau', icon: '⚙️', description: 'Maschinen- und Anlagenbauer, Automatisierung' },
|
||||||
{ id: 'health', name: 'Gesundheitswesen', icon: '🏥', description: 'Krankenhaeuser, DiGA, Medizintechnik' },
|
{ id: 'health', name: 'Gesundheitswesen', icon: '🏥', description: 'Krankenhaeuser, DiGA, Medizintechnik' },
|
||||||
{ id: 'finance', name: 'Finanzsektor', icon: '🏦', description: 'Banken, Versicherungen, Zahlungsdienstleister' },
|
{ id: 'finance', name: 'Finanzsektor', icon: '🏦', description: 'Banken, Versicherungen, Zahlungsdienstleister' },
|
||||||
{ id: 'ecommerce', name: 'E-Commerce', icon: '🛒', description: 'Online-Shops, Marktplaetze' },
|
{ id: 'ecommerce', name: 'E-Commerce', icon: '🛒', description: 'Online-Shops, Marktplaetze' },
|
||||||
@@ -1448,19 +1449,36 @@ const INDUSTRIES = [
|
|||||||
|
|
||||||
// Mapping: Which regulations apply to which industries
|
// Mapping: Which regulations apply to which industries
|
||||||
const INDUSTRY_REGULATION_MAP: Record<string, string[]> = {
|
const INDUSTRY_REGULATION_MAP: Record<string, string[]> = {
|
||||||
all: ['GDPR', 'EPRIVACY', 'TDDDG'],
|
// Grundlage fuer ALLE Unternehmen in DE/EU
|
||||||
health: ['GDPR', 'TDDDG', 'BSI-TR-03161-1', 'BSI-TR-03161-2', 'BSI-TR-03161-3', 'NIS2', 'AIACT', 'PLD', 'EHDS'],
|
all: ['GDPR', 'EPRIVACY', 'TDDDG', 'BDSG_FULL', 'SCC', 'DPF'],
|
||||||
finance: ['GDPR', 'TDDDG', 'NIS2', 'EUCSA', 'DSA', 'AIACT', 'DPF', 'DORA', 'PSD2', 'AMLR', 'MiCA'],
|
// Maschinenbau — Kern-Zielgruppe: Maschinen- und Anlagenbauer mit Software/KI
|
||||||
ecommerce: ['GDPR', 'TDDDG', 'DSA', 'GPSR', 'EAA', 'PLD', 'DPF', 'PSD2',
|
maschinenbau: ['GDPR', 'TDDDG', 'BDSG_FULL', 'MACHINERY_REG', 'BLUE_GUIDE', 'CRA', 'NIS2', 'AIACT',
|
||||||
'DE_PANGV', 'DE_VSBG', 'DE_PRODHAFTG', 'DE_VERPACKG', 'DE_ELEKTROG', 'DE_BFSG', 'DE_UWG',
|
'PLD', 'GPSR', 'DATAACT', 'EUCSA', 'DE_PRODHAFTG', 'DE_ELEKTROG', 'DE_BATTDG'],
|
||||||
|
// Gesundheit: DiGA, Krankenhaeuser, Medizintechnik
|
||||||
|
health: ['GDPR', 'TDDDG', 'BDSG_FULL', 'BSI-TR-03161-1', 'BSI-TR-03161-2', 'BSI-TR-03161-3',
|
||||||
|
'NIS2', 'AIACT', 'PLD', 'EHDS', 'EUCSA', 'CRA'],
|
||||||
|
// Finanzen: Banken, Versicherungen, Zahlungsdienstleister
|
||||||
|
finance: ['GDPR', 'TDDDG', 'BDSG_FULL', 'NIS2', 'EUCSA', 'DSA', 'AIACT', 'DPF', 'DORA', 'PSD2',
|
||||||
|
'AMLR', 'MiCA', 'EAA', 'DE_HGB_RET', 'DE_AO_RET'],
|
||||||
|
// E-Commerce: Online-Shops, Marktplaetze, Verbraucherschutz
|
||||||
|
ecommerce: ['GDPR', 'TDDDG', 'BDSG_FULL', 'DSA', 'GPSR', 'EAA', 'PLD', 'DPF', 'PSD2', 'CRA',
|
||||||
|
'DE_BGB_AGB', 'DE_PANGV', 'DE_VSBG', 'DE_PRODHAFTG', 'DE_VERPACKG', 'DE_ELEKTROG', 'DE_BFSG', 'DE_UWG',
|
||||||
'E_COMMERCE_RL', 'VERBRAUCHERRECHTE_RL', 'WARENKAUF_RL', 'KLAUSEL_RL', 'UNLAUTERE_PRAKTIKEN_RL',
|
'E_COMMERCE_RL', 'VERBRAUCHERRECHTE_RL', 'WARENKAUF_RL', 'KLAUSEL_RL', 'UNLAUTERE_PRAKTIKEN_RL',
|
||||||
'PREISANGABEN_RL', 'OMNIBUS_RL', 'DIGITALE_INHALTE_RL'],
|
'PREISANGABEN_RL', 'OMNIBUS_RL', 'DIGITALE_INHALTE_RL'],
|
||||||
tech: ['GDPR', 'TDDDG', 'CRA', 'AIACT', 'DPF', 'SCC', 'DATAACT', 'DSM', 'MiCA'],
|
// Technologie: Software-Entwickler, SaaS, Cloud
|
||||||
iot: ['GDPR', 'CRA', 'GPSR', 'PLD', 'DATAACT', 'AIACT'],
|
tech: ['GDPR', 'TDDDG', 'BDSG_FULL', 'CRA', 'NIS2', 'AIACT', 'DPF', 'SCC', 'DATAACT', 'DSM',
|
||||||
ai: ['GDPR', 'AIACT', 'PLD', 'DSM', 'DATAACT'],
|
'MiCA', 'EUCSA', 'DE_URHG', 'DE_GESCHGEHG'],
|
||||||
kritis: ['GDPR', 'NIS2', 'EUCSA', 'CRA', 'AIACT', 'DORA'],
|
// IoT/Hardware: Geraetehersteller, Smart Devices, Embedded
|
||||||
media: ['GDPR', 'TDDDG', 'DSA', 'DSM', 'EAA', 'AIACT'],
|
iot: ['GDPR', 'TDDDG', 'CRA', 'GPSR', 'PLD', 'DATAACT', 'AIACT', 'MACHINERY_REG', 'BLUE_GUIDE',
|
||||||
public: ['GDPR', 'NIS2', 'EUCSA', 'EAA', 'DGA', 'AIACT', 'EHDS'],
|
'NIS2', 'DE_ELEKTROG', 'DE_PRODHAFTG', 'DE_BATTDG'],
|
||||||
|
// KI-Anbieter: KI-Entwickler und -Anwender
|
||||||
|
ai: ['GDPR', 'TDDDG', 'AIACT', 'PLD', 'DSM', 'DATAACT', 'CRA', 'EUCSA', 'DE_URHG'],
|
||||||
|
// KRITIS: Energie, Wasser, Transport
|
||||||
|
kritis: ['GDPR', 'TDDDG', 'BDSG_FULL', 'NIS2', 'EUCSA', 'CRA', 'AIACT', 'DORA', 'DATAACT'],
|
||||||
|
// Medien/Plattformen: Social Media, Content-Plattformen
|
||||||
|
media: ['GDPR', 'TDDDG', 'DSA', 'DSM', 'EAA', 'AIACT', 'DGA', 'DMA', 'DE_URHG'],
|
||||||
|
// Oeffentlicher Sektor: Behoerden, Verwaltung
|
||||||
|
public: ['GDPR', 'TDDDG', 'BDSG_FULL', 'NIS2', 'EUCSA', 'EAA', 'DGA', 'AIACT', 'EHDS', 'DATAACT'],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thematic groupings showing overlaps
|
// Thematic groupings showing overlaps
|
||||||
@@ -1497,8 +1515,8 @@ const THEMATIC_GROUPS = [
|
|||||||
id: 'product-safety',
|
id: 'product-safety',
|
||||||
name: 'Produktsicherheit & Haftung',
|
name: 'Produktsicherheit & Haftung',
|
||||||
color: 'bg-orange-500',
|
color: 'bg-orange-500',
|
||||||
regulations: ['CRA', 'PLD', 'GPSR', 'EAA'],
|
regulations: ['CRA', 'PLD', 'GPSR', 'EAA', 'MACHINERY_REG', 'BLUE_GUIDE'],
|
||||||
description: 'Sicherheitsanforderungen, CE-Kennzeichnung, Barrierefreiheit'
|
description: 'Sicherheitsanforderungen, CE-Kennzeichnung, Maschinenverordnung, Barrierefreiheit'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'finance',
|
id: 'finance',
|
||||||
|
|||||||
253
docs-src/services/klausur-service/OCR-Kombi-Pipeline.md
Normal file
253
docs-src/services/klausur-service/OCR-Kombi-Pipeline.md
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
# OCR Kombi Pipeline - Modulare 11-Schritt-Architektur
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Status:** Phase 1 implementiert (Grundgeruest + DB)
|
||||||
|
**URL:** https://macmini:3002/ai/ocr-kombi
|
||||||
|
|
||||||
|
## Uebersicht
|
||||||
|
|
||||||
|
Die OCR Kombi Pipeline ist der Nachfolger des OCR-Overlay-Monolithen (`/ai/ocr-overlay`).
|
||||||
|
Sie zerlegt den OCR-Prozess in **11 modulare Schritte** mit je einer eigenen Komponente
|
||||||
|
pro Frontend- und Backend-Datei. Ziel: schnelles Debugging, klare Verantwortlichkeiten,
|
||||||
|
Multi-Page-Dokument-Unterstuetzung.
|
||||||
|
|
||||||
|
**Primaerer Modus:** Kombi (PaddleOCR + Tesseract) — der einzige Modus, den der User nutzt.
|
||||||
|
|
||||||
|
### Warum ein Refactor?
|
||||||
|
|
||||||
|
| Problem (alt) | Loesung (neu) |
|
||||||
|
|----------------|---------------|
|
||||||
|
| `page.tsx` = 751-Zeilen-Monolith mit 3 Modi | `page.tsx` = ~140-Zeilen-Orchestrator, je 1 Datei pro Step |
|
||||||
|
| Upload, Orientierung und Page-Split in einem Step | 3 separate Steps mit eigener Logik |
|
||||||
|
| Keine Multi-Page-Dokument-Unterstuetzung | `document_group_id` + `page_number` auf DB-Ebene |
|
||||||
|
| OCR intransparent (eine Blackbox) | 3-Phasen-Fortschritt + Engine-Attribution pro Wort (geplant) |
|
||||||
|
| `grid_editor_api.py` = 1801 Zeilen | 4 Module + Orchestrator (geplant) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pipeline-Schritte
|
||||||
|
|
||||||
|
| # | Step | Frontend | Backend | Beschreibung |
|
||||||
|
|---|------|----------|---------|--------------|
|
||||||
|
| 1 | Upload | `StepUpload.tsx` | `step_upload.py` | Bild/PDF hochladen, Titel, Kategorie. Multi-Page-PDF → N Sessions |
|
||||||
|
| 2 | Orientierung | `StepOrientation.tsx` | (shared) | Rotation 90/180/270 erkennen + korrigieren |
|
||||||
|
| 3 | Seitentrennung | `StepPageSplit.tsx` | (shared) | Doppelseiten erkennen + splitten |
|
||||||
|
| 4 | Begradigung | `StepDeskew.tsx` | (shared) | Hough Lines + Word Alignment |
|
||||||
|
| 5 | Entzerrung | `StepDewarp.tsx` | (shared) | Shear-Korrektur (Vertikalkanten-Drift) |
|
||||||
|
| 6 | Zuschneiden | `StepContentCrop.tsx` | (shared) | Scanner-Raender entfernen (nach Begradigung!) |
|
||||||
|
| 7 | OCR | `StepOcr.tsx` | (shared) | Tesseract + PaddleOCR + Merge |
|
||||||
|
| 8 | Strukturerkennung | `StepStructure.tsx` | (shared) | Boxen, Zonen, Farben, Grafiken |
|
||||||
|
| 9 | Grid-Aufbau | `StepGridBuild.tsx` | (shared) | Strukturiertes Grid aus OCR + Struktur |
|
||||||
|
| 10 | Grid-Review | `StepGridReview.tsx` | (shared) | Excel-Editor, IPA, Silben, Korrekturen |
|
||||||
|
| 11 | Ground Truth | `StepGroundTruth.tsx` | (shared) | Validierung + GT-Markierung |
|
||||||
|
|
||||||
|
!!! note "Crop nach Dewarp"
|
||||||
|
Seitentrennung (Step 3) passiert **vor** Begradigung — richtig, weil jede Haelfte
|
||||||
|
unabhaengig begradigt wird. Der Content-Crop (Step 6) bleibt **nach** Dewarp,
|
||||||
|
weil content-basierter Crop auf geradem Bild besser funktioniert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multi-Page-Dokument-Gruppierung
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
|
||||||
|
Ein Lehrer scannt 10 Vokabelseiten als eine PDF-Datei. Im Endnutzer-Frontend soll das
|
||||||
|
ein zusammenhaengendes Dokument sein. Alle Seiten muessen spaeter zu gemeinsamen
|
||||||
|
Lern-Units verarbeitet werden koennen.
|
||||||
|
|
||||||
|
### Loesung: `document_group_id` + `page_number`
|
||||||
|
|
||||||
|
Zwei neue Felder auf `ocr_pipeline_sessions` (Migration `009_add_document_group.sql`):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE ocr_pipeline_sessions
|
||||||
|
ADD COLUMN IF NOT EXISTS document_group_id UUID,
|
||||||
|
ADD COLUMN IF NOT EXISTS page_number INT;
|
||||||
|
```
|
||||||
|
|
||||||
|
| Upload-Typ | document_group_id | page_number |
|
||||||
|
|------------|-------------------|-------------|
|
||||||
|
| Einzelbild | neues UUID | 1 |
|
||||||
|
| Multi-Page-PDF (10 Seiten) | gleiches UUID fuer alle 10 | 1..10 |
|
||||||
|
| Doppelseiten-Split von S. 3 | gleiches UUID | neue S. 3 + S. 4, Rest umkontiert |
|
||||||
|
|
||||||
|
### Benennung
|
||||||
|
|
||||||
|
Upload-Titel "Vokabeln Unit 3" erzeugt:
|
||||||
|
|
||||||
|
- "Vokabeln Unit 3 — S. 1"
|
||||||
|
- "Vokabeln Unit 3 — S. 2"
|
||||||
|
- ...
|
||||||
|
- "Vokabeln Unit 3 — S. 10"
|
||||||
|
|
||||||
|
### Session-Liste im Admin
|
||||||
|
|
||||||
|
Gruppierte Anzeige: Ein Dokument-Header ("Vokabeln Unit 3, 10 Seiten") mit aufklappbaren
|
||||||
|
Einzel-Sessions darunter. Jede Session hat eigenen Pipeline-Status.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API-Endpoints
|
||||||
|
|
||||||
|
### Neue Endpoints (OCR Kombi)
|
||||||
|
|
||||||
|
| Methode | Pfad | Beschreibung |
|
||||||
|
|---------|------|--------------|
|
||||||
|
| POST | `/api/v1/ocr-kombi/upload` | Upload: Einzelbild oder Multi-Page-PDF |
|
||||||
|
| GET | `/api/v1/ocr-kombi/documents/{group_id}` | Alle Sessions einer Dokumentgruppe |
|
||||||
|
|
||||||
|
### Bestehende Endpoints (wiederverwendet)
|
||||||
|
|
||||||
|
Die Kombi-Pipeline nutzt alle bestehenden Endpoints aus `/api/v1/ocr-pipeline/`:
|
||||||
|
|
||||||
|
| Methode | Pfad | Step |
|
||||||
|
|---------|------|------|
|
||||||
|
| POST | `/sessions` | Upload (Legacy, Einzelbild) |
|
||||||
|
| POST | `/sessions/{id}/orientation` | Orientierung |
|
||||||
|
| POST | `/sessions/{id}/page-split` | Seitentrennung |
|
||||||
|
| POST | `/sessions/{id}/deskew` | Begradigung |
|
||||||
|
| POST | `/sessions/{id}/dewarp` | Entzerrung |
|
||||||
|
| POST | `/sessions/{id}/crop` | Zuschneiden |
|
||||||
|
| POST | `/sessions/{id}/paddle-kombi` | OCR (Kombi) |
|
||||||
|
| POST | `/sessions/{id}/detect-structure` | Strukturerkennung |
|
||||||
|
| POST | `/sessions/{id}/build-grid` | Grid-Aufbau |
|
||||||
|
| POST | `/sessions/{id}/save-grid` | Grid speichern |
|
||||||
|
| GET | `/sessions/{id}/grid-editor` | Grid laden |
|
||||||
|
| POST | `/sessions/{id}/mark-ground-truth` | GT markieren |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dateistruktur
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
|
||||||
|
```
|
||||||
|
admin-lehrer/app/(admin)/ai/ocr-kombi/
|
||||||
|
├── page.tsx # ~140 Zeilen, Orchestrator mit Suspense-Boundary
|
||||||
|
├── types.ts # KOMBI_V2_STEPS (11 Steps), DocumentGroup-Types, OCR-Transparenz-Types
|
||||||
|
└── useKombiPipeline.ts # Hook: Session-State, Step-Navigation, Dokument-Gruppierung
|
||||||
|
|
||||||
|
admin-lehrer/components/ocr-kombi/
|
||||||
|
├── KombiStepper.tsx # 11-Step-Indikator (kompakt, scrollbar)
|
||||||
|
├── SessionList.tsx # Gruppierte Session-Liste (Dokumentgruppen aufklappbar)
|
||||||
|
├── SessionHeader.tsx # Aktive Session: Name + Kategorie + GT-Badge
|
||||||
|
├── StepUpload.tsx # Drag-Drop + Titel + Kategorie-Auswahl
|
||||||
|
├── StepOrientation.tsx # Wrapper → shared StepOrientation
|
||||||
|
├── StepPageSplit.tsx # Doppelseiten-Erkennung + Auto-Advance
|
||||||
|
├── StepDeskew.tsx # Wrapper → shared StepDeskew
|
||||||
|
├── StepDewarp.tsx # Wrapper → shared StepDewarp
|
||||||
|
├── StepContentCrop.tsx # Wrapper → shared StepCrop
|
||||||
|
├── StepOcr.tsx # Wrapper → PaddleDirectStep (kombi endpoint)
|
||||||
|
├── StepStructure.tsx # Wrapper → shared StepStructureDetection
|
||||||
|
├── StepGridBuild.tsx # Auto-Trigger build-grid + Ergebnis-Anzeige
|
||||||
|
├── StepGridReview.tsx # Wrapper → shared StepGridReview (mit saveRef)
|
||||||
|
└── StepGroundTruth.tsx # GT-Markierung mit Auto-Save
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
|
||||||
|
```
|
||||||
|
klausur-service/backend/ocr_kombi/
|
||||||
|
├── __init__.py
|
||||||
|
├── router.py # Composite Router (/api/v1/ocr-kombi)
|
||||||
|
└── step_upload.py # Multi-Page-PDF → N Sessions + document_group_id
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shared (wiederverwendet)
|
||||||
|
|
||||||
|
Die Kombi-Pipeline nutzt alle bestehenden Backend-Module:
|
||||||
|
|
||||||
|
- `orientation_crop_api.py` — Orientierung, Page-Split, Crop
|
||||||
|
- `ocr_pipeline_api.py` — Deskew, Dewarp
|
||||||
|
- `ocr_pipeline_ocr_merge.py` — PaddleOCR + Tesseract Merge
|
||||||
|
- `grid_editor_api.py` — Grid-Aufbau + Editor
|
||||||
|
- `ocr_pipeline_session_store.py` — DB-Layer (erweitert um document_group_id)
|
||||||
|
- Alle `cv_*.py` — CV-Algorithmen
|
||||||
|
|
||||||
|
### Migration
|
||||||
|
|
||||||
|
```
|
||||||
|
migrations/009_add_document_group.sql # document_group_id UUID + page_number INT + Index
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementierungsphasen
|
||||||
|
|
||||||
|
| Phase | Status | Beschreibung |
|
||||||
|
|-------|--------|--------------|
|
||||||
|
| **1: Grundgeruest + DB** | Implementiert | DB-Migration, Types, Hook, Stepper, SessionList, page.tsx, Navigation, Backend-Router |
|
||||||
|
| **2: Vorverarbeitungs-Steps** | Geplant | Multi-Page-PDF-Upload, Orientierung ohne Upload, Seitentrennung mit document_group_id |
|
||||||
|
| **3: OCR-Transparenz** | Geplant | 3-Phasen-Fortschritt, Engine-Attribution pro Wort, Farbkodierung |
|
||||||
|
| **4: Grid-Pipeline aufteilen** | Geplant | grid_editor_api.py → 4 Module + Orchestrator |
|
||||||
|
| **5: Restliche Steps** | Geplant | Structure, GridBuild, GridReview, GroundTruth voll integriert |
|
||||||
|
| **6: Features migrieren** | Spaeter | LLM-Review-Streaming, Labeling-Mode, Bild-Generierung |
|
||||||
|
| **7: Aufraeumen** | Spaeter | /ai/ocr-overlay und /ai/ocr-pipeline loeschen |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## OCR-Transparenz (Phase 3, geplant)
|
||||||
|
|
||||||
|
### 3-Phasen-Fortschritt in Step 7
|
||||||
|
|
||||||
|
1. "Tesseract laeuft..." (Fortschrittsbalken)
|
||||||
|
2. "PaddleOCR laeuft..." (Fortschrittsbalken)
|
||||||
|
3. "Merge laeuft..." (Fortschrittsbalken)
|
||||||
|
|
||||||
|
### Engine-Attribution pro Wort
|
||||||
|
|
||||||
|
Vergleichsansicht mit Farbkodierung:
|
||||||
|
|
||||||
|
| Farbe | Bedeutung |
|
||||||
|
|-------|-----------|
|
||||||
|
| Gruen | Beide Engines einig |
|
||||||
|
| Blau | Nur PaddleOCR |
|
||||||
|
| Orange | Nur Tesseract |
|
||||||
|
| Gelb | Konflikt, PaddleOCR gewaehlt |
|
||||||
|
| Rot | Konflikt, Tesseract gewaehlt |
|
||||||
|
|
||||||
|
### Geplanter Endpoint
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /sessions/{id}/ocr-kombi-transparent
|
||||||
|
→ { raw_tesseract, raw_paddle, merged, engine_source_per_word }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Grid-Pipeline-Aufteilung (Phase 4, geplant)
|
||||||
|
|
||||||
|
`grid_editor_api.py` (1801 Zeilen) wird aufgeteilt in:
|
||||||
|
|
||||||
|
| Modul | Inhalt | ~Zeilen |
|
||||||
|
|-------|--------|---------|
|
||||||
|
| `grid_build_filters.py` | Margin, Footer, Header, Exclude, Grafik-Filter | ~200 |
|
||||||
|
| `grid_build_zones.py` | Box-Detect, Page-Zones, Vert-Dividers | ~250 |
|
||||||
|
| `grid_build_columns.py` | Spalten-Clustering + Union-Merge + Zone-Grids | ~300 |
|
||||||
|
| `grid_build_postprocess.py` | Row/Cell-Postprocessing, IPA, Farben, Dictionary | ~500 |
|
||||||
|
|
||||||
|
`grid_editor_api.py` wird zum schlanken Orchestrator.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verhaeltnis zu bestehenden Pipelines
|
||||||
|
|
||||||
|
| Pipeline | Route | Status | Beschreibung |
|
||||||
|
|----------|-------|--------|--------------|
|
||||||
|
| **OCR Kombi** | `/ai/ocr-kombi` | Aktiv (neu) | Modulare 11-Schritt-Pipeline |
|
||||||
|
| OCR Overlay | `/ai/ocr-overlay` | Legacy | 751-Zeilen-Monolith, 3 Modi |
|
||||||
|
| OCR Pipeline | `/ai/ocr-pipeline` | Legacy | Volle Pipeline mit Spalten |
|
||||||
|
| OCR Compare | `/ai/ocr-compare` | Eigenstaendig | Methoden-Vergleich |
|
||||||
|
|
||||||
|
Die alte OCR Overlay (`/ai/ocr-overlay`) bleibt waehrend des gesamten Umbaus parallel nutzbar
|
||||||
|
fuer A/B-Tests. Sobald die Kombi-Pipeline feature-complete ist, werden die alten Pipelines
|
||||||
|
in Phase 7 entfernt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aenderungshistorie
|
||||||
|
|
||||||
|
| Datum | Version | Aenderung |
|
||||||
|
|-------|---------|-----------|
|
||||||
|
| 2026-03-26 | 1.0.0 | **Phase 1:** Grundgeruest mit 11-Step-Architektur, DB-Migration (document_group_id, page_number), Backend-Router mit Multi-Page-Upload, Frontend mit SessionList (gruppiert), KombiStepper, 13 Step-Komponenten, useKombiPipeline Hook, Navigation |
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# OCR Pipeline - Schrittweise Seitenrekonstruktion
|
# OCR Pipeline - Schrittweise Seitenrekonstruktion
|
||||||
|
|
||||||
**Version:** 5.0.0
|
**Version:** 5.1.0
|
||||||
**Status:** Produktiv (Schritte 1–10 + Grid Editor + Regression Framework)
|
**Status:** Produktiv (Schritte 1–10 + Grid Editor + Regression Framework)
|
||||||
**URL:** https://macmini:3002/ai/ocr-pipeline
|
**URL:** https://macmini:3002/ai/ocr-pipeline
|
||||||
|
|
||||||
@@ -149,7 +149,9 @@ klausur-service/backend/
|
|||||||
├── ocr_pipeline_api.py # FastAPI Router (Schritte 2-10)
|
├── ocr_pipeline_api.py # FastAPI Router (Schritte 2-10)
|
||||||
├── orientation_crop_api.py # FastAPI Router (Schritte 1 + 4)
|
├── orientation_crop_api.py # FastAPI Router (Schritte 1 + 4)
|
||||||
├── grid_editor_api.py # Grid Editor: build-grid, save-grid, grid-editor
|
├── grid_editor_api.py # Grid Editor: build-grid, save-grid, grid-editor
|
||||||
|
├── grid_editor_helpers.py # Footer-Filterung, Seitenzahl-Extraktion
|
||||||
├── cv_ocr_engines.py # OCR-Engines, IPA-Korrektur, Britfone-Woerterbuch
|
├── cv_ocr_engines.py # OCR-Engines, IPA-Korrektur, Britfone-Woerterbuch
|
||||||
|
├── cv_syllable_detect.py # Deutsche Silbentrennung (Silben:DE Modus)
|
||||||
├── cv_box_detect.py # Box-Erkennung + Zonen-Aufteilung
|
├── cv_box_detect.py # Box-Erkennung + Zonen-Aufteilung
|
||||||
├── cv_graphic_detect.py # Grafik-/Bilderkennung (Region-basiert)
|
├── cv_graphic_detect.py # Grafik-/Bilderkennung (Region-basiert)
|
||||||
├── cv_color_detect.py # Farbtext-Erkennung (HSV-Analyse)
|
├── cv_color_detect.py # Farbtext-Erkennung (HSV-Analyse)
|
||||||
@@ -1081,6 +1083,8 @@ Rekonstruktion fuer Vokabelseiten mit komplexen Layouts (Bilder, Ueberschriften,
|
|||||||
| Datei | Beschreibung |
|
| Datei | Beschreibung |
|
||||||
|-------|--------------|
|
|-------|--------------|
|
||||||
| `grid_editor_api.py` | `_build_grid_core()` Pipeline, alle Steps |
|
| `grid_editor_api.py` | `_build_grid_core()` Pipeline, alle Steps |
|
||||||
|
| `grid_editor_helpers.py` | `_filter_footer_words()` → Seitenzahl-Extraktion, Footer-Filterung |
|
||||||
|
| `cv_syllable_detect.py` | Deutsche Silbentrennung mit IPA-Kompatibilitaet |
|
||||||
| `cv_ocr_engines.py` | IPA-Korrektur, Britfone-Woerterbuch, Garbled-IPA-Erkennung |
|
| `cv_ocr_engines.py` | IPA-Korrektur, Britfone-Woerterbuch, Garbled-IPA-Erkennung |
|
||||||
| `cv_vocab_types.py` | `PageZone` (mit `image_overlays`), `ColumnGeometry` |
|
| `cv_vocab_types.py` | `PageZone` (mit `image_overlays`), `ColumnGeometry` |
|
||||||
| `tests/test_grid_editor_api.py` | 27 Tests |
|
| `tests/test_grid_editor_api.py` | 27 Tests |
|
||||||
@@ -1106,9 +1110,15 @@ Kombi-Wortdaten
|
|||||||
├─ Step 4: Farb-Annotation
|
├─ Step 4: Farb-Annotation
|
||||||
│ → detect_word_colors(): HSV-Farbanalyse aller word_boxes
|
│ → detect_word_colors(): HSV-Farbanalyse aller word_boxes
|
||||||
│
|
│
|
||||||
|
├─ Step 4b2: Per-Cell Artifact Filter
|
||||||
|
│ → Einzel-Wort-Zellen mit ≤2 Zeichen und conf < 65 entfernen
|
||||||
|
│
|
||||||
├─ Step 4c: Oversized Word Box Removal
|
├─ Step 4c: Oversized Word Box Removal
|
||||||
│ → word_boxes > 3x Median entfernen (Grafik-Artefakte)
|
│ → word_boxes > 3x Median entfernen (Grafik-Artefakte)
|
||||||
│
|
│
|
||||||
|
├─ Step 4d2: Connector Column Normalization
|
||||||
|
│ → Dominante Kurzwoerter in schmalen Spalten normalisieren
|
||||||
|
│
|
||||||
├─ Step 5: Overlay-Wort-Filter
|
├─ Step 5: Overlay-Wort-Filter
|
||||||
│ → Woerter innerhalb image_overlays entfernen
|
│ → Woerter innerhalb image_overlays entfernen
|
||||||
│
|
│
|
||||||
@@ -1197,6 +1207,38 @@ des Headwords der vorherigen Zeile). Diese werden von PaddleOCR als garbled Text
|
|||||||
4. Schlaegt IPA im Britfone-Woerterbuch nach
|
4. Schlaegt IPA im Britfone-Woerterbuch nach
|
||||||
5. Beruecksichtigt alle Wortteile (z.B. "close sth. down" → `[klˈəʊz dˈaʊn]`)
|
5. Beruecksichtigt alle Wortteile (z.B. "close sth. down" → `[klˈəʊz dˈaʊn]`)
|
||||||
|
|
||||||
|
### Per-Cell Artifact Filter (Step 4b2)
|
||||||
|
|
||||||
|
Entfernt OCR-Rauschen auf Zellebene: Zellen mit genau einer `word_box`, maximal 2 Zeichen
|
||||||
|
und Confidence unter 65 werden als Artefakte klassifiziert und entfernt.
|
||||||
|
|
||||||
|
**Konstanten:**
|
||||||
|
|
||||||
|
| Parameter | Wert | Beschreibung |
|
||||||
|
|-----------|------|--------------|
|
||||||
|
| `_ARTIFACT_MAX_LEN` | 2 | Maximale Textlaenge fuer Artefakt-Verdacht |
|
||||||
|
| `_ARTIFACT_CONF_THRESHOLD` | 65 | Confidence-Schwelle (darunter = Artefakt) |
|
||||||
|
|
||||||
|
**Sicherheit:** Einzelne Zeichen mit hoher Confidence (z.B. rote `!`-Marker mit conf=98)
|
||||||
|
werden **nicht** entfernt, da ihre Confidence ueber dem Schwellwert liegt.
|
||||||
|
|
||||||
|
**Typische Artefakte:** `(as)` conf=55, `u)` conf=44 — OCR-Noise aus Seitenraendern
|
||||||
|
oder Schatten.
|
||||||
|
|
||||||
|
### Connector Column Normalization (Step 4d2)
|
||||||
|
|
||||||
|
Erkennt schmale Spalten mit einem dominanten Kurzwort (z.B. "oder", "and", "bzw.")
|
||||||
|
und normalisiert OCR-Fehler bei denen das dominante Wort mit Rauschen versehen wurde.
|
||||||
|
|
||||||
|
**Algorithmus:**
|
||||||
|
|
||||||
|
1. Pro Spalte: Zaehle Textvorkommen aller Zellen
|
||||||
|
2. Pruefe ob ein dominantes Wort existiert (≥ 60% der Zellen, max 10 Zeichen)
|
||||||
|
3. Fuer Zellen die mit dem dominanten Wort **beginnen** und max 2 Zeichen laenger sind:
|
||||||
|
Normalisiere auf das dominante Wort
|
||||||
|
|
||||||
|
**Beispiel:** Spalte mit "oder" in 80% der Zellen → `"oderb"` wird zu `"oder"` normalisiert.
|
||||||
|
|
||||||
### Compound Word IPA Decomposition (Step 5e)
|
### Compound Word IPA Decomposition (Step 5e)
|
||||||
|
|
||||||
Zusammengesetzte Woerter wie "schoolbag" oder "blackbird" haben oft keinen eigenen
|
Zusammengesetzte Woerter wie "schoolbag" oder "blackbird" haben oft keinen eigenen
|
||||||
@@ -1253,6 +1295,69 @@ Admin-UI fuer effiziente Massenpruefung von Sessions:
|
|||||||
|
|
||||||
Admin-UI: [/ai/ocr-ground-truth](https://macmini:3002/ai/ocr-ground-truth)
|
Admin-UI: [/ai/ocr-ground-truth](https://macmini:3002/ai/ocr-ground-truth)
|
||||||
|
|
||||||
|
### Page Number Extraction
|
||||||
|
|
||||||
|
Die Footer-Filterung (`_filter_footer_words` in `grid_editor_helpers.py`) erkennt
|
||||||
|
Seitenzahlen in den untersten 5% des Bildes und gibt sie als Metadaten zurueck,
|
||||||
|
statt sie stillschweigend zu entfernen.
|
||||||
|
|
||||||
|
**Algorithmus:**
|
||||||
|
|
||||||
|
1. Woerter in den untersten 5% des Bildes identifizieren
|
||||||
|
2. Wenn ≤ 3 Woerter mit ≤ 10 Zeichen Gesamtlaenge: Als Seitenzahl extrahieren
|
||||||
|
3. Rueckgabe als `PageNumber`-Objekt: `{text, y_pct, number?}`
|
||||||
|
4. Ziffern werden separat als `number` (Integer) extrahiert
|
||||||
|
|
||||||
|
**Datentyp:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PageNumber {
|
||||||
|
text: string // Roh-OCR-Text (z.B. "u)233")
|
||||||
|
y_pct: number // Vertikale Position in Prozent
|
||||||
|
number?: number // Extrahierte Zahl (z.B. 233)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Frontend-Anzeige:**
|
||||||
|
|
||||||
|
In der Summary-Leiste (GridEditor + StepGridReview) als Badge: `S. 233`.
|
||||||
|
Zeigt bevorzugt `page_number.number` (saubere Zahl), Fallback auf `page_number.text`.
|
||||||
|
|
||||||
|
**Zweck:** Spaetere Zusammenfuehrung aufeinanderfolgender Seiten im Kundenfrontend.
|
||||||
|
|
||||||
|
### Footer-Zeilen-Erkennung (Verbesserung)
|
||||||
|
|
||||||
|
Die Footer-Erkennung wurde um zwei Pruefungen erweitert, um falsch-positive
|
||||||
|
Footer-Markierungen bei Content-Zeilen zu verhindern:
|
||||||
|
|
||||||
|
| Pruefung | Bedingung | Grund |
|
||||||
|
|----------|-----------|-------|
|
||||||
|
| Komma-Check | `',' in text` → kein Footer | Content-Saetze enthalten Kommas, Seitenzahlen nicht |
|
||||||
|
| Laengen-Check | `len(text) > 20` → kein Footer | Seitenzahlen sind kurz, Content-Zeilen lang |
|
||||||
|
|
||||||
|
**Vorher:** `"Uhrzeit, Vergangenheit, Zukunft"` wurde als Footer markiert.
|
||||||
|
**Nachher:** Nur tatsaechliche Seitenzahlen (kurz, ohne Kommas) werden als Footer erkannt.
|
||||||
|
|
||||||
|
### Silben + IPA Kombination (Fix)
|
||||||
|
|
||||||
|
**Datei:** `cv_syllable_detect.py`
|
||||||
|
|
||||||
|
Wenn beide Modi (Silben:DE und IPA) aktiviert sind, blockierte der `_IPA_RE`-Guard
|
||||||
|
die Silbentrennung, weil programmatisch eingefuegte IPA-Klammern (z.B. `[bɪltʃøn]`)
|
||||||
|
IPA-Zeichen enthalten.
|
||||||
|
|
||||||
|
**Loesung:** Vor der IPA-Pruefung wird Bracket-Content entfernt:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Bracket-Content strippen, da programmatisch eingefuegt
|
||||||
|
text_no_brackets = re.sub(r'\[[^\]]*\]', '', text)
|
||||||
|
if _IPA_RE.search(text_no_brackets):
|
||||||
|
return text # Echte IPA im Fliesstext → keine Silbentrennung
|
||||||
|
```
|
||||||
|
|
||||||
|
So wird `"Bild·chen [bɪltʃøn]"` korrekt silbifiziert: Die Silbenpunkte bleiben erhalten,
|
||||||
|
und die IPA in Klammern wird nicht als Blockiergrund gewertet.
|
||||||
|
|
||||||
### `en_col_type` Erkennung
|
### `en_col_type` Erkennung
|
||||||
|
|
||||||
Die Erkennung der Englisch-Headword-Spalte nutzt **Bracket-IPA-Pattern-Count**
|
Die Erkennung der Englisch-Headword-Spalte nutzt **Bracket-IPA-Pattern-Count**
|
||||||
@@ -1620,6 +1725,8 @@ Die Ergebnisse fliessen in Schritt 5 (Spaltenerkennung) und den Grid Editor ein.
|
|||||||
|
|
||||||
| Datum | Version | Aenderung |
|
| Datum | Version | Aenderung |
|
||||||
|-------|---------|----------|
|
|-------|---------|----------|
|
||||||
|
| 2026-03-26 | 5.2.0 | **OCR Kombi Pipeline:** Neuer modularer Nachfolger als 11-Schritt-Architektur unter `/ai/ocr-kombi`. Eigene Dokumentation: [OCR Kombi Pipeline](OCR-Kombi-Pipeline.md). Phase 1 (Grundgeruest + DB) implementiert: DB-Migration (`document_group_id`, `page_number`), Frontend-Orchestrator, 13 Step-Komponenten, Backend-Router mit Multi-Page-Upload. |
|
||||||
|
| 2026-03-26 | 5.1.0 | **Grid Quality & Metadata:** Per-Cell Artifact Filter (Step 4b2: ≤2 Zeichen + conf < 65), Connector Column Normalization (Step 4d2: dominante Kurzwoerter), Footer-Erkennung verbessert (Komma/Laengen-Check), Seitenzahl-Extraktion als Metadaten (`page_number` Feld im Grid-Result), Frontend-Anzeige in Summary-Leiste. Silben+IPA-Kombination gefixt (Bracket-Content vor IPA-Guard strippen). |
|
||||||
| 2026-03-23 | 5.0.0 | **Phase 1 Sprint 1:** Compound-IPA-Zerlegung (`_decompose_compound`), Trailing-Garbled-Fragment-Entfernung (Multi-Wort-Headwords), Regression Framework mit DB-Persistenz + History + Shell-Script, Ground-Truth Review Workflow UI, Page-Crop Determinismus verifiziert. Admin-Seiten: `/ai/ocr-regression`, `/ai/ocr-ground-truth`. |
|
| 2026-03-23 | 5.0.0 | **Phase 1 Sprint 1:** Compound-IPA-Zerlegung (`_decompose_compound`), Trailing-Garbled-Fragment-Entfernung (Multi-Wort-Headwords), Regression Framework mit DB-Persistenz + History + Shell-Script, Ground-Truth Review Workflow UI, Page-Crop Determinismus verifiziert. Admin-Seiten: `/ai/ocr-regression`, `/ai/ocr-ground-truth`. |
|
||||||
| 2026-03-20 | 4.7.0 | Grid Editor: Zone Merging ueber Bilder (`image_overlays`), Heading Detection (Farbe + Hoehe), Ghost-Filter (borderless-aware), Oversized Word Box Removal, IPA Phonetic Correction (Britfone), IPA Continuation Detection, `en_col_type` via Bracket-Count. 27 Tests. |
|
| 2026-03-20 | 4.7.0 | Grid Editor: Zone Merging ueber Bilder (`image_overlays`), Heading Detection (Farbe + Hoehe), Ghost-Filter (borderless-aware), Oversized Word Box Removal, IPA Phonetic Correction (Britfone), IPA Continuation Detection, `en_col_type` via Bracket-Count. 27 Tests. |
|
||||||
| 2026-03-16 | 4.6.0 | Strukturerkennung (Schritt 8): Region-basierte Grafikerkennung (`cv_graphic_detect.py`) mit Zwei-Pass-Verfahren (Farbregionen + schwarze Illustrationen), Wort-Ueberlappungs-Filter, Box/Zonen/Farb-Analyse. Schritt laeuft nach Worterkennung. |
|
| 2026-03-16 | 4.6.0 | Strukturerkennung (Schritt 8): Region-basierte Grafikerkennung (`cv_graphic_detect.py`) mit Zwei-Pass-Verfahren (Farbregionen + schwarze Illustrationen), Wort-Ueberlappungs-Filter, Box/Zonen/Farb-Analyse. Schritt laeuft nach Worterkennung. |
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ nav:
|
|||||||
- BYOEH Developer Guide: services/klausur-service/BYOEH-Developer-Guide.md
|
- BYOEH Developer Guide: services/klausur-service/BYOEH-Developer-Guide.md
|
||||||
- NiBiS Pipeline: services/klausur-service/NiBiS-Ingestion-Pipeline.md
|
- NiBiS Pipeline: services/klausur-service/NiBiS-Ingestion-Pipeline.md
|
||||||
- OCR Pipeline: services/klausur-service/OCR-Pipeline.md
|
- OCR Pipeline: services/klausur-service/OCR-Pipeline.md
|
||||||
|
- OCR Kombi Pipeline: services/klausur-service/OCR-Kombi-Pipeline.md
|
||||||
- TrOCR ONNX: services/klausur-service/TrOCR-ONNX.md
|
- TrOCR ONNX: services/klausur-service/TrOCR-ONNX.md
|
||||||
- OCR Labeling: services/klausur-service/OCR-Labeling-Spec.md
|
- OCR Labeling: services/klausur-service/OCR-Labeling-Spec.md
|
||||||
- OCR Vergleich: services/klausur-service/OCR-Compare.md
|
- OCR Vergleich: services/klausur-service/OCR-Compare.md
|
||||||
|
|||||||
Reference in New Issue
Block a user