import React, { useEffect, useMemo, useRef, useState } from "react"; import { createRoot } from "react-dom/client"; import { Activity, BarChart3, CheckCircle2, ChevronRight, Clock3, Download, FileChartColumn, FileText, Layers3, LoaderCircle, RefreshCcw, Search, ShieldCheck, Sparkles, Upload, X, AlertTriangle } from "lucide-react"; import "./styles.css"; const API = ""; const MODELS = ["xgboost", "logistic_regression", "random_forest", "linear_svm", "sentence_embedding_lr"]; async function jsonRequest(url, options) { const response = await fetch(`${API}${url}`, options); const body = await response.json().catch(() => ({})); if (!response.ok) throw new Error(body.detail || body.error || `Request failed (${response.status})`); return body; } function App() { const [view, setView] = useState("analysis"); const [inputMode, setInputMode] = useState("upload"); const [samples, setSamples] = useState([]); const [sampleId, setSampleId] = useState(""); const [file, setFile] = useState(null); const [result, setResult] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [batchFiles, setBatchFiles] = useState([]); const [batchResults, setBatchResults] = useState([]); const [analyticsModel, setAnalyticsModel] = useState("xgboost"); const [analytics, setAnalytics] = useState(null); const fileInput = useRef(null); useEffect(() => { jsonRequest("/api/samples").then(setSamples).catch((e) => setError(e.message)); }, []); useEffect(() => { if (view === "analytics") jsonRequest(`/api/analytics?model=${analyticsModel}`).then(setAnalytics).catch((e) => setError(e.message)); }, [view, analyticsModel]); const activeSample = samples.find((item) => item.id === sampleId); const previewUrl = file ? URL.createObjectURL(file) : sampleId ? `/api/samples/${sampleId}/preview` : ""; async function analyze() { setError(""); setResult(null); setLoading(true); try { if (inputMode === "upload") { if (!file) throw new Error("Choose a PNG, JPG, JPEG, or PDF document first."); const data = new FormData(); data.append("file", file); setResult(await jsonRequest("/api/process", { method: "POST", body: data })); } else { if (!sampleId) throw new Error("Select a sample document first."); setResult(await jsonRequest(`/api/process-sample/${sampleId}`, { method: "POST" })); } } catch (e) { setError(e.message); } finally { setLoading(false); } } async function runBatch() { if (!batchFiles.length) return setError("Choose at least one document for batch processing."); setError(""); setLoading(true); try { const data = new FormData(); batchFiles.forEach((item) => data.append("files", item)); setBatchResults(await jsonRequest("/api/process-batch", { method: "POST", body: data })); } catch (e) { setError(e.message); } finally { setLoading(false); } } function resetAnalysis() { setFile(null); setSampleId(""); setResult(null); setError(""); } return
Document_intelligenceDocument intelligence studio
Pipeline online CPU inference
{error &&
{error}
} {view === "analysis" && } {view === "batch" && } {view === "analytics" && }
; } function NavButton({ icon, label, active, onClick }) { return ; } function AnalysisView({ inputMode, setInputMode, samples, sampleId, setSampleId, activeSample, file, setFile, previewUrl, result, loading, analyze, resetAnalysis, fileInput }) { return <> Reset}/>
{inputMode === "sample" && }
Input document

{file?.name || activeSample?.label || "No document selected"}

