// App.js - Main React Component import React, { useState, useEffect, useRef, useCallback } from 'react'; import './App.css'; import { w3cwebsocket as W3CWebSocket } from "websocket"; // Document Processing Component (Left Zone) const DocumentPanel = ({ onDocumentSelect, onExtract, currentDocument, isProcessing }) => { const [dragActive, setDragActive] = useState(false); const fileInputRef = useRef(null); const handleDrag = (e) => { e.preventDefault(); e.stopPropagation(); if (e.type === "dragenter" || e.type === "dragover") { setDragActive(true); } else if (e.type === "dragleave") { setDragActive(false); } }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); if (e.dataTransfer.files && e.dataTransfer.files[0]) { handleFileSelect(e.dataTransfer.files[0]); } }; const handleFileSelect = async (file) => { // Upload file const formData = new FormData(); formData.append('file', file); try { const response = await fetch('/api/upload', { method: 'POST', body: formData, }); if (response.ok) { const result = await response.json(); onDocumentSelect(result); } else { console.error('Upload failed'); } } catch (error) { console.error('Upload error:', error); } }; const handleFileInput = (e) => { if (e.target.files && e.target.files[0]) { handleFileSelect(e.target.files[0]); } }; const handleDelete = async () => { if (currentDocument) { try { await fetch(`/api/documents/${currentDocument.document_id}`, { method: 'DELETE', }); onDocumentSelect(null); } catch (error) { console.error('Delete error:', error); } } }; const renderThumbnail = () => { if (!currentDocument) { return
Document
; } // Use server-generated thumbnail for all document types const thumbnailUrl = `/api/documents/${currentDocument.document_id}/thumbnail`; return ( {`Miniature { // Fallback if thumbnail generation fails e.target.style.display = 'none'; e.target.nextSibling.style.display = 'flex'; }} /> ); }; return (

Document Processing

Upload and intelligent analysis of your documents

