feat: add table detection options and scan artifact removal

- Add TableDetectionSelector component for wired/wireless/region detection
- Add CV-based table line detector module (disabled due to poor performance)
- Add scan artifact removal preprocessing step (removes faint horizontal lines)
- Add PreprocessingConfig schema with remove_scan_artifacts option
- Update frontend PreprocessingSettings with scan artifact toggle
- Integrate table detection config into ProcessingPage
- Archive extract-table-cell-boxes proposal

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-11-30 13:21:50 +08:00
parent f5a2c8a750
commit 95ae1f1bdb
17 changed files with 1906 additions and 344 deletions

View File

@@ -0,0 +1,124 @@
import { cn } from '@/lib/utils'
import { Checkbox } from '@/components/ui/checkbox'
import { Table, Grid3X3, Rows3 } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import type { TableDetectionConfig } from '@/types/apiV2'
interface TableDetectionSelectorProps {
value: TableDetectionConfig
onChange: (config: TableDetectionConfig) => void
disabled?: boolean
className?: string
}
interface DetectionOption {
key: keyof TableDetectionConfig
icon: React.ReactNode
labelKey: string
descKey: string
}
const DETECTION_OPTIONS: DetectionOption[] = [
{
key: 'enable_wired_table',
icon: <Grid3X3 className="w-5 h-5" />,
labelKey: 'processing.tableDetection.wired',
descKey: 'processing.tableDetection.wiredDesc',
},
{
key: 'enable_wireless_table',
icon: <Rows3 className="w-5 h-5" />,
labelKey: 'processing.tableDetection.wireless',
descKey: 'processing.tableDetection.wirelessDesc',
},
{
key: 'enable_region_detection',
icon: <Table className="w-5 h-5" />,
labelKey: 'processing.tableDetection.region',
descKey: 'processing.tableDetection.regionDesc',
},
]
export default function TableDetectionSelector({
value,
onChange,
disabled = false,
className,
}: TableDetectionSelectorProps) {
const { t } = useTranslation()
const handleOptionChange = (key: keyof TableDetectionConfig, checked: boolean) => {
onChange({
...value,
[key]: checked,
})
}
return (
<div className={cn('border rounded-lg p-4 bg-white', className)}>
{/* Header */}
<div className="flex items-center gap-2 mb-4">
<Table className="w-5 h-5 text-gray-600" />
<h3 className="text-lg font-semibold text-gray-900">{t('processing.tableDetection.title')}</h3>
</div>
{/* Detection Options */}
<div className="space-y-3">
{DETECTION_OPTIONS.map((option) => {
const isChecked = value[option.key]
return (
<label
key={option.key}
className={cn(
'flex items-start gap-4 p-4 rounded-lg border-2 transition-all cursor-pointer',
isChecked
? 'border-blue-500 bg-blue-50'
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50',
disabled && 'opacity-50 cursor-not-allowed'
)}
>
{/* Checkbox */}
<Checkbox
checked={isChecked}
onCheckedChange={(checked) => handleOptionChange(option.key, checked)}
disabled={disabled}
className="mt-0.5"
/>
{/* Icon */}
<div
className={cn(
'p-2 rounded-lg flex-shrink-0',
isChecked ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-500'
)}
>
{option.icon}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<span
className={cn(
'font-medium',
isChecked ? 'text-blue-700' : 'text-gray-900'
)}
>
{t(option.labelKey)}
</span>
<p className="text-sm text-gray-500 mt-1">{t(option.descKey)}</p>
</div>
</label>
)
})}
</div>
{/* Info Note */}
<div className="mt-4 p-3 bg-amber-50 border border-amber-200 rounded-md">
<p className="text-sm text-amber-800">
{t('processing.tableDetection.note')}
</p>
</div>
</div>
)
}