import time import gradio as gr import requests # Default backend URL for Modal deployment DEFAULT_BACKEND_URL = "PASTE_YOUR_DEPLOYED_URL_HERE" def extract_text(receipt, api_uri, progress=gr.Progress(track_tqdm=True)): if receipt is None: return gr.update(value="Please upload a receipt image.", interactive=True) # Use user-provided API URI or default backend_url = ( api_uri.strip() if api_uri and api_uri.strip() else DEFAULT_BACKEND_URL ) parse_url = f"{backend_url}/parse" result_url = f"{backend_url}/result" try: mime_type = getattr(receipt, "type", "application/octet-stream") with open(receipt.name, "rb") as f: files = {"receipt": (receipt.name, f, mime_type)} resp = requests.post(parse_url, files=files) # Send image to backend if not resp.ok: return f"Error from backend: {resp.status_code} {resp.text}" data = resp.json() call_id = data.get("call_id") if not call_id: return "No call_id returned from backend." # Poll /result/{call_id} for i in range(60): # Poll for up to 60 seconds poll_resp = requests.get(f"{result_url}/{call_id}") if poll_resp.status_code == 202: progress((i + 1) / 60, desc="Processing...") time.sleep(1) continue if poll_resp.ok: try: result = poll_resp.json() if isinstance(result, dict): return result.get("result", str(result)) return str(result) except Exception: return poll_resp.text else: return f"Error polling result: {poll_resp.status_code} {poll_resp.text}" return "Timed out waiting for OCR result." except Exception as e: return f"Exception: {e}" # JavaScript to force dark theme on Gradio js_func = """ function refresh() { const url = new URL(window.location); if (url.searchParams.get('__theme') !== 'dark') { url.searchParams.set('__theme', 'dark'); window.location.href = url.href; } } """ def main(): with gr.Blocks( js=js_func, theme=gr.themes.Soft(primary_hue="orange", secondary_hue="gray") ) as demo: # Title and subtitle gr.HTML("""
Upload a receipt image and extract text using NuExtract-2.0 hosted on Modal.