import { useState, useCallback } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Sparkles, Zap, Loader2, Settings, Image as ImageIcon, FileText } 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 axios from 'axios' const API_BASE = import.meta.env.VITE_API_URL || '/api' function App() { 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 }) const handleFileTypeChange = useCallback((newType) => { // Clear current file when switching types setImage(null) if (imagePreview) { URL.revokeObjectURL(imagePreview) } setImagePreview(null) setError(null) setResult(null) setFileType(newType) }, [imagePreview]) const handleImageSelect = useCallback((file) => { if (file === null) { // Clear everything when removing image setImage(null) if (imagePreview && fileType === 'image') { URL.revokeObjectURL(imagePreview) } setImagePreview(null) setError(null) setResult(null) } else { setImage(file) // Only create preview URL for images, not PDFs if (fileType === 'image') { setImagePreview(URL.createObjectURL(file)) } else { setImagePreview(file) // Just store the file for PDFs } setError(null) setResult(null) } }, [imagePreview, fileType]) const handleSubmit = async () => { if (!image) { setError('Please upload an image first') return } setLoading(true) setError(null) try { const formData = new FormData() formData.append('image', image) formData.append('mode', mode) formData.append('prompt', prompt) // Enable grounding only for find mode 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) } catch (err) { setError(err.response?.data?.detail || err.message || 'An error occurred') } finally { setLoading(false) } } const handleCopy = useCallback(() => { if (result?.text) { navigator.clipboard.writeText(result.text) } }, [result]) const handleDownload = useCallback(() => { if (!result?.text) return const extensions = { plain_ocr: 'txt', describe: 'txt', find_ref: 'txt', freeform: 'txt', } const ext = extensions[mode] || 'txt' const blob = new Blob([result.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

{/* Main Content */}
{/* 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
{/* 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