{!currentDocument ? (
fileInputRef.current?.click()} >
+

Drop your document here

or click to browse your files

PDF • JPG • PNG • GIF • WebP • BMP • TIFF
) : (

{currentDocument.filename}

{(currentDocument.file_size / 1024).toFixed(1)} KB
{currentDocument.status}
{/* Document thumbnail with PDF support */}
{renderThumbnail()}
📄 {currentDocument.filename}
{/* Horizontal action buttons */}
)}
); }; // Enhanced Results Component (Right Zone) const ResultsPanel = ({ extractionResult }) => { const [copiedText, setCopiedText] = useState(''); const getMetricData = (result, key) => { if (!result || result[key] === undefined || result[key] === null) { return { value: 0, display: 'N/A', quality: 'poor' }; } const value = typeof result[key] === 'number' ? result[key] : parseFloat(result[key]) || 0; // Keep decimal precision for more realistic display const percentage = Math.round(value * 1000) / 10; // One decimal place let quality = 'poor'; if (percentage >= 90) quality = 'excellent'; else if (percentage >= 75) quality = 'good'; else if (percentage >= 50) quality = 'average'; return { value: percentage, display: `${percentage.toFixed(1)}%`, quality, color: quality === 'excellent' ? '#34C759' : quality === 'good' ? '#007AFF' : quality === 'average' ? '#FF9500' : '#FF3B30' }; }; const copyToClipboard = async () => { const text = formatExtractedText(extractionResult); try { await navigator.clipboard.writeText(text); setCopiedText('Copied!'); setTimeout(() => setCopiedText(''), 2000); } catch (err) { setCopiedText('Error'); setTimeout(() => setCopiedText(''), 2000); } }; const formatExtractedText = (result) => { if (!result) return ''; let text = ''; // Header with metadata text += `=====================================\n`; text += ` DOCUMENT ANALYSIS REPORT\n`; text += `=====================================\n\n`; // Document information if (result.document_type) { text += `DOCUMENT TYPE: ${result.document_type}\n`; } if (result.confidence_level) { text += `CONFIDENCE LEVEL: ${(result.confidence_level * 100).toFixed(1)}%\n`; } if (result.processing_time) { text += `PROCESSING TIME: ${result.processing_time}\n`; } text += `\n`; // Analysis scores text += `ANALYSIS SCORES:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; const imageQuality = getMetricData(result, 'image_quality_score'); const businessLogic = getMetricData(result, 'business_logic_score'); const infoRelevance = getMetricData(result, 'information_relevance_score'); text += ` • Image quality..........: ${imageQuality.display}\n`; text += ` • Business logic.........: ${businessLogic.display}\n`; text += ` • Information relevance..: ${infoRelevance.display}\n\n`; // OCR content if (result.ocr_text) { text += `EXTRACTED TEXT:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; text += `${result.ocr_text}\n\n`; } // Structured data if (result.key_fields && result.key_fields.length > 0) { text += `IDENTIFIED KEY FIELDS:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; result.key_fields.forEach((field, index) => { text += ` ${index + 1}. ${field.field}: ${field.value}\n`; if (field.confidence) { text += ` Confidence: ${(field.confidence * 100).toFixed(1)}%\n`; } }); text += '\n'; } // Dates if (result.dates && result.dates.length > 0) { text += `DETECTED DATES:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; result.dates.forEach((date, index) => { text += ` ${index + 1}. ${date.date_type}: ${date.date_value}\n`; if (date.confidence) { text += ` Confidence: ${(date.confidence * 100).toFixed(1)}%\n`; } }); text += '\n'; } // Amounts if (result.amounts && result.amounts.length > 0) { text += `IDENTIFIED AMOUNTS:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; result.amounts.forEach((amount, index) => { text += ` ${index + 1}. ${amount.amount_type}: ${amount.amount_value}`; if (amount.currency) text += ` ${amount.currency}`; text += '\n'; if (amount.confidence) { text += ` Confidence: ${(amount.confidence * 100).toFixed(1)}%\n`; } }); text += '\n'; } // Named entities if (result.entities && result.entities.length > 0) { text += `RECOGNIZED ENTITIES:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; const groupedEntities = {}; result.entities.forEach(entity => { if (!groupedEntities[entity.entity_type]) { groupedEntities[entity.entity_type] = []; } groupedEntities[entity.entity_type].push(entity); }); Object.entries(groupedEntities).forEach(([type, entities]) => { text += ` ${type}:\n`; entities.forEach(entity => { text += ` • ${entity.entity_value}`; if (entity.confidence) { text += ` (${(entity.confidence * 100).toFixed(1)}%)`; } text += '\n'; }); }); text += '\n'; } // Analysis summary if (result.summary) { text += `ANALYSIS SUMMARY:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; if (result.summary.total_fields) { text += ` • Extracted fields: ${result.summary.total_fields}\n`; } if (result.summary.pages_processed) { text += ` • Pages processed: ${result.summary.pages_processed}\n`; } if (result.summary.accuracy_score) { text += ` • Accuracy score: ${(result.summary.accuracy_score * 100).toFixed(1)}%\n`; } } // AI feedback if (result.supervisor_feedback) { text += `\nAI ANALYSIS:\n`; text += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`; text += `${result.supervisor_feedback}\n`; } text += `\n=====================================\n`; text += `Generated on ${new Date().toLocaleString('en-US')}\n`; text += `=====================================`; return text; }; const imageQuality = getMetricData(extractionResult, 'image_quality_score'); const businessLogic = getMetricData(extractionResult, 'business_logic_score'); const infoRelevance = getMetricData(extractionResult, 'information_relevance_score'); return (

Analysis Results

Performance metrics and extracted data

{/* Enhanced metrics */}
Image Quality
{imageQuality.display}
Business Logic
{businessLogic.display}
Info Relevance
{infoRelevance.display}
{/* Enhanced extracted content zone */}

Extracted Data

