""" Multimodal Document Extraction Pipeline — Professional Demo Author: Aravind Kumar Nalukurthi """ import gradio as gr import plotly.graph_objects as go import os try: from pipeline.extractor import GPT4VExtractor, DOCUMENT_SCHEMAS, encode_pil_image from pipeline.validator import DocumentValidator, HumanReviewQueue PIPELINE_AVAILABLE = True except Exception as e: GPT4VExtractor = None PIPELINE_AVAILABLE = False OPENAI_KEY = os.getenv("OPENAI_API_KEY", "") CSS = """ * { box-sizing: border-box; } body, .gradio-container { background: #000 !important; font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', sans-serif !important; color: #f5f5f7 !important; } .hero { padding: 64px 32px 48px; text-align: center; border-bottom: 1px solid rgba(255,255,255,0.07); } .hero-badge { display: inline-block; background: rgba(255,159,10,0.12); color: #ff9f0a; font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; padding: 5px 14px; border-radius: 20px; border: 1px solid rgba(255,159,10,0.2); margin-bottom: 22px; } .hero-title { font-size: 48px; font-weight: 700; color: #f5f5f7; line-height: 1.06; letter-spacing: -0.025em; margin: 0 0 18px; } .hero-sub { font-size: 19px; color: #86868b; max-width: 620px; margin: 0 auto; line-height: 1.55; } .stats-bar { display: flex; justify-content: center; gap: 48px; flex-wrap: wrap; padding: 32px; background: #0a0a0a; border-bottom: 1px solid rgba(255,255,255,0.07); } .stat { text-align: center; } .stat-val { font-size: 30px; font-weight: 700; color: #ff9f0a; letter-spacing: -0.02em; } .stat-label { font-size: 12px; color: #6e6e73; margin-top: 3px; font-weight: 500; } .section { padding: 36px 32px; border-bottom: 1px solid rgba(255,255,255,0.06); } .sec-label { font-size: 12px; font-weight: 600; color: #6e6e73; letter-spacing: 0.09em; text-transform: uppercase; margin: 0 0 18px; } .card { background: #111; border: 1px solid rgba(255,255,255,0.08); border-radius: 14px; padding: 22px 24px; margin-bottom: 10px; } .card-title { font-size: 16px; font-weight: 600; color: #f5f5f7; margin: 0 0 8px; } .card-body { font-size: 14px; color: #86868b; line-height: 1.6; margin: 0; } .field-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,0.05); } .field-name { font-size: 13px; color: #86868b; font-weight: 500; } .field-value { font-size: 14px; color: #f5f5f7; font-weight: 500; } .conf-bar { height: 4px; border-radius: 2px; margin-top: 3px; } .badge-auto { background: rgba(48,209,88,0.12); color: #30d158; border: 1px solid rgba(48,209,88,0.2); padding: 4px 12px; border-radius: 8px; font-size: 12px; font-weight: 600; } .badge-review { background: rgba(255,69,58,0.12); color: #ff453a; border: 1px solid rgba(255,69,58,0.2); padding: 4px 12px; border-radius: 8px; font-size: 12px; font-weight: 600; } footer { display: none !important; } """ INVOICE_DEMO = { "fields": {"invoice_number": "INV-2024-0847", "vendor_name": "Acme Solutions LLC", "date": "2024-03-15", "subtotal": 2850.00, "tax_amount": 256.50, "total_amount": 3106.50, "currency": "USD"}, "confidence": {"invoice_number": 0.97, "vendor_name": 0.94, "date": 0.99, "subtotal": 0.91, "tax_amount": 0.88, "total_amount": 0.95, "currency": 0.99}, "overall": 0.94, "review": False, } LOW_CONF_DEMO = { "fields": {"invoice_number": "unclear", "vendor_name": "??", "date": "03/?/24", "subtotal": None, "tax_amount": None, "total_amount": 450.00, "currency": "USD"}, "confidence": {"invoice_number": 0.22, "vendor_name": 0.14, "date": 0.31, "subtotal": 0.08, "tax_amount": 0.12, "total_amount": 0.55, "currency": 0.71}, "overall": 0.19, "review": True, } def conf_color(v): return "#30d158" if v >= 0.85 else ("#ff9f0a" if v >= 0.60 else "#ff453a") def build_conf_chart(conf_dict): fields, values = list(conf_dict.keys()), [conf_dict[f] for f in conf_dict] fig = go.Figure([go.Bar( x=values, y=fields, orientation="h", marker_color=[conf_color(v) for v in values], text=[f"{v*100:.0f}%" for v in values], textposition="inside", textfont=dict(color="#000", size=12), )]) fig.update_layout( template="plotly_dark", paper_bgcolor="rgba(0,0,0,0)", plot_bgcolor="rgba(0,0,0,0)", font=dict(color="#86868b"), xaxis=dict(range=[0, 1.1], gridcolor="rgba(255,255,255,0.05)"), height=280, margin=dict(t=20, b=20, l=110, r=30), showlegend=False, ) return fig def render_demo(d): badge = 'Auto-Approved' if not d["review"] else 'Sent to Human Review' rows = "".join([ f'
Pipeline modules not available in this environment.
Enter your OpenAI API key above to run live extraction.
Upload a document image first.
Error: {e}
Upload any document image and GPT-4o reads it, extracts every field into structured JSON, validates the data for consistency, and routes anything uncertain to a human review queue — automatically.
Businesses process thousands of documents daily — invoices, contracts, IDs. Manual data entry is slow and error-prone. Traditional OCR extracts raw text but doesn't understand structure or meaning. This pipeline uses GPT-4o's vision to understand documents the way a human would.
The image is sent to GPT-4o with a schema-driven prompt ("Extract these specific fields from this invoice"). The model returns structured JSON with per-field confidence scores. High-detail mode is used for small text.
The extracted JSON is checked for consistency. For invoices: does subtotal + tax ≈ total (within 2%)? Are dates valid? Are required fields present? Each error adds a confidence penalty.
Documents above 70% confidence are auto-approved. Below 70%: queued for human review. Below 40%: HIGH priority review. This lets human effort focus on the 10% of documents that actually need it.
No API key: Click "Pre-computed Examples" to see results on a clean invoice and a low-quality scan.
With API key: Go to "Live Extraction" and upload any document.