{(file || activeSample) && Ready}
{inputMode === "upload" &&
fileInput.current?.click()} onDragOver={(e) => e.preventDefault()} onDrop={(e) => { e.preventDefault(); setFile(e.dataTransfer.files[0]); }}> setFile(e.target.files[0])}/>{file ? "Replace document" : "Choose a document"}PNG, JPG, JPEG, or PDF · maximum 10 MB
} {inputMode === "sample" &&
{activeSample?.label || "Choose a sample above"}{activeSample?.description || "Use a curated document to check the pipeline without uploading a file."}
} {previewUrl && (file?.type?.startsWith("image/") || activeSample) ?
Document preview
: previewUrl ?
PDF document selected
:
Preview appears here after selecting a document
}
; } function ResultsPanel({ result, loading }) { if (loading) return

Processing document

OCR, layout classification, and field extraction are running.

; if (!result) return
Analysis output

Ready for processing

Select a document and run the pipeline to see classification, extracted fields, and routing confidence.

; const cls = result.doc_class.replaceAll("_", " "); return
Analysis output

Document decision

{result.needs_review ? "Review" : "Accepted"}
Predicted class{cls}
Class confidence{(result.class_confidence * 100).toFixed(1)}%
} label="OCR words" value={result.ocr_token_count}/>} label="Latency" value={`${result.processing_time_ms} ms`}/>
Structured fields
{Object.entries(result.fields || {}).map(([key, value]) =>
{key.replaceAll("_", " ")}{value ?? "Not detected"}{result.field_confidences?.[key] ? `${(result.field_confidences[key] * 100).toFixed(0)}%` : "—"}
)}
{result.routing_reason || (result.needs_review ? "Manual review recommended" : "Confidence thresholds satisfied")}
; } function Stat({ icon, label, value }) { return
{icon}{label}{value}
; } function BatchView({ batchFiles, setBatchFiles, batchResults, runBatch, loading }) { const input = useRef(null); return <>
Batch input

{batchFiles.length ? `${batchFiles.length} documents selected` : "Select documents"}

setBatchFiles([...e.target.files])}/>
{batchFiles.length ? batchFiles.map((file) =>
{file.name}{(file.size / 1024).toFixed(0)} KB
) :
Your selected documents will appear here.
}
{batchResults.length > 0 &&
Batch output

Processing summary

{batchResults.map((item) => )}
DocumentClassConfidenceDecisionWordsLatency
{item.file_name}{item.error ? Error : item.doc_class}{item.confidence ? `${(item.confidence * 100).toFixed(1)}%` : "—"}{item.error ? item.error : item.needs_review ? "Review" : "Accepted"}{item.words ?? "—"}{item.latency_ms ? `${item.latency_ms} ms` : "—"}
}; } function AnalyticsView({ analyticsModel, setAnalyticsModel, analytics }) { return <>
Confusion matrix

{analyticsModel.replaceAll("_", " ")}

{analytics?.matrix_url ? Normalized confusion matrix :
Matrix artifact not found.
}
Performance report

Classification metrics

; } function MetricsTable({ data }) { if (!data) return
Metrics are not available.
; return
{Object.entries(data).map(([key, value]) => typeof value === "object" ? : null)}
ClassPrecisionRecallF1Support
{key}{fmt(value.precision)}{fmt(value.recall)}{fmt(value["f1-score"])}{value.support ?? "—"}
; } function fmt(value) { return typeof value === "number" ? value.toFixed(3) : "—"; } function PageHeading({ kicker, title, description, action }) { return
{kicker}

{title}

{description}

{action}
; } function downloadJson(result) { downloadBlob(JSON.stringify(result, null, 2), `${result.doc_id}_results.json`, "application/json"); } function downloadCsv(result) { const rows = [["Field Name", "Extracted Value", "Confidence"], ...Object.entries(result.fields || {}).map(([key, value]) => [key, value ?? "", result.field_confidences?.[key] ?? ""])]; downloadBlob(rows.map((row) => row.map((cell) => `"${String(cell).replaceAll('"', '""')}"`).join(",")).join("\n"), `${result.doc_id}_fields.csv`, "text/csv"); } function downloadBlob(content, name, type) { const url = URL.createObjectURL(new Blob([content], {type})); const anchor = document.createElement("a"); anchor.href = url; anchor.download = name; anchor.click(); URL.revokeObjectURL(url); } createRoot(document.getElementById("root")).render();