{extractionResult ? formatExtractedText(extractionResult) : ''}
); }; // Real Terminal with actual system logs const Terminal = ({ logs }) => { const terminalRef = useRef(null); useEffect(() => { if (terminalRef.current) { terminalRef.current.scrollTop = terminalRef.current.scrollHeight; } }, [logs]); return (
System Terminal
{logs.map((log, index) => { let logClass = 'log-info'; let content = ''; if (log.type === 'log') { logClass = 'log-message'; content = log.content; } else { content = log.content; if (log.type === 'error') logClass = 'log-error'; else if (log.type === 'success') logClass = 'log-success'; else if (log.type === 'warning') logClass = 'log-warning'; else if (log.type === 'system') logClass = 'log-system'; } return
{content}
; })}
); }; // Main App Component const App = () => { const [currentDocument, setCurrentDocument] = useState(null); const [extractionResult, setExtractionResult] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [logs, setLogs] = useState([]); const [isConnected, setIsConnected] = useState(false); const wsClient = useRef(null); const addLog = useCallback((log) => { setLogs(prevLogs => [...prevLogs, log].slice(-100)); // Keep last 100 logs }, []); useEffect(() => { const connectWebSocket = () => { // Determine WebSocket protocol based on browser's protocol const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"; // Construct the WebSocket URL based on the browser's host const wsUrl = `${wsProtocol}//${window.location.host}/ws`; console.log(`Attempting to connect to WebSocket at: ${wsUrl}`); const client = new W3CWebSocket(wsUrl); wsClient.current = client; client.onopen = () => { console.log("WebSocket Client Connected"); setIsConnected(true); addLog({ type: 'system', content: `[${new Date().toLocaleTimeString()}] System Connected to backend.` }); }; client.onmessage = (message) => { const data = JSON.parse(message.data); if (data.type === 'log') { // This is a real log from the backend addLog({ type: 'log', content: data.content }); } else { // This is a direct message (e.g., upload success) addLog({ type: data.type, content: `[${data.timestamp}] ${data.message}` }); } }; client.onerror = (error) => { console.error("WebSocket Error: ", error); setIsConnected(false); addLog({ type: 'error', content: `[${new Date().toLocaleTimeString()}] WebSocket connection error. See browser console for details.` }); }; client.onclose = () => { console.log("WebSocket Client Disconnected"); setIsConnected(false); addLog({ type: 'system', content: `[${new Date().toLocaleTimeString()}] System Disconnected. Attempting to reconnect in 5s...` }); // Implement reconnection logic setTimeout(connectWebSocket, 5000); }; }; connectWebSocket(); // Cleanup on component unmount return () => { if (wsClient.current) { wsClient.current.close(); } }; }, [addLog]); // Re-run effect if addLog changes const handleDocumentSelect = (document) => { setCurrentDocument(document); setExtractionResult(null); addLog({ type: 'system', content: `[${new Date().toLocaleTimeString()}] Document "${document.filename}" uploaded successfully (${(document.file_size / 1024).toFixed(1)} KB)` }); addLog({ type: 'info', content: 'Preparing multi-agent analysis pipeline...' }); }; const handleExtract = async (documentId) => { if (!documentId) return; setIsProcessing(true); setExtractionResult(null); // Clear previous results try { // Start the extraction process const response = await fetch(`/api/extract/${documentId}`, { method: 'POST', }); if (response.ok) { const result = await response.json(); console.log('Extraction result:', result); // Debug log setExtractionResult(result); // Final success message addLog({ type: 'system', content: 'Analysis results loaded successfully' }); } else { const errorText = await response.text(); console.error('Extraction error response:', errorText); addLog({ type: 'error', content: `Error during analysis: ${response.status}` }); } } catch (error) { console.error('Extraction error:', error); addLog({ type: 'error', content: `Network error: ${error.message}` }); } finally { setIsProcessing(false); } }; return (
{/* Header */}
OCR/LAD/RAD Intelligence Platform
{isConnected ? 'System Connected' : 'System Disconnected'}
{/* Main content - 2 columns */}
{/* Terminal at bottom with real system logs */}
); }; export default App;