anycoder-93a1d1af / index.html
raomyousaf's picture
Upload folder using huggingface_hub
6eb91da verified
Raw
History Blame Contribute Delete
20.9 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OCR + Form Data Extraction Tool</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #6366f1;
--secondary: #a855f7;
--accent: #ec4899;
--bg-dark: #0f172a;
--bg-card: #1e293b;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--success: #10b981;
--border: #334155;
--glass: rgba(30, 41, 58, 0.7);
--scan-color: #00ff9d;
}
* {
box-sizing: boxed;
margin: 0;
padding: 0;
font-family: 'Inter', sans-serif;
}
body {
background-color: var(--bg-dark);
color: var(--text-main);
height: 100vh;
display: flex;
overflow: hidden;
background-image: radial-gradient(circle at 10% 20%, rgba(63, 66, 241, 0.1) 0%, transparent 20%),
radial-gradient(circle at 90% 80%, rgba(236, 72, 153, 0.1) 0%, transparent 20%);
}
/* --- Layout --- */
.app-container {
display: flex;
width: 100%;
height: 100%;
}
/* Sidebar */
.sidebar {
width: 280px;
background: var(--bg-card);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 20px;
transition: transform 0.3s ease;
z-index: 10;
}
.logo-area {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 30px;
font-weight: 700;
font-size: 1.2rem;
color: var(--primary);
}
.logo-area i {
font-size: 1.5rem;
}
.nav-item {
padding: 12px 15px;
border-radius: 8px;
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 5px;
}
.nav-item:hover, .nav-item.active {
background: rgba(63, 66, 241, 0.1);
color: var(--text-main);
}
.nav-item.active {
border-left: 3px solid var(--primary);
}
.history-section {
margin-top: 40px;
flex-grow: 1;
}
.history-title {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--text-muted);
margin-bottom: 15px;
}
.history-item {
padding: 10px;
border-bottom: 1px solid var(--border);
font-size: 0.9rem;
color: var(--text-muted);
cursor: pointer;
}
.history-item:hover {
color: var(--text-main);
}
/* Main Content */
.main-content {
flex-grow: 1;
padding: 30px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 20px;
position: relative;
}
/* Header */
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.header-title h1 {
font-size: 1.8rem;
margin-bottom: 5px;
}
.header-title p {
color: var(--text-muted);
font-size: 0.9rem;
}
.anycoder-badge {
background: linear-gradient(135deg, var(--primary), var(--secondary));
padding: 8px 16px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
color: white;
text-decoration: none;
box-shadow: 0 4px 15px rgba(63, 66, 241, 0.3);
transition: transform 0.2s;
}
.anycoder-badge:hover {
transform: translateY(-2px);
}
/* Workspace Grid */
.workspace {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
height: 100%;
}
/* Card Styles */
.card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 1px solid var(--border);
padding-bottom: 10px;
}
.card-title {
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
/* Upload Zone */
.upload-zone {
flex-grow: 1;
border: 2px dashed var(--border);
border-radius: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
position: relative;
background: rgba(15, 23, 42, 0.3);
}
.upload-zone:hover {
border-color: var(--primary);
background: rgba(63, 66, 241, 0.05);
}
.upload-icon {
font-size: 3rem;
color: var(--text-muted);
margin-bottom: 15px;
}
.upload-text {
color: var(--text-muted);
font-weight: 500;
}
.upload-subtext {
color: var(--text-muted);
font-size: 0.8rem;
opacity: 0.7;
margin-top: 5px;
}
/* Image Preview Area */
.preview-container {
position: relative;
width: 100%;
height: 100%;
display: none; /* Hidden by default */
background: #000;
border-radius: 12px;
overflow: hidden;
}
.preview-image {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.6;
}
/* Scanner Effect */
.scanner-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to bottom, transparent, rgba(0, 255, 157, 0.2), transparent);
animation: scan 3s linear infinite;
display: none;
}
@keyframes scan {
0% { top: -100%; }
100% { top: 100%; }
}
/* Results Panel */
.results-content {
flex-grow: 1;
overflow-y: auto;
}
.data-field {
background: rgba(15, 23, 42, 0.5);
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
border: 1px solid var(--border);
transition: border-color 0.3s;
}
.data-field:hover {
border-color: var(--secondary);
}
.field-label {
font-size: 0.8rem;
color: var(--text-muted);
margin-bottom: 5px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.field-value {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-main);
}
.confidence-badge {
font-size: 0.7rem;
padding: 2px 6px;
background: var(--success);
color: #fff;
border-radius: 4px;
margin-left: 10px;
float: right;
}
/* Loading State */
.processing-state {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.loader {
width: 50px;
height: 50px;
border: 3px solid transparent;
border-top-color: var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loader-text {
margin-top: 20px;
color: var(--text-main);
font-weight: 600;
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--bg-card);
border-left: 4px solid var(--success);
padding: 15px 25px;
border-radius: 8px;
color: var(--text-main);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
transform: translateY(100px);
opacity: 0;
transition: all 0.3s;
z-index: 100;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
/* Responsive */
@media (max-width: 900px) {
.workspace {
grid-template-columns: 1fr;
}
.sidebar {
display: none; /* Simplify for mobile */
}
.app-container {
display: block;
}
.main-content {
padding: 15px;
}
}
</style>
</head>
<body>
<div class="app-container">
<!-- Sidebar -->
<aside class="sidebar">
<div class="logo-area">
<i class="fa-solid fa-eye"></i>
<span>VisionExtract</span>
</div>
<div class="nav-item active">
<i class="fa-solid fa-layer-group"></i>
<span>New Extraction</span>
</div>
<div class="nav-item">
<i class="fa-solid fa-bolt"></i>
<span>Batch Process</span>
</div>
<div class="nav-item">
<i class="fa-solid fa-cog"></i>
<span>Settings</span>
</div>
<div class="history-section">
<div class="history-title">Recent Scans</div>
<div class="history-item">Invoice_001.png</div>
<div class="history-item">Form_Submit_22.jpg</div>
<div class="history-item">Receipt_Starbucks.png</div>
</div>
<div style="margin-top: 20px; font-size: 0.7rem; color: var(--text-muted);">
v2.4.0 Stable
</div>
</aside>
<!-- Main Content -->
<main class="main-content">
<header>
<div class="header-title">
<h1>OCR Data Extraction</h1>
<p>Upload a document to automatically extract structured fields.</p>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoder-badge">
Built with anycoder
</a>
</header>
<div class="workspace">
<!-- Left Column: Upload/Preview -->
<div class="card">
<div class="card-header">
<div class="card-title">
<i class="fa-solid fa-image"></i> Source Document
</div>
<button id="clearBtn" class="nav-item" style="padding: 5px 10px; font-size: 0.8rem;">
<i class="fa-solid fa-trash"></i> Clear
</button>
</div>
<!-- Upload Zone -->
<div class="upload-zone" id="dropZone">
<input type="file" id="fileInput" hidden accept="image/png, image/jpeg">
<i class="fa-solid fa-cloud-arrow-up upload-icon"></i>
<div class="upload-text">Click or Drag image here</div>
<div class="upload-subtext">Supports PNG, JPG (Max 5MB)</div>
</div>
<!-- Preview Container (Hidden initially) -->
<div class="preview-container" id="previewContainer">
<img src="" alt="Preview" class="preview-image" id="previewImage">
<div class="scanner-overlay" id="scannerOverlay"></div>
</div>
<!-- Processing State (Hidden initially) -->
<div class="processing-state" id="processingState">
<div class="loader"></div>
<div class="loader-text">Analyzing Document...</div>
<div style="font-size: 0.8rem; color: var(--text-muted); margin-top: 5px;">Extracting fields: Name, Date, Total...</div>
</div>
</div>
<!-- Right Column: Results -->
<div class="card">
<div class="card-header">
<div class="card-title">
<i class="fa-solid fa-file-code"></i> Extracted Data
</div>
<button id="copyJsonBtn" class="nav-item" style="padding: 5px 10px; font-size: 0.8rem;">
<i class="fa-solid fa-copy"></i> Copy JSON
</button>
</div>
<div class="results-content" id="resultsContent">
<div style="text-align: center; color: var(--text-muted); padding: 40px;">
<i class="fa-solid fa-robot" style="font-size: 2rem; opacity: 0.5; margin-bottom: 10px;"></i>
<p>Waiting for input...</p>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fa-solid fa-check-circle" style="color: var(--success); margin-right: 10px;"></i>
<span id="toastMessage">Action completed successfully</span>
</div>
<script>
// --- DOM Elements ---
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const previewContainer = document.getElementById('previewContainer');
const previewImage = document.getElementById('previewImage');
const scannerOverlay = document.getElementById('scannerOverlay');
const processingState = document.getElementById('processingState');
const resultsContent = document.getElementById('resultsContent');
const copyJsonBtn = document.getElementById('copyJsonBtn');
const clearBtn = document.getElementById('clearBtn');
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
// --- Event Handlers ---
// Drag & Drop
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#6366f1';
dropZone.style.background = 'rgba(63, 66, 241, 0.1)';
});
dropZone.addEventListener('dragleave', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#334155';
dropZone.style.background = 'rgba(15, 23, 42, 0.3)';
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#334155';
dropZone.style.background = 'rgba(15, 23, 42, 0.3)';
if (e.dataTransfer.files.length) {
handleFile(e.dataTransfer.files[0]);
}
});
fileInput.addEventListener('change', (e) => {
if (e.target.files.length) {
handleFile(e.target.files[0]);
}
});
clearBtn.addEventListener('click', resetUI);
copyJsonBtn.addEventListener('click', copyToClipboard);
// --- Core Logic ---
function handleFile(file) {
if (!file.type.startsWith('image/')) {
showToast('Please upload an image file.');
return;
}
// 1. Show Preview
const reader = new FileReader();
reader.onload = (e) => {
previewImage.src = e.target.result;
dropZone.style.display = 'none';
previewContainer.style.display = 'block';
// 2. Start Simulation
startProcessing();
};
reader.readAsDataURL(file);
}
function startProcessing() {
// UI Transition
previewContainer.style.display = 'none';
processingState.style.display = 'flex';
scannerOverlay.style.display = 'block'; // Show scanner animation
// Simulate OCR Delay (2.5 seconds)
setTimeout(() => {
processingState.style.display = 'none';
scannerOverlay.style.display = 'none';
previewContainer.style.display = 'block'; // Keep image visible
// Generate Mock Data
generateMockResults();
showToast('Extraction Complete');
}, 2500);
}
function generateMockResults() {
// Mock Data representing what an OCR engine might find
const mockData = {
"document_type": "Invoice",
"invoice_number": "INV-2023-0045",
"date": "2023-10-15",
"client": "Acme Corp",
"total_amount": "$1,250.00",
"tax": "$125.00",
"status": "Paid"
};
let html = '';
for (const [key, value] of Object.entries(mockData)) {
html += `
<div class="data-field">
<div class="field-label">
${key.replace('_', ' ').toUpperCase()}
<span class="confidence-badge">98% Conf</span>
</div>
<div class="field-value">${value}</div>
</div>
`;
}
// Add raw JSON view toggle logic (optional enhancement)
html += `
<div class="data-field" style="background: #0f172a; border: 1px solid #334155;">
<div class="field-label">RAW JSON OUTPUT</div>
<pre style="color: #a855f7; font-size: 0.8rem; overflow-x: auto;">
${JSON.stringify(mockData, null, 2)}
</pre>
</div>
`;
resultsContent.innerHTML = html;
}
function copyToClipboard() {
// Extract text from the pre tag
const rawJson = resultsContent.querySelector('pre').innerText;
navigator.clipboard.writeText(rawJson).then(() => {
showToast('JSON copied to clipboard');
});
}
function resetUI() {
dropZone.style.display = 'flex';
previewContainer.style.display = 'none';
processingState.style.display = 'none';
scannerOverlay.style.display = 'none';
fileInput.value = '';
previewImage.src = '';
resultsContent.innerHTML = `
<div style="text-align: center; color: var(--text-muted); padding: 40px;">
<i class="fa-solid fa-robot" style="font-size: 2rem; opacity: 0.5; margin-bottom: 10px;"></i>
<p>Waiting for input...</p>
</div>
`;
}
function showToast(message) {
toastMessage.innerText = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
</script>
</body>
</html>