Bilder > 1500px werden vor dem Upload verkleinert. Koordinaten
werden zurueckskaliert. JPEG statt PNG fuer schnelleren Upload.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update chunk counts for 8 successfully ingested DE laws (Phase H1)
- Add 6 new BGB-Teile entries (AGB, Fernabsatz, Kaufrecht, Widerruf, Digital)
- Add EGBGB Widerrufsbelehrung entry
- Update COLLECTION_TOTALS: gesetze 58304→63567 (+5263 Phase H chunks)
- Add Verbraucherschutz thematic group to Landkarte
- Extend ecommerce industry map with consumer protection regulations
- Update date to March 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PaddleOCR als neue engine=paddle Option in der OCR-Pipeline.
Microservice auf Hetzner (paddleocr-service/), async HTTP-Client
(paddleocr_remote.py), Frontend-Dropdown, automatisch words_first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 15 new regulations from Phase H ingestion:
- DE: PAngV, VSBG, ProdHaftG, VerpackG, ElektroG, BattDG, BFSG, UWG, GewO
- EU: Warenkauf-RL, Klausel-RL, UGP-RL, Preisangaben-RL, Omnibus-RL, BattVO
Chunk counts set to 0 (will be updated after successful ingestion).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_has_ipa_gap() prüft ob Tesseract eine IPA-Klammer übersehen hat anhand
des physischen Abstands zwischen Headword und nächstem Wort. Ohne Gap
(z.B. "be good at sth.", "Focus on language") wird kein IPA eingefügt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_insert_missing_ipa ueberspringe Texte mit >6 Woertern oder Klammern.
Neue _insert_headword_ipa fuer column_text: prueft nur das erste Wort
der Zeile, unabhaengig von Textlaenge oder vorhandenen Klammern.
Ausserdem _sync_word_boxes_after_ipa_insert gefixt: Token-Vergleich
nutzt jetzt paralleles Durchlaufen statt zip (verschobene Positionen).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fuer column_text werden fehlende IPA-Lautschriften (challenge, profit,
film, badge) wieder eingefuegt, aber gleichzeitig eine synthetische
word_box erzeugt, damit die 1:1 Token-zu-Box Zuordnung im Overlay
erhalten bleibt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_strip_orphan_bracket entfernte deutsche Bedeutungsangaben in Klammern,
weil sie weder als Grammar-Partikel noch als IPA erkannt wurden.
Fix: Klammerinhalte mit echten Wörtern (>=4 Buchstaben) werden behalten.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
word_boxes wurden nur im Cell-Crop-Pfad (narrow columns) gesetzt,
aber nicht im Full-Page Word-Assignment-Pfad (broad columns).
Jetzt werden die Tesseract-Wort-Koordinaten in beiden Pfaden gespeichert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TEXT kommt aus cell.text (bereinigt, IPA-korrigiert).
POSITIONEN kommen aus word_boxes (exakte OCR-Koordinaten).
Tokens werden 1:1 in Leserichtung zugeordnet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: _ocr_cell_crop speichert jetzt word_boxes mit exakten
Tesseract/RapidOCR Wort-Koordinaten (left, top, width, height)
im Cell-Ergebnis. Absolute Bildkoordinaten, bereits zurueckgemappt.
Frontend: Slide-Hook nutzt word_boxes direkt wenn vorhanden —
jedes Wort wird exakt an seiner OCR-Position platziert. Kein
Pixel-Scanning noetig. Fallback auf alten Slide wenn keine Boxes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gruppen-Sliding schob nicht weit genug nach rechts. Zurueck zum
Original-Einzelwort-Slide, aber mit den Fixes:
- fontRatio=1.0 (konsistente Schriftgroesse wie Fallback)
- Token-Breiten aus medianCh * 0.7 / refFontSize (statt totalInk)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vorher: split(/\s+/) zerlegte alles in Einzelwoerter, verlor die
Spaltenstruktur (3+ Spaces zwischen Gruppen). Woerter stauten sich links.
Jetzt: split(/\s{3,}/) erhält Gruppen wie im Cluster-Modus. Jede Gruppe
wird als Einheit von links nach rechts geschoben bis Tinte gefunden.
Breite = max(gemessene Textbreite, tatsaechliche Tintenbreite).
fontRatio=1.0, kein Wort geht verloren.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fontRatio war 0.65 (35% kleiner als Fallback-Rendering). Jetzt 1.0
wie beim Fallback. Token-Breiten berechnet aus measureText skaliert
auf die tatsaechlich gerenderte Schriftgroesse (medianCh * 0.7).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Schriftgroesse wird jetzt GLOBAL aus der medianen Zellhoehe berechnet
(65% der Zellhoehe als Ziel-Font). Alle Tokens bekommen dieselbe
konsistente Groesse. Die Slide-Logik bestimmt nur noch die x-Position.
Vorher: Scale pro Zelle aus Ink-Span/Textbreite -> inkonsistente Groessen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
totalInk zaehlte nur dunkle Pixel-Spalten (Striche), ignorierte
Luecken zwischen Buchstaben. Scale war dadurch viel zu klein,
Schrift unlesbar. Jetzt wird der Ink-Span (erstes bis letztes
dunkles Pixel) als Referenz fuer die Textbreite verwendet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Neuer Hook useSlideWordPositions: Schiebt alle erkannten Woerter von links
nach rechts ueber die Pixel-Projektion bis jedes Wort auf seiner Tinte
einrastet. Kein Wort geht verloren, keine Cluster-Matching-Regeln noetig.
Toggle-Button (Slide/Cluster) in der Overlay-Toolbar zum Umschalten.
Bestehender Cluster-Algorithmus bleibt als Alternative erhalten.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix_cell_phonetics() ersetzt fehlerhafte IPA-Klammern UND fuegt fehlende
Lautschrift fuer englische Woerter ein (z.B. badge, film, challenge, profit).
Wird auf alle Zellen mit col_type column_en/column_text angewandt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zwei wesentliche Verbesserungen:
1. Multi-group: Gruppen werden per Best-Fit-Breite den Clustern
zugeordnet statt naiv links-nach-rechts. Damit wird z.B.
"Kokosnuss" dem DE-Spalten-Cluster zugeordnet statt dem
breiteren Box-Cluster.
2. Single-group Fallback: verwendet den BREITESTEN Cluster statt
first-to-last Span. Verhindert dass Streupixel von benachbarten
Seitenbereichen den Text nach links ziehen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Box-Rahmen werden vom OCR als einzelne Symbole wie "|" oder ">"
erkannt und als eigene Text-Gruppen behandelt. Das verfaelscht die
Cluster-Zuordnung weil diese Artefakte entweder keinen eigenen
Cluster erzeugen oder den falschen Cluster zugewiesen bekommen.
Fix: Gruppen mit max 2 Zeichen ohne Buchstaben/Ziffern werden mit
der benachbarten Gruppe zusammengefuehrt bevor die Cluster-Zuordnung
laeuft.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wenn mehr Pixel-Cluster als Text-Gruppen existieren (z.B. wegen
Box-Rahmenlinien), werden jetzt die N breitesten Cluster ausgewaehlt
statt naiv clusters[i]→groups[i] zuzuordnen. Text-Cluster sind
breiter als Rahmenlinien-Cluster.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vorher: wenn Text mehr Wort-Gruppen hatte als Pixel-Cluster gefunden
wurden (z.B. bei Box-Rahmen die Cluster zusammenmergen), wurde die
Zelle komplett uebersprungen → Fallback bei x=0%.
Jetzt: Fallback auf Single-Span Positionierung (first→last Cluster)
statt Skip. Damit wird der Text immer korrekt horizontal platziert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Schriftgroesse basiert jetzt auf Median-Zeilenhoehe statt
individueller Zellhoehe — keine Groessensprunge in Box-Bereichen
2. Sehr schmale Pixel-Cluster (< 0.5% Zellbreite) werden gefiltert,
damit Box-Rahmen nicht als Textposition erkannt werden
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NameError behoben: skip_heal_gaps war nicht im Scope der
_word_batch_stream_generator Funktion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_heal_row_gaps verschiebt Zell-Positionen nach Entfernung von Artefakt-Zeilen,
was im Overlay zu sichtbarem Versatz fuehrt (z.B. 23px bei "badge").
Neuer skip_heal_gaps Parameter in build_cell_grid_v2 und words-Endpoint
behaelt die exakten Zeilen-Positionen bei.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Seiten mit Info-Boxen (andere Zeilenhoehe) fuehren dazu, dass _regularize_row_grid
die Zeilenpositionen verzerrt. Neuer skip_regularize Parameter nutzt stattdessen
die gap-basierten Zeilen, die der tatsaechlichen Seitengeometrie folgen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Statt Side-by-Side wird der erkannte Text jetzt direkt ueber das
Originalbild gelegt. Textfarbe (rot/blau/schwarz) und Deckkraft
per Slider einstellbar fuer einfache visuelle Fehlersuche.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wenn column_result fehlt (z.B. OCR Overlay Pipeline), wird automatisch
eine einzelne ganzseitige Pseudo-Spalte erzeugt statt einen Fehler zu werfen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Das cropped image ist bereits orientierungskorrigiert. Die zusaetzliche
180°-Rotation ueber imageRotation drehte das Bild falsch herum.
imageRotation wird weiter fuer Pixel-Matching genutzt, aber nicht mehr
fuer die Bildanzeige.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Euro/Badge-Zeilen hatten ihren Center innerhalb der Box-Zone, weshalb
das Clamping nicht griff. Jetzt wird anhand der Box-Mitte entschieden
ob eine Zelle nach oben (clamp height) oder unten (push y) gehoert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
boxZonesPct useMemo war nach bedingten Returns platziert, was gegen
Reacts Rules of Hooks verstoesst und einen Client-Side Crash ausloest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zellen oberhalb der Box werden in der Hoehe begrenzt, Zellen unterhalb
werden nach unten verschoben. Sub-Session-Zellen bleiben unveraendert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- detect_rows: Content-Strips nutzen jetzt box_ranges_inner (geschrumpft
um border_thickness, min 5px) statt der vollen Box-Range
- detect_words: _row_in_box Filter nutzt ebenfalls inner Range
- Dadurch wird die letzte Zeile oberhalb einer Box nicht mehr
faelschlicherweise der Box zugeordnet und ausgeschlossen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- usePixelWordPositions: neuer rotation-Parameter (0 | 180)
- Bei 180°: Bild auf Canvas rotiert, Zell-Koordinaten transformiert,
Cluster-Positionen zurueck-gespiegelt
- StepReconstruction: 180°-Toggle-Button in Overlay-Toolbar
- Default 180° bei Parent-Sessions mit Boxen
- Linkes Originalbild wird ebenfalls CSS-rotiert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- usePixelWordPositions Hook extrahiert (shared zwischen StepLlmReview und StepReconstruction)
- StepReconstruction: neuer Overlay-Modus mit 50/50 Layout (Original + Rekonstruktion)
- Sub-Session-Zellen werden in Parent-Koordinaten konvertiert und zusammengefuehrt
- Spalten-/Zeilenlinien und Box-Zone-Markierung aus column_result/row_result
- Schriftgroesse-Slider und Bold-Toggle fuer Overlay
- StepLlmReview: ~140 Zeilen Pixel-Analyse durch Hook ersetzt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alle Wortgruppen bekommen die gleiche fontRatio (gerundet auf 0.02),
basierend auf der haeufigsten berechneten Groesse. Ueberschriften
und Fliesstext haben damit einheitliche Schriftgroesse.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Analysiert Schwarzpixel-Verteilung auf dem Originalbild per Canvas.
Findet Wort-Cluster pro Zeile und positioniert erkannte Textgruppen
an den exakten Pixel-Positionen. Monospace-Font zurueck auf Sans-Serif.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
column_text Zellen enthalten proportionale Leerzeichen zur Ausrichtung.
Mit Monospace-Font stehen Waehrungswerte korrekt untereinander.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alle Zellen einer Spalte bekommen die gleiche x-Position (Median)
damit Werte vertikal korrekt untereinander stehen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Neuer Overlay-Modus zeigt OCR-Text per bbox_pct ueber weissem
Hintergrund neben dem Originalbild. Steuerelemente fuer Schriftgroesse,
Einrueckung und Bold. Inline-Editing per contentEditable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_cells_to_vocab_entries wurde nur bei is_vocab (column_en/column_de)
aufgerufen. Fuer Sub-Sessions mit column_text wurden keine Eintraege
erzeugt, daher blieb die Korrektur-Tabelle leer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_cells_to_vocab_entries kannte column_text nicht, daher wurden
keine Eintraege erzeugt. Jetzt mappt column_text -> 'text' Feld.
Frontend: column_text in FIELD_LABELS/COL_TYPE_TO_FIELD/COL_TYPE_COLOR.
Label: "Tabelle" statt "Vokabeltabelle" fuer Sub-Sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>