fix(ocr-pipeline): show sub-columns in reconstruction and LLM review steps
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 27s
CI / test-go-edu-search (push) Successful in 26s
CI / test-python-klausur (push) Failing after 1m54s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 21s
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 27s
CI / test-go-edu-search (push) Successful in 26s
CI / test-python-klausur (push) Failing after 1m54s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 21s
- Add marker/bbox_marker fields to WordEntry type - Add page_ref/column_marker colors to StepReconstruction - Make StepLlmReview table dynamic based on columns_used metadata, showing all detected columns (EN, DE, Example, page_ref, marker) instead of hardcoded EN/DE/Beispiel only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -181,12 +181,14 @@ export interface WordEntry {
|
|||||||
german: string
|
german: string
|
||||||
example: string
|
example: string
|
||||||
source_page?: string
|
source_page?: string
|
||||||
|
marker?: string
|
||||||
confidence: number
|
confidence: number
|
||||||
bbox: WordBbox
|
bbox: WordBbox
|
||||||
bbox_en: WordBbox | null
|
bbox_en: WordBbox | null
|
||||||
bbox_de: WordBbox | null
|
bbox_de: WordBbox | null
|
||||||
bbox_ex: WordBbox | null
|
bbox_ex: WordBbox | null
|
||||||
bbox_ref?: WordBbox | null
|
bbox_ref?: WordBbox | null
|
||||||
|
bbox_marker?: WordBbox | null
|
||||||
status?: 'pending' | 'confirmed' | 'edited' | 'skipped'
|
status?: 'pending' | 'confirmed' | 'edited' | 'skipped'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import type { GridResult, WordEntry } from '@/app/(admin)/ai/ocr-pipeline/types'
|
import type { GridResult, WordEntry, ColumnMeta } from '@/app/(admin)/ai/ocr-pipeline/types'
|
||||||
|
|
||||||
const KLAUSUR_API = '/klausur-api'
|
const KLAUSUR_API = '/klausur-api'
|
||||||
|
|
||||||
@@ -34,6 +34,26 @@ const FIELD_LABELS: Record<string, string> = {
|
|||||||
english: 'EN',
|
english: 'EN',
|
||||||
german: 'DE',
|
german: 'DE',
|
||||||
example: 'Beispiel',
|
example: 'Beispiel',
|
||||||
|
source_page: 'Seite',
|
||||||
|
marker: 'Marker',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Map column type to WordEntry field name */
|
||||||
|
const COL_TYPE_TO_FIELD: Record<string, string> = {
|
||||||
|
column_en: 'english',
|
||||||
|
column_de: 'german',
|
||||||
|
column_example: 'example',
|
||||||
|
page_ref: 'source_page',
|
||||||
|
column_marker: 'marker',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Column type → color class */
|
||||||
|
const COL_TYPE_COLOR: Record<string, string> = {
|
||||||
|
column_en: 'text-blue-600 dark:text-blue-400',
|
||||||
|
column_de: 'text-green-600 dark:text-green-400',
|
||||||
|
column_example: 'text-orange-600 dark:text-orange-400',
|
||||||
|
page_ref: 'text-cyan-600 dark:text-cyan-400',
|
||||||
|
column_marker: 'text-gray-500 dark:text-gray-400',
|
||||||
}
|
}
|
||||||
|
|
||||||
type RowStatus = 'pending' | 'active' | 'reviewed' | 'corrected' | 'skipped'
|
type RowStatus = 'pending' | 'active' | 'reviewed' | 'corrected' | 'skipped'
|
||||||
@@ -51,6 +71,7 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
|
|||||||
|
|
||||||
// Full vocab table state
|
// Full vocab table state
|
||||||
const [vocabEntries, setVocabEntries] = useState<WordEntry[]>([])
|
const [vocabEntries, setVocabEntries] = useState<WordEntry[]>([])
|
||||||
|
const [columnsUsed, setColumnsUsed] = useState<ColumnMeta[]>([])
|
||||||
const [activeRowIndices, setActiveRowIndices] = useState<Set<number>>(new Set())
|
const [activeRowIndices, setActiveRowIndices] = useState<Set<number>>(new Set())
|
||||||
const [reviewedRows, setReviewedRows] = useState<Set<number>>(new Set())
|
const [reviewedRows, setReviewedRows] = useState<Set<number>>(new Set())
|
||||||
const [skippedRows, setSkippedRows] = useState<Set<number>>(new Set())
|
const [skippedRows, setSkippedRows] = useState<Set<number>>(new Set())
|
||||||
@@ -86,6 +107,7 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
|
|||||||
|
|
||||||
const entries = wordResult.vocab_entries || wordResult.entries || []
|
const entries = wordResult.vocab_entries || wordResult.entries || []
|
||||||
setVocabEntries(entries)
|
setVocabEntries(entries)
|
||||||
|
setColumnsUsed(wordResult.columns_used || [])
|
||||||
|
|
||||||
// Check if LLM review was already run
|
// Check if LLM review was already run
|
||||||
const llmReview = wordResult.llm_review
|
const llmReview = wordResult.llm_review
|
||||||
@@ -458,9 +480,23 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
|
|||||||
<thead className="sticky top-0 z-10">
|
<thead className="sticky top-0 z-10">
|
||||||
<tr className="bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
<tr className="bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
||||||
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium w-10">#</th>
|
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium w-10">#</th>
|
||||||
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">EN</th>
|
{columnsUsed.length > 0 ? (
|
||||||
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">DE</th>
|
columnsUsed.map((col, i) => {
|
||||||
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">Beispiel</th>
|
const field = COL_TYPE_TO_FIELD[col.type]
|
||||||
|
if (!field) return null
|
||||||
|
return (
|
||||||
|
<th key={i} className={`px-2 py-2 text-left font-medium ${COL_TYPE_COLOR[col.type] || 'text-gray-500 dark:text-gray-400'}`}>
|
||||||
|
{FIELD_LABELS[field] || field}
|
||||||
|
</th>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">EN</th>
|
||||||
|
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">DE</th>
|
||||||
|
<th className="px-2 py-2 text-left text-gray-500 dark:text-gray-400 font-medium">Beispiel</th>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<th className="px-2 py-2 text-center text-gray-500 dark:text-gray-400 font-medium w-16">Status</th>
|
<th className="px-2 py-2 text-center text-gray-500 dark:text-gray-400 font-medium w-16">Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -486,15 +522,30 @@ export function StepLlmReview({ sessionId, onNext }: StepLlmReviewProps) {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<td className="px-2 py-1.5 text-gray-400 font-mono text-xs">{idx}</td>
|
<td className="px-2 py-1.5 text-gray-400 font-mono text-xs">{idx}</td>
|
||||||
<td className="px-2 py-1.5">
|
{columnsUsed.length > 0 ? (
|
||||||
<CellContent text={entry.english} field="english" rowChanges={rowChanges} />
|
columnsUsed.map((col, i) => {
|
||||||
</td>
|
const field = COL_TYPE_TO_FIELD[col.type]
|
||||||
<td className="px-2 py-1.5">
|
if (!field) return null
|
||||||
<CellContent text={entry.german} field="german" rowChanges={rowChanges} />
|
const text = (entry as Record<string, unknown>)[field] as string || ''
|
||||||
</td>
|
return (
|
||||||
<td className="px-2 py-1.5 text-xs">
|
<td key={i} className="px-2 py-1.5 text-xs">
|
||||||
<CellContent text={entry.example} field="example" rowChanges={rowChanges} />
|
<CellContent text={text} field={field} rowChanges={rowChanges} />
|
||||||
</td>
|
</td>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<td className="px-2 py-1.5">
|
||||||
|
<CellContent text={entry.english} field="english" rowChanges={rowChanges} />
|
||||||
|
</td>
|
||||||
|
<td className="px-2 py-1.5">
|
||||||
|
<CellContent text={entry.german} field="german" rowChanges={rowChanges} />
|
||||||
|
</td>
|
||||||
|
<td className="px-2 py-1.5 text-xs">
|
||||||
|
<CellContent text={entry.example} field="example" rowChanges={rowChanges} />
|
||||||
|
</td>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<td className="px-2 py-1.5 text-center">
|
<td className="px-2 py-1.5 text-center">
|
||||||
<StatusIcon status={rowStatus} />
|
<StatusIcon status={rowStatus} />
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
|
|||||||
column_de: 'border-green-400/40 focus:border-green-500',
|
column_de: 'border-green-400/40 focus:border-green-500',
|
||||||
column_example: 'border-orange-400/40 focus:border-orange-500',
|
column_example: 'border-orange-400/40 focus:border-orange-500',
|
||||||
column_text: 'border-purple-400/40 focus:border-purple-500',
|
column_text: 'border-purple-400/40 focus:border-purple-500',
|
||||||
|
page_ref: 'border-cyan-400/40 focus:border-cyan-500',
|
||||||
|
column_marker: 'border-gray-400/40 focus:border-gray-500',
|
||||||
}
|
}
|
||||||
return colors[colType] || 'border-gray-400/40 focus:border-gray-500'
|
return colors[colType] || 'border-gray-400/40 focus:border-gray-500'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user