CoolFace
Apppublic

ek-developers/ocr-frontend

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
app.py309 linesDownload Raw Back to root
1import gradio as gr2import requests3import os4 5# ── Config ─────────────────────────────────────────────────────────────────────6API_URL = os.getenv("OCR_API_URL", "https://ek-developers-my-ocr-api.hf.space/ocr")7 8# ── Core function ──────────────────────────────────────────────────────────────9def run_ocr(image, prompt_text):10    if image is None:11        return "⚠️ Please upload an image first."12 13    if not prompt_text or not prompt_text.strip():14        prompt_text = "Free OCR."15 16    try:17        with open(image, "rb") as f:18            response = requests.post(19                API_URL,20                files={"file": ("image.jpg", f, "image/jpeg")},21                data={"prompt_text": prompt_text},22                timeout=180,23            )24 25        if response.status_code == 200:26            text = response.json().get("text", "").strip()27            if not text:28                return "⚠️ No text found in image. Try a clearer photo or different prompt."29            return text30        else:31            return f"❌ API error {response.status_code}: {response.text}"32 33    except requests.exceptions.Timeout:34        return "⌛ Request timed out. The model may still be loading — please try again in 30 seconds."35    except requests.exceptions.ConnectionError:36        return "❌ Could not connect to the OCR backend. It may be sleeping — try again shortly."37    except Exception as e:38        return f"❌ Unexpected error: {str(e)}"39 40 41# ── UI ─────────────────────────────────────────────────────────────────────────42css = """43@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=IBM+Plex+Sans:wght@300;400;600&display=swap');44 45.gradio-container {46    max-width: 1000px !important;47    margin: 0 auto !important;48    font-family: 'IBM Plex Sans', sans-serif !important;49}50 51#app-header {52    text-align: center;53    padding: 2.5rem 0 1.5rem;54    border-bottom: 1px solid #e2e8f0;55    margin-bottom: 2rem;56}57 58#app-header .badge {59    display: inline-block;60    background: #eff6ff;61    color: #2563eb;62    font-family: 'IBM Plex Mono', monospace;63    font-size: 0.7rem;64    letter-spacing: 2px;65    padding: 4px 12px;66    border-radius: 20px;67    border: 1px solid #bfdbfe;68    margin-bottom: 1rem;69    text-transform: uppercase;70}71 72#app-header h1 {73    font-size: 2.6rem;74    font-weight: 600;75    color: #0f172a;76    margin: 0 0 0.5rem;77    letter-spacing: -1px;78    line-height: 1.1;79}80 81#app-header h1 span { color: #2563eb; }82 83#app-header p {84    color: #64748b;85    font-size: 0.95rem;86    font-weight: 300;87    margin: 0;88}89 90.panel-label {91    font-family: 'IBM Plex Mono', monospace;92    font-size: 0.7rem;93    letter-spacing: 2px;94    text-transform: uppercase;95    color: #2563eb;96    margin-bottom: 0.75rem;97    padding-bottom: 0.5rem;98    border-bottom: 1px solid #e2e8f0;99}100 101#run-btn {102    background: #2563eb !important;103    border: none !important;104    color: #ffffff !important;105    font-family: 'IBM Plex Mono', monospace !important;106    font-size: 0.85rem !important;107    letter-spacing: 1.5px !important;108    text-transform: uppercase !important;109    border-radius: 6px !important;110    width: 100% !important;111    margin-top: 0.5rem !important;112    transition: background 0.2s !important;113}114 115#run-btn:hover {116    background: #1d4ed8 !important;117}118 119#clear-btn {120    background: transparent !important;121    border: 1px solid #e2e8f0 !important;122    color: #94a3b8 !important;123    font-family: 'IBM Plex Mono', monospace !important;124    font-size: 0.8rem !important;125    letter-spacing: 1px !important;126    border-radius: 6px !important;127    width: 100% !important;128    transition: all 0.2s !important;129}130 131#clear-btn:hover {132    border-color: #94a3b8 !important;133    color: #475569 !important;134}135 136#output-text textarea {137    font-family: 'IBM Plex Mono', monospace !important;138    font-size: 0.88rem !important;139    line-height: 1.7 !important;140    min-height: 320px !important;141}142 143#status-bar {144    display: flex;145    align-items: center;146    justify-content: space-between;147    padding: 0.6rem 1rem;148    background: #f8fafc;149    border: 1px solid #e2e8f0;150    border-radius: 6px;151    margin-bottom: 0.75rem;152}153 154#status-bar .dot {155    width: 7px;156    height: 7px;157    border-radius: 50%;158    background: #22c55e;159    display: inline-block;160    margin-right: 7px;161    box-shadow: 0 0 6px #22c55e88;162}163 164#status-bar span {165    font-family: 'IBM Plex Mono', monospace;166    font-size: 0.72rem;167    color: #64748b;168    letter-spacing: 1px;169}170 171#status-bar .api-url {172    color: #94a3b8;173    font-size: 0.68rem;174    font-family: 'IBM Plex Mono', monospace;175}176 177#footer {178    text-align: center;179    padding: 2rem 0 2.5rem;180    border-top: 1px solid #e2e8f0;181    margin-top: 2.5rem;182    color: #94a3b8;183    font-family: 'IBM Plex Mono', monospace;184    font-size: 0.72rem;185    letter-spacing: 0.5px;186}187 188#footer a { color: #2563eb; text-decoration: none; }189#footer a:hover { text-decoration: underline; }190 191#copy-btn {192    background: transparent !important;193    border: 1px solid #e2e8f0 !important;194    color: #64748b !important;195    font-family: 'IBM Plex Mono', monospace !important;196    font-size: 0.78rem !important;197    letter-spacing: 1px !important;198    border-radius: 6px !important;199    width: 100% !important;200    margin-top: 0.4rem !important;201    transition: all 0.2s !important;202}203 204#copy-btn:hover {205    border-color: #2563eb !important;206    color: #2563eb !important;207}208"""209 210with gr.Blocks(title="DeepSeek OCR") as demo:211 212    gr.HTML("""213        <div id="app-header">214            <div class="badge">Powered by DeepSeek · Ollama</div>215            <h1>Deep<span>Seek</span> OCR</h1>216            <p>Extract text from any image using AI — receipts, menus, documents, signs</p>217        </div>218    """)219 220    with gr.Row(equal_height=False):221 222        with gr.Column(scale=1):223            gr.HTML('<div class="panel-label">01 · Input</div>')224 225            image_input = gr.Image(226                type="filepath",227                label="Upload Image",228                sources=["upload", "clipboard"],229            )230 231            prompt_input = gr.Textbox(232                label="Prompt",233                value="Free OCR.",234                placeholder="e.g. Extract all menu items and prices.",235                lines=2,236            )237 238            with gr.Row():239                run_btn = gr.Button("▶  RUN OCR", variant="primary", elem_id="run-btn")240                clear_btn = gr.ClearButton(241                    components=[image_input, prompt_input],242                    value="✕  CLEAR",243                    elem_id="clear-btn"244                )245 246        with gr.Column(scale=1):247            gr.HTML('<div class="panel-label">02 · Extracted Text</div>')248 249            gr.HTML(f"""250                <div id="status-bar">251                    <span><span class="dot"></span>API CONNECTED</span>252                    <span class="api-url">{API_URL}</span>253                </div>254            """)255 256            output_text = gr.Textbox(257                label="Result",258                lines=14,259                elem_id="output-text",260                placeholder="Extracted text will appear here after running OCR...",261            )262 263            copy_btn = gr.Button("⎘  COPY TEXT", elem_id="copy-btn")264            copy_status = gr.HTML("")265 266            copy_btn.click(267                fn=None,268                inputs=output_text,269                outputs=copy_status,270                js="""271                (text) => {272                    if (!text) return '<p id="copy-msg">⚠️ Nothing to copy.</p>';273                    navigator.clipboard.writeText(text);274                    setTimeout(() => {275                        const el = document.getElementById('copy-msg');276                        if (el) el.innerText = '';277                    }, 2000);278                    return '<p id="copy-msg" style="color:#22c55e; font-family:monospace; font-size:0.8rem; margin:4px 0;">✓ Copied to clipboard!</p>';279                }280                """281            )282 283    gr.Examples(284        examples=[285            ["Free OCR."],286            ["Extract all menu items and prices."],287            ["Extract only the grand total."],288            ["List all ingredients on the label."],289            ["Read the text on this sign."],290            ["Extract the table contents."],291        ],292        inputs=[prompt_input],293        label="Example Prompts — click to use",294    )295 296    gr.HTML("""297        <div id="footer">298            DeepSeek OCR · Built with Ollama + FastAPI + Gradio · Hosted on299            <a href="https://huggingface.co/spaces" target="_blank">Hugging Face Spaces</a>300            &nbsp;·&nbsp;301            <a href="https://ek-developers-my-ocr-api.hf.space/docs" target="_blank">API Docs →</a>302        </div>303    """)304 305    run_btn.click(fn=run_ocr, inputs=[image_input, prompt_input], outputs=output_text)306    image_input.upload(fn=run_ocr, inputs=[image_input, prompt_input], outputs=output_text)307 308 309demo.launch(css=css)