import { useState, useCallback } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Sparkles, Zap, Loader2, Settings, Image as ImageIcon, FileText, Layers } from 'lucide-react' import ImageUpload from './components/ImageUpload' import ModeSelector from './components/ModeSelector' import ResultPanel from './components/ResultPanel' import AdvancedSettings from './components/AdvancedSettings' import PDFProcessor from './components/PDFProcessor' import MetadataForm from './components/MetadataForm' import JobsPanel from './components/JobsPanel' import axios from 'axios' const API_BASE = import.meta.env.VITE_API_URL || '/api' function App() { const [view, setView] = useState('new_job') // 'new_job' | 'jobs' // OCR state const [mode, setMode] = useState('plain_ocr') const [fileType, setFileType] = useState('image') // 'image' or 'pdf' const [image, setImage] = useState(null) const [imagePreview, setImagePreview] = useState(null) const [result, setResult] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [showAdvanced, setShowAdvanced] = useState(false) const [includeCaption, setIncludeCaption] = useState(false) // Form state const [prompt, setPrompt] = useState('') const [findTerm, setFindTerm] = useState('') const [advancedSettings, setAdvancedSettings] = useState({ base_size: 1024, image_size: 640, crop_mode: true, test_compress: false }) // Job metadata const [metadata, setMetadata] = useState({ author: '', book: '', chapter: '', page: '' }) // Editable OCR text (for plain_ocr mode, editable before commit) const [editedOcrText, setEditedOcrText] = useState('') // Job commit state const [commitLoading, setCommitLoading] = useState(false) const [commitResult, setCommitResult] = useState(null) const handleFileTypeChange = useCallback((newType) => { setImage(null) if (imagePreview) URL.revokeObjectURL(imagePreview) setImagePreview(null) setError(null) setResult(null) setFileType(newType) }, [imagePreview]) const handleImageSelect = useCallback((file) => { if (file === null) { setImage(null) if (imagePreview && fileType === 'image') URL.revokeObjectURL(imagePreview) setImagePreview(null) setError(null) setResult(null) } else { setImage(file) setImagePreview(fileType === 'image' ? URL.createObjectURL(file) : file) setError(null) setResult(null) setEditedOcrText('') setCommitResult(null) } }, [imagePreview, fileType]) const handleSubmit = async () => { if (!image) { setError('Please upload an image first') return } setLoading(true) setError(null) setCommitResult(null) try { const formData = new FormData() formData.append('image', image) formData.append('mode', mode) formData.append('prompt', prompt) formData.append('grounding', mode === 'find_ref') formData.append('include_caption', includeCaption) formData.append('find_term', findTerm) formData.append('schema', '') formData.append('base_size', advancedSettings.base_size) formData.append('image_size', advancedSettings.image_size) formData.append('crop_mode', advancedSettings.crop_mode) formData.append('test_compress', advancedSettings.test_compress) const response = await axios.post(`${API_BASE}/ocr`, formData, { headers: { 'Content-Type': 'multipart/form-data' }, }) setResult(response.data) setEditedOcrText(response.data.text || '') setCommitResult(null) } catch (err) { setError(err.response?.data?.detail || err.message || 'An error occurred') } finally { setLoading(false) } } const handleCommitJob = useCallback(async () => { if (!image) return setCommitLoading(true) setCommitResult(null) try { const formData = new FormData() formData.append('image', image) formData.append('author', metadata.author) formData.append('book', metadata.book) formData.append('chapter', metadata.chapter) formData.append('page', metadata.page) formData.append('ocr_text', editedOcrText) formData.append('mode', mode) const response = await axios.post(`${API_BASE}/jobs`, formData, { headers: { 'Content-Type': 'multipart/form-data' }, }) setCommitResult({ success: true, job: response.data }) } catch (err) { setCommitResult({ success: false, error: err.response?.data?.detail || err.message }) } finally { setCommitLoading(false) } }, [image, editedOcrText, metadata, mode]) const handleCopy = useCallback(() => { const text = editedOcrText || result?.text if (text) navigator.clipboard.writeText(text) }, [editedOcrText, result]) const handleDownload = useCallback(() => { const text = editedOcrText || result?.text if (!text) return const ext = { plain_ocr: 'txt', describe: 'txt', find_ref: 'txt', freeform: 'txt' }[mode] || 'txt' const blob = new Blob([text], { type: 'text/plain' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `deepseek-ocr-result.${ext}` a.click() URL.revokeObjectURL(url) }, [result, mode]) return (
{/* Animated background */}
{/* Header */}

DeepSeek OCR

Next-Gen Vision AI

{/* Navigation */}
{/* Main Content */}
{view === 'jobs' ? ( ) : (
{/* Left Panel - Upload & Controls */} {/* File Type Toggle */}
handleFileTypeChange('image')} className={`p-3 rounded-xl text-sm font-medium transition-all flex items-center justify-center gap-2 ${ fileType === 'image' ? 'bg-gradient-to-r from-purple-600 to-cyan-600 text-white' : 'glass text-gray-400 hover:bg-white/5' }`} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > Image OCR handleFileTypeChange('pdf')} className={`p-3 rounded-xl text-sm font-medium transition-all flex items-center justify-center gap-2 ${ fileType === 'pdf' ? 'bg-gradient-to-r from-purple-600 to-cyan-600 text-white' : 'glass text-gray-400 hover:bg-white/5' }`} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > PDF Processing
{/* Job Metadata */} {/* Mode Selector with integrated inputs */} {/* Image/PDF Upload */} {/* Advanced Settings Toggle */} setShowAdvanced(!showAdvanced)} className="w-full glass px-4 py-3 rounded-2xl flex items-center justify-between hover:bg-white/5 transition-colors" whileHover={{ scale: 1.01 }} whileTap={{ scale: 0.99 }} >
Advanced Settings
{/* Advanced Settings Panel */} {showAdvanced && ( )} {/* Action Button / PDF Processor */} {fileType === 'pdf' ? ( ) : ( <>
{loading ? ( <> Processing Magic... ) : ( <> Analyze Image )}
{error && (

{error}

)} )} {/* Right Panel - Results */}
)}
{/* Footer */}
) } export default App