Spaces:
Sleeping
Sleeping
| import React, { useState } from "react"; | |
| export default function App() { | |
| const [file, setFile] = useState(null); | |
| const [loading, setLoading] = useState(false); | |
| const [result, setResult] = useState(null); | |
| const [error, setError] = useState(null); | |
| const handleFileChange = (e) => { | |
| const selectedFile = e.target.files[0]; | |
| if (selectedFile) { | |
| if (selectedFile.type !== "application/pdf") { | |
| setError("Please select a PDF file"); | |
| setFile(null); | |
| return; | |
| } | |
| setFile(selectedFile); | |
| setError(null); | |
| setResult(null); | |
| } | |
| }; | |
| const handleClassify = async () => { | |
| if (!file) { | |
| setError("Please select a PDF file first"); | |
| return; | |
| } | |
| setLoading(true); | |
| setError(null); | |
| setResult(null); | |
| const formData = new FormData(); | |
| formData.append("file", file); | |
| try { | |
| const response = await fetch("/api/classify", { | |
| method: "POST", | |
| body: formData, | |
| }); | |
| if (!response.ok) { | |
| const errorData = await response.json(); | |
| throw new Error(errorData.detail || "Classification failed"); | |
| } | |
| const data = await response.json(); | |
| setResult(data); | |
| } catch (err) { | |
| setError(err.message || "An error occurred during classification"); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleReset = () => { | |
| setFile(null); | |
| setResult(null); | |
| setError(null); | |
| // Reset file input | |
| const fileInput = document.getElementById("pdf-upload"); | |
| if (fileInput) fileInput.value = ""; | |
| }; | |
| return ( | |
| <div | |
| style={{ | |
| fontFamily: "system-ui, -apple-system, sans-serif", | |
| maxWidth: "800px", | |
| margin: "0 auto", | |
| padding: "24px", | |
| lineHeight: 1.6, | |
| }} | |
| > | |
| <div style={{ textAlign: "center", marginBottom: "32px" }}> | |
| <h1 style={{ margin: "0 0 8px 0", color: "#1a1a1a" }}> | |
| 📄 Document Classifier | |
| </h1> | |
| <p style={{ color: "#666", margin: "0" }}> | |
| Upload a PDF file to classify its document type using BERT-tiny | |
| </p> | |
| </div> | |
| <div | |
| style={{ | |
| border: "2px dashed #ddd", | |
| borderRadius: "12px", | |
| padding: "32px", | |
| textAlign: "center", | |
| backgroundColor: "#fafafa", | |
| marginBottom: "24px", | |
| }} | |
| > | |
| <input | |
| id="pdf-upload" | |
| type="file" | |
| accept=".pdf" | |
| onChange={handleFileChange} | |
| style={{ display: "none" }} | |
| /> | |
| <label | |
| htmlFor="pdf-upload" | |
| style={{ | |
| display: "inline-block", | |
| padding: "12px 24px", | |
| backgroundColor: "#4f46e5", | |
| color: "white", | |
| borderRadius: "8px", | |
| cursor: "pointer", | |
| fontSize: "16px", | |
| fontWeight: "500", | |
| marginBottom: "16px", | |
| transition: "background-color 0.2s", | |
| }} | |
| onMouseOver={(e) => (e.target.style.backgroundColor = "#4338ca")} | |
| onMouseOut={(e) => (e.target.style.backgroundColor = "#4f46e5")} | |
| > | |
| {file ? "Change PDF File" : "Select PDF File"} | |
| </label> | |
| {file && ( | |
| <div style={{ marginTop: "16px" }}> | |
| <p style={{ margin: "8px 0", color: "#333" }}> | |
| <strong>Selected:</strong> {file.name} | |
| </p> | |
| <p style={{ margin: "4px 0", color: "#666", fontSize: "14px" }}> | |
| Size: {(file.size / 1024).toFixed(2)} KB | |
| </p> | |
| </div> | |
| )} | |
| <div style={{ marginTop: "24px" }}> | |
| <button | |
| onClick={handleClassify} | |
| disabled={!file || loading} | |
| style={{ | |
| padding: "12px 32px", | |
| fontSize: "16px", | |
| fontWeight: "600", | |
| backgroundColor: file && !loading ? "#10b981" : "#9ca3af", | |
| color: "white", | |
| border: "none", | |
| borderRadius: "8px", | |
| cursor: file && !loading ? "pointer" : "not-allowed", | |
| transition: "background-color 0.2s", | |
| }} | |
| onMouseOver={(e) => { | |
| if (file && !loading) { | |
| e.target.style.backgroundColor = "#059669"; | |
| } | |
| }} | |
| onMouseOut={(e) => { | |
| if (file && !loading) { | |
| e.target.style.backgroundColor = "#10b981"; | |
| } | |
| }} | |
| > | |
| {loading ? "Classifying..." : "Classify Document"} | |
| </button> | |
| {file && ( | |
| <button | |
| onClick={handleReset} | |
| disabled={loading} | |
| style={{ | |
| padding: "12px 24px", | |
| fontSize: "16px", | |
| fontWeight: "500", | |
| backgroundColor: "transparent", | |
| color: "#666", | |
| border: "1px solid #ddd", | |
| borderRadius: "8px", | |
| cursor: loading ? "not-allowed" : "pointer", | |
| marginLeft: "12px", | |
| }} | |
| > | |
| Reset | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| {error && ( | |
| <div | |
| style={{ | |
| padding: "16px", | |
| backgroundColor: "#fee2e2", | |
| border: "1px solid #fecaca", | |
| borderRadius: "8px", | |
| color: "#991b1b", | |
| marginBottom: "24px", | |
| }} | |
| > | |
| <strong>Error:</strong> {error} | |
| </div> | |
| )} | |
| {result && ( | |
| <div | |
| style={{ | |
| padding: "24px", | |
| backgroundColor: "#f0fdf4", | |
| border: "2px solid #86efac", | |
| borderRadius: "12px", | |
| marginBottom: "24px", | |
| }} | |
| > | |
| <h2 style={{ margin: "0 0 16px 0", color: "#166534" }}> | |
| Classification Result | |
| </h2> | |
| <div | |
| style={{ | |
| backgroundColor: "white", | |
| padding: "20px", | |
| borderRadius: "8px", | |
| marginBottom: "16px", | |
| }} | |
| > | |
| <div style={{ marginBottom: "12px" }}> | |
| <span style={{ color: "#666", fontSize: "14px" }}> | |
| Document Type: | |
| </span> | |
| <div | |
| style={{ | |
| fontSize: "24px", | |
| fontWeight: "700", | |
| color: "#10b981", | |
| marginTop: "4px", | |
| textTransform: "capitalize", | |
| }} | |
| > | |
| {result.classification.document_type} | |
| </div> | |
| </div> | |
| <div style={{ marginBottom: "12px" }}> | |
| <span style={{ color: "#666", fontSize: "14px" }}> | |
| Confidence: | |
| </span> | |
| <div | |
| style={{ | |
| fontSize: "20px", | |
| fontWeight: "600", | |
| color: "#059669", | |
| marginTop: "4px", | |
| }} | |
| > | |
| {(result.classification.confidence * 100).toFixed(1)}% | |
| </div> | |
| </div> | |
| <div style={{ marginTop: "16px", paddingTop: "16px", borderTop: "1px solid #e5e7eb" }}> | |
| <span style={{ color: "#666", fontSize: "14px" }}> | |
| File: {result.filename} | |
| </span> | |
| <br /> | |
| <span style={{ color: "#666", fontSize: "14px" }}> | |
| Text Length: {result.text_length.toLocaleString()} characters | |
| </span> | |
| </div> | |
| </div> | |
| {result.classification.all_scores && ( | |
| <div> | |
| <h3 style={{ margin: "0 0 12px 0", fontSize: "16px", color: "#166534" }}> | |
| Top 5 Classifications: | |
| </h3> | |
| <div style={{ backgroundColor: "white", padding: "16px", borderRadius: "8px" }}> | |
| {Object.entries(result.classification.all_scores).map( | |
| ([type, score]) => ( | |
| <div | |
| key={type} | |
| style={{ | |
| display: "flex", | |
| justifyContent: "space-between", | |
| alignItems: "center", | |
| padding: "8px 0", | |
| borderBottom: "1px solid #f3f4f6", | |
| }} | |
| > | |
| <span style={{ textTransform: "capitalize", color: "#374151" }}> | |
| {type} | |
| </span> | |
| <span | |
| style={{ | |
| fontWeight: "600", | |
| color: type === result.classification.document_type ? "#10b981" : "#6b7280", | |
| }} | |
| > | |
| {(score * 100).toFixed(1)}% | |
| </span> | |
| </div> | |
| ) | |
| )} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| {loading && ( | |
| <div style={{ textAlign: "center", padding: "24px" }}> | |
| <div | |
| style={{ | |
| display: "inline-block", | |
| width: "40px", | |
| height: "40px", | |
| border: "4px solid #e5e7eb", | |
| borderTop: "4px solid #4f46e5", | |
| borderRadius: "50%", | |
| animation: "spin 1s linear infinite", | |
| }} | |
| /> | |
| <p style={{ marginTop: "16px", color: "#666" }}> | |
| Processing your document... | |
| </p> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |