From bc13978bc1e0f050e704f4f852ef7395c88d9379 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Wed, 11 Mar 2026 16:13:31 +0100 Subject: [PATCH] feat: Slide-Modus als alternative Wort-Positionierung im Overlay 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 --- .../ocr-overlay/OverlayReconstruction.tsx | 30 ++- .../ocr-overlay/useSlideWordPositions.ts | 224 ++++++++++++++++++ 2 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 admin-lehrer/components/ocr-overlay/useSlideWordPositions.ts diff --git a/admin-lehrer/components/ocr-overlay/OverlayReconstruction.tsx b/admin-lehrer/components/ocr-overlay/OverlayReconstruction.tsx index 94705e8..7df5507 100644 --- a/admin-lehrer/components/ocr-overlay/OverlayReconstruction.tsx +++ b/admin-lehrer/components/ocr-overlay/OverlayReconstruction.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import type { GridResult, GridCell, RowResult, RowItem } from '@/app/(admin)/ai/ocr-overlay/types' import { usePixelWordPositions } from './usePixelWordPositions' +import { useSlideWordPositions } from './useSlideWordPositions' const KLAUSUR_API = '/klausur-api' @@ -42,19 +43,27 @@ export function OverlayReconstruction({ sessionId, onNext }: OverlayReconstructi const [imageRotation, setImageRotation] = useState<0 | 180>(0) const [textOpacity, setTextOpacity] = useState(100) const [textColor, setTextColor] = useState<'red' | 'blue' | 'black'>('red') + const [positioningMode, setPositioningMode] = useState<'cluster' | 'slide'>('slide') const reconRef = useRef(null) const [reconWidth, setReconWidth] = useState(0) - // Pixel-based word positions + // Pixel-based word positions (both algorithms run, toggle selects which to use) const overlayImageUrl = sessionId ? `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped` : '' - const cellWordPositions = usePixelWordPositions( + const clusterPositions = usePixelWordPositions( overlayImageUrl, gridCells, status === 'ready', imageRotation, ) + const slidePositions = useSlideWordPositions( + overlayImageUrl, + gridCells, + status === 'ready', + imageRotation, + ) + const cellWordPositions = positioningMode === 'slide' ? slidePositions : clusterPositions // Track container width useEffect(() => { @@ -395,6 +404,23 @@ export function OverlayReconstruction({ sessionId, onNext }: OverlayReconstructi
+ {/* Positioning mode toggle */} + + +
+ {/* Text color */} {(['red', 'blue', 'black'] as const).map(c => (