fix: Overlay spaltenweise Ausrichtung per Median-Snap
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 33s
CI / test-go-edu-search (push) Successful in 33s
CI / test-python-klausur (push) Failing after 2m7s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 22s

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>
This commit is contained in:
Benjamin Admin
2026-03-10 11:20:06 +01:00
parent e44e319ccf
commit ca7d44e543

View File

@@ -1,6 +1,6 @@
'use client'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import type { GridCell, GridResult, WordEntry, ColumnMeta } from '@/app/(admin)/ai/ocr-pipeline/types'
const KLAUSUR_API = '/klausur-api'
@@ -402,6 +402,28 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
// Active entry for highlighting on image
const activeEntry = vocabEntries.find((_: WordEntry, i: number) => activeRowIndices.has(i))
// Snap all cells in the same column to consistent x/w positions
// Uses the median x and max width per col_index so columns align vertically
const colPositions = useMemo(() => {
const byCol = new Map<number, { xs: number[]; ws: number[] }>()
for (const cell of cells) {
if (!cell.bbox_pct) continue
const entry = byCol.get(cell.col_index) || { xs: [], ws: [] }
entry.xs.push(cell.bbox_pct.x)
entry.ws.push(cell.bbox_pct.w)
byCol.set(cell.col_index, entry)
}
const result = new Map<number, { x: number; w: number }>()
for (const [colIdx, { xs, ws }] of byCol) {
xs.sort((a, b) => a - b)
ws.sort((a, b) => a - b)
const medianX = xs[Math.floor(xs.length / 2)]
const medianW = ws[Math.floor(ws.length / 2)]
result.set(colIdx, { x: medianX, w: medianW })
}
return result
}, [cells])
const pct = progress ? Math.round((progress.current / progress.total) * 100) : 0
/** Handle inline edit of a cell in the overlay */
@@ -672,6 +694,9 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
>
{cells.map(cell => {
if (!cell.bbox_pct || !cell.text) return null
const col = colPositions.get(cell.col_index)
const cellX = col?.x ?? cell.bbox_pct.x
const cellW = col?.w ?? cell.bbox_pct.w
const aspect = imageNaturalSize ? imageNaturalSize.h / imageNaturalSize.w : 4 / 3
const containerH = reconWidth * aspect
const cellHeightPx = containerH * (cell.bbox_pct.h / 100)
@@ -683,9 +708,9 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
contentEditable
suppressContentEditableWarning
style={{
left: `${cell.bbox_pct.x}%`,
left: `${cellX}%`,
top: `${cell.bbox_pct.y}%`,
width: `${cell.bbox_pct.w}%`,
width: `${cellW}%`,
height: `${cell.bbox_pct.h}%`,
fontSize: `${fontSize}px`,
fontWeight: globalBold ? 'bold' : (cell.is_bold ? 'bold' : 'normal'),