feat: refactor dual-track architecture (Phase 1-5)

## Backend Changes
- **Service Layer Refactoring**:
  - Add ProcessingOrchestrator for unified document processing
  - Add PDFTableRenderer for table rendering extraction
  - Add PDFFontManager for font management with CJK support
  - Add MemoryPolicyEngine (73% code reduction from MemoryGuard)

- **Bug Fixes**:
  - Fix Direct Track table row span calculation
  - Fix OCR Track image path handling
  - Add cell_boxes coordinate validation
  - Filter out small decorative images
  - Add covering image detection

## Frontend Changes
- **State Management**:
  - Add TaskStore for centralized task state management
  - Add localStorage persistence for recent tasks
  - Add processing state tracking

- **Type Consolidation**:
  - Merge shared types from api.ts to apiV2.ts
  - Update imports in authStore, uploadStore, ResultsTable, SettingsPage

- **Page Integration**:
  - Integrate TaskStore in ProcessingPage and TaskDetailPage
  - Update useTaskValidation hook with cache sync

## Testing
- Direct Track: edit.pdf (3 pages, 1.281s), edit3.pdf (2 pages, 0.203s)
- Cell boxes validation: 43 valid, 0 invalid
- Table merging: 12 merged cells verified

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-07 07:18:27 +08:00
parent 8265be1741
commit eff9b0bcd5
19 changed files with 3637 additions and 173 deletions

View File

@@ -16,6 +16,7 @@ import TableDetectionSelector from '@/components/TableDetectionSelector'
import ProcessingTrackSelector from '@/components/ProcessingTrackSelector'
import TaskNotFound from '@/components/TaskNotFound'
import { useTaskValidation } from '@/hooks/useTaskValidation'
import { useTaskStore, useProcessingState } from '@/store/taskStore'
import type { LayoutModel, ProcessingOptions, PreprocessingMode, PreprocessingConfig, TableDetectionConfig, ProcessingTrack } from '@/types/apiV2'
export default function ProcessingPage() {
@@ -23,6 +24,10 @@ export default function ProcessingPage() {
const navigate = useNavigate()
const { toast } = useToast()
// Use TaskStore for processing state management
const { startProcessing, stopProcessing, updateTaskStatus } = useTaskStore()
const processingState = useProcessingState()
// Use shared hook for task validation
const { taskId, taskDetail, isLoading: isValidating, isNotFound, clearAndReset } = useTaskValidation({
refetchInterval: (query) => {
@@ -93,9 +98,16 @@ export default function ProcessingPage() {
table_detection: tableDetectionConfig,
}
// Update TaskStore processing state
startProcessing(forceTrack, options)
return apiClientV2.startTask(taskId!, options)
},
onSuccess: () => {
// Update task status in cache
if (taskId) {
updateTaskStatus(taskId, 'processing', forceTrack || undefined)
}
toast({
title: '開始處理',
description: 'OCR 處理已開始',
@@ -103,6 +115,8 @@ export default function ProcessingPage() {
})
},
onError: (error: any) => {
// Stop processing state on error
stopProcessing()
toast({
title: t('errors.processingFailed'),
description: error.response?.data?.detail || t('errors.networkError'),
@@ -111,14 +125,25 @@ export default function ProcessingPage() {
},
})
// Auto-redirect when completed
// Handle task status changes - update store and redirect when completed
useEffect(() => {
if (taskDetail?.status === 'completed') {
// Stop processing state and update cache
stopProcessing()
if (taskId) {
updateTaskStatus(taskId, 'completed', taskDetail.processing_track)
}
setTimeout(() => {
navigate('/tasks')
}, 1000)
} else if (taskDetail?.status === 'failed') {
// Stop processing state on failure
stopProcessing()
if (taskId) {
updateTaskStatus(taskId, 'failed')
}
}
}, [taskDetail?.status, navigate])
}, [taskDetail?.status, taskDetail?.processing_track, taskId, navigate, stopProcessing, updateTaskStatus])
const handleStartProcessing = () => {
processOCRMutation.mutate()