"""OCR tab โ€” extract text from images and PDFs via capability bus.""" from __future__ import annotations import asyncio import base64 import concurrent.futures from typing import Any def _run(coro): try: loop = asyncio.get_running_loop() except RuntimeError: loop = None if loop and loop.is_running(): with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool: return pool.submit(asyncio.run, coro).result() return asyncio.run(coro) def build_ocr_tab(bus: Any | None = None) -> None: import gradio as gr gr.HTML("""

๐Ÿ“„ OCR โ€” Text Extraction

Tesseract ยท TrOCR ยท extract text from scans, photos, PDFs ยท offline

""") with gr.Row(): with gr.Column(scale=2): ocr_input = gr.File( label="Upload image or PDF", file_types=[".png", ".jpg", ".jpeg", ".tiff", ".bmp", ".pdf"], ) lang_hint = gr.Textbox( label="Language hint (optional)", placeholder="eng deu fra auto โ€ฆ", value="", ) ocr_btn = gr.Button("๐Ÿ“„ Extract Text", variant="primary", size="lg") with gr.Column(scale=3): ocr_out = gr.Textbox(label="Extracted text", lines=12, interactive=False) status_out = gr.Textbox(label="Status", lines=1, interactive=False) def _ocr(file_obj, lang: str) -> tuple[str, str]: if file_obj is None: return "", "โš  Upload a file first" if bus is None: return "", "โš  No bus โ€” run inside a HearthNet node" file_path = file_obj if isinstance(file_obj, str) else file_obj.name cap = "ocr.pdf" if file_path.lower().endswith(".pdf") else "ocr.image" try: with open(file_path, "rb") as f: b64 = base64.b64encode(f.read()).decode() except Exception as exc: return "", f"โš  Could not read file: {exc}" async def _call(): return await bus.call( cap, (1, 0), {"params": {"language": lang.strip() or None}, "input": {"file_b64": b64}}, ) try: result = _run(_call()) except Exception as exc: return "", f"โš  Bus error: {exc}" if "error" in result: if result["error"] == "backend_unavailable": return "", "โš  No OCR backend โ€” install: pip install pytesseract pillow" return "", f"โš  {result.get('message', result['error'])}" text = result.get("output", result).get("text", str(result)) word_count = len(text.split()) return text, f"โœ“ Extracted {word_count} words" ocr_btn.click(_ocr, inputs=[ocr_input, lang_hint], outputs=[ocr_out, status_out]) gr.HTML("""
โ„น Setup help
Tesseract: pip install pytesseract pillow + install the Tesseract binary
  Ubuntu: apt-get install tesseract-ocr
  macOS: brew install tesseract
  Windows: download from UB-Mannheim
Languages: eng (English), deu (German), fra (French), chi_sim (Simplified Chinese), โ€ฆ
Install language packs: apt-get install tesseract-ocr-deu tesseract-ocr-fra
""")