feat: implement hybrid image extraction and memory management

Backend:
- Add hybrid image extraction for Direct track (inline image blocks)
- Add render_inline_image_regions() fallback when OCR doesn't find images
- Add check_document_for_missing_images() for detecting missing images
- Add memory management system (MemoryGuard, ModelManager, ServicePool)
- Update pdf_generator_service to handle HYBRID processing track
- Add ElementType.LOGO for logo extraction

Frontend:
- Fix PDF viewer re-rendering issues with memoization
- Add TaskNotFound component and useTaskValidation hook
- Disable StrictMode due to react-pdf incompatibility
- Fix task detail and results page loading states

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-11-26 10:56:22 +08:00
parent ba8ddf2b68
commit 1afdb822c3
26 changed files with 8273 additions and 366 deletions

View File

@@ -0,0 +1,64 @@
import { useEffect, useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useUploadStore } from '@/store/uploadStore'
import { apiClientV2 } from '@/services/apiV2'
import type { TaskDetail } from '@/types/apiV2'
interface UseTaskValidationResult {
taskId: string | null
taskDetail: TaskDetail | undefined
isLoading: boolean
isNotFound: boolean
clearAndReset: () => void
}
/**
* Hook for validating task existence and handling deleted tasks gracefully.
* Shows loading state first, then either returns task data or marks as not found.
*/
export function useTaskValidation(options?: {
refetchInterval?: number | false | ((query: any) => number | false)
}): UseTaskValidationResult {
const { batchId, clearUpload } = useUploadStore()
const taskId = batchId ? String(batchId) : null
const [isNotFound, setIsNotFound] = useState(false)
const { data: taskDetail, isLoading, error, isFetching } = useQuery({
queryKey: ['taskDetail', taskId],
queryFn: () => apiClientV2.getTask(taskId!),
enabled: !!taskId && !isNotFound,
retry: (failureCount, error: any) => {
// Don't retry on 404
if (error?.response?.status === 404) {
return false
}
return failureCount < 2
},
refetchInterval: options?.refetchInterval ?? false,
// Disable stale time to ensure we check fresh data
staleTime: 0,
})
// Handle 404 error - mark as not found immediately
useEffect(() => {
if (error && (error as any)?.response?.status === 404) {
setIsNotFound(true)
}
}, [error])
// Clear state and store
const clearAndReset = () => {
clearUpload()
setIsNotFound(false)
}
return {
taskId,
taskDetail,
// Show loading if we have a taskId and are still fetching (but not if already marked as not found)
isLoading: !!taskId && !isNotFound && (isLoading || isFetching) && !taskDetail,
isNotFound,
clearAndReset,
}
}