import gradio as gr import time import json # Mock OCR Function to simulate the backend logic def process_document(file): if file is None: return None, None # Simulate processing time (Scanner effect) time.sleep(2.5) # Mock extracted data mock_data = { "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", "confidence_score": 0.98 } return file, mock_data # Custom CSS to match the "VisionExtract" dark/glass theme from the request custom_css = """ :root { --primary: #6366f1; --secondary: #a855f7; --accent: #ec4899; --bg-dark: #0f172a; --bg-card: #1e293b; --text-main: #f8fafc; --text-muted: #94a3b8; --success: #10b981; --border: #334155; } body { background-color: var(--bg-dark); color: var(--text-main); font-family: 'Inter', sans-serif; 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%); } .gradio-container { background: transparent !important; } /* Sidebar Styling */ .sidebar-container { background: var(--bg-card); border-right: 1px solid var(--border); color: var(--text-main); } .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; font-weight: 500; } .nav-item:hover { background: rgba(63, 66, 241, 0.1); color: var(--text-main); } /* Card Styling */ .gr-box { background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } /* Header Badge */ .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; display: inline-block; margin-bottom: 10px; } .anycoder-badge:hover { transform: translateY(-2px); text-decoration: none; color: white; } /* Results Panel */ .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; display: flex; justify-content: space-between; } .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; } /* Scanner Animation Overlay (Simulated via HTML component) */ .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; z-index: 10; pointer-events: none; } @keyframes scan { 0% { top: -100%; } 100% { top: 100%; } } """ def create_app(): with gr.Blocks() as demo: # --- Sidebar --- with gr.Sidebar(position="left", open=True): gr.Markdown("
👁️ VisionExtract
") gr.Markdown("") gr.Markdown("") gr.Markdown("") gr.Markdown("
Recent Scans
") gr.Markdown("
Invoice_001.png
") gr.Markdown("
Form_Submit_22.jpg
") gr.Markdown("
Receipt_Starbucks.png
") gr.Markdown("
v2.4.0 Stable
") # --- Main Content --- with gr.Column(): # Header with gr.Row(): gr.Markdown("

OCR Data Extraction

Upload a document to automatically extract structured fields.

") gr.HTML("Built with anycoder") # Workspace Grid with gr.Row(): # Left Column: Upload/Preview with gr.Column(scale=1): with gr.Group(): gr.Markdown("
🖼️ Source Document
") # File Input file_input = gr.File(label="Upload Document", file_types=["image"], height=150) # Image Preview (Hidden initially, shown after upload) image_preview = gr.Image(label="Preview", interactive=False, height=400, visible=False) # Scanner Effect Overlay (HTML Component) scanner_html = gr.HTML( value="
", visible=False, label="Processing" ) clear_btn = gr.Button("🗑️ Clear", variant="secondary", size="sm") # Right Column: Results with gr.Column(scale=1): with gr.Group(): gr.Markdown("
📊 Extracted Data
") # Results Display results_json = gr.JSON(label="Raw JSON", visible=False) results_markdown = gr.Markdown(value="
🤖 Waiting for input...
", label="Structured Fields") copy_btn = gr.Button("📋 Copy JSON", variant="secondary", size="sm", visible=False) # --- Logic --- def clear_all(): return None, None, None, False, False, False, "
🤖 Waiting for input...
", False, False def process_logic(file): if file is None: return None, None, False, False, None, False, "
🤖 Waiting for input...
", False, False # Run OCR simulation img, data = process_document(file) # Format Markdown Results html_fields = "" for key, value in data.items(): if key != "confidence_score": html_fields += f"""
{key.replace('_', ' ').upper()} 98% Conf
{value}
""" html_fields += f"""
RAW JSON OUTPUT
                        {json.dumps(data, indent=2)}
                    
""" return img, img, True, True, data, True, html_fields, True, True # Event Listeners file_input.upload( fn=process_logic, inputs=[file_input], outputs=[image_preview, image_preview, scanner_html, scanner_html, results_json, copy_btn, results_markdown, copy_btn, copy_btn] ) clear_btn.click( fn=clear_all, inputs=[], outputs=[file_input, image_preview, scanner_html, scanner_html, results_json, copy_btn, results_markdown, copy_btn, copy_btn] ) return demo if __name__ == "__main__": demo = create_app() demo.launch( theme=gr.themes.Base(), css=custom_css, footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}] )