test
This commit is contained in:
148
frontend/src/components/ProcessingTrackSelector.tsx
Normal file
148
frontend/src/components/ProcessingTrackSelector.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Cpu, FileText, Sparkles, Info } from 'lucide-react'
|
||||
import type { ProcessingTrack, DocumentAnalysisResponse } from '@/types/apiV2'
|
||||
|
||||
interface ProcessingTrackSelectorProps {
|
||||
value: ProcessingTrack | null // null means "use system recommendation"
|
||||
onChange: (track: ProcessingTrack | null) => void
|
||||
documentAnalysis?: DocumentAnalysisResponse | null
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function ProcessingTrackSelector({
|
||||
value,
|
||||
onChange,
|
||||
documentAnalysis,
|
||||
disabled = false,
|
||||
}: ProcessingTrackSelectorProps) {
|
||||
const recommendedTrack = documentAnalysis?.recommended_track
|
||||
|
||||
const tracks = [
|
||||
{
|
||||
id: null as ProcessingTrack | null,
|
||||
name: '自動選擇',
|
||||
description: '根據文件類型自動選擇最佳處理方式',
|
||||
icon: Sparkles,
|
||||
color: 'text-purple-600',
|
||||
bgColor: 'bg-purple-50',
|
||||
borderColor: 'border-purple-200',
|
||||
recommended: false,
|
||||
},
|
||||
{
|
||||
id: 'direct' as ProcessingTrack,
|
||||
name: '直接提取 (DIRECT)',
|
||||
description: '從 PDF 中直接提取文字圖層,適用於可編輯 PDF',
|
||||
icon: FileText,
|
||||
color: 'text-blue-600',
|
||||
bgColor: 'bg-blue-50',
|
||||
borderColor: 'border-blue-200',
|
||||
recommended: recommendedTrack === 'direct',
|
||||
},
|
||||
{
|
||||
id: 'ocr' as ProcessingTrack,
|
||||
name: 'OCR 識別',
|
||||
description: '使用光學字元識別處理圖片或掃描文件',
|
||||
icon: Cpu,
|
||||
color: 'text-green-600',
|
||||
bgColor: 'bg-green-50',
|
||||
borderColor: 'border-green-200',
|
||||
recommended: recommendedTrack === 'ocr',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-primary/10 rounded-lg">
|
||||
<Sparkles className="w-5 h-5 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>處理方式選擇</CardTitle>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
選擇文件的處理方式,或讓系統自動判斷
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{/* Info about override */}
|
||||
{value !== null && recommendedTrack && value !== recommendedTrack && (
|
||||
<div className="flex items-start gap-2 p-3 bg-amber-50 border border-amber-200 rounded-lg">
|
||||
<Info className="w-4 h-4 text-amber-600 flex-shrink-0 mt-0.5" />
|
||||
<p className="text-sm text-amber-800">
|
||||
您已覆蓋系統建議。系統原本建議使用「{recommendedTrack === 'direct' ? '直接提取' : 'OCR 識別'}」方式處理此文件。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Track options */}
|
||||
<div className="grid gap-3">
|
||||
{tracks.map((track) => {
|
||||
const isSelected = value === track.id
|
||||
const Icon = track.icon
|
||||
|
||||
return (
|
||||
<button
|
||||
key={track.id ?? 'auto'}
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(track.id)}
|
||||
className={`
|
||||
w-full p-4 rounded-lg border-2 text-left transition-all
|
||||
${isSelected
|
||||
? `${track.borderColor} ${track.bgColor}`
|
||||
: 'border-border hover:border-primary/30 hover:bg-muted/30'
|
||||
}
|
||||
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
||||
`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={`p-2 rounded-lg ${isSelected ? track.bgColor : 'bg-muted'}`}>
|
||||
<Icon className={`w-5 h-5 ${isSelected ? track.color : 'text-muted-foreground'}`} />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={`font-medium ${isSelected ? track.color : ''}`}>
|
||||
{track.name}
|
||||
</span>
|
||||
{track.recommended && (
|
||||
<Badge variant="outline" className="text-xs bg-white">
|
||||
系統建議
|
||||
</Badge>
|
||||
)}
|
||||
{isSelected && (
|
||||
<Badge variant="default" className="text-xs">
|
||||
已選擇
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{track.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Current analysis info */}
|
||||
{documentAnalysis && (
|
||||
<div className="pt-3 border-t border-border">
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
||||
<span>文件分析信心度: {(documentAnalysis.confidence * 100).toFixed(0)}%</span>
|
||||
{documentAnalysis.page_count && (
|
||||
<span>頁數: {documentAnalysis.page_count}</span>
|
||||
)}
|
||||
{documentAnalysis.text_coverage !== null && (
|
||||
<span>文字覆蓋率: {(documentAnalysis.text_coverage * 100).toFixed(1)}%</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user