Spaces:
Running
Running
Download index.html from khan1289/ocr-reader: direct link, hf CLI and curl.
- Browser
- Download file 6.29 kB
-
https://huggingface.co/spaces/khan1289/ocr-reader/resolve/main/index.html
- Command line
-
hf download hf://spaces/khan1289/ocr-reader/index.html
-
curl -L -o index.html https://huggingface.co/spaces/khan1289/ocr-reader/resolve/main/index.html
6.29 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>OCR Reader</title> | |
| <style> | |
| :root { --bg1:#eef2ff; --bg2:#fdf2f8; --card:#fff; --text:#1e1b4b; --muted:#6b7280; --border:#e5e7eb; --accent:#4f46e5; --accent2:#7c3aed; } | |
| @media (prefers-color-scheme: dark) { | |
| :root { --bg1:#0f172a; --bg2:#1e1b4b; --card:#1e293b; --text:#f1f5f9; --muted:#94a3b8; --border:#334155; --accent:#818cf8; --accent2:#a78bfa; } | |
| } | |
| * { box-sizing: border-box; } | |
| body { margin:0; min-height:100vh; padding:20px; display:flex; align-items:center; justify-content:center; | |
| font-family:"Segoe UI",system-ui,Arial,sans-serif; color:var(--text); | |
| background:linear-gradient(135deg,var(--bg1),var(--bg2)); } | |
| .card { width:100%; max-width:640px; background:var(--card); padding:34px; border-radius:20px; box-shadow:0 20px 50px rgba(79,70,229,.18); } | |
| h1 { margin:0 0 4px; font-size:32px; background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; } | |
| .sub { margin:0 0 6px; color:var(--muted); } | |
| .tip { margin:0 0 20px; font-size:13px; color:var(--muted); } | |
| #drop { border:2px dashed var(--border); border-radius:14px; padding:18px; text-align:center; cursor:pointer; transition:border-color .2s; } | |
| #drop:hover, #drop.over { border-color:var(--accent); } | |
| #preview { display:none; max-width:100%; max-height:220px; margin:0 auto 10px; border-radius:8px; } | |
| #dropText { color:var(--muted); } | |
| button { font-family:inherit; cursor:pointer; border:none; border-radius:12px; } | |
| #btn { width:100%; margin-top:14px; padding:14px; font-size:17px; font-weight:600; color:#fff; background:linear-gradient(90deg,var(--accent),var(--accent2)); } | |
| #btn:disabled { opacity:.5; cursor:not-allowed; } | |
| #status { margin-top:16px; font-size:14px; color:var(--muted); } | |
| .track { height:8px; margin-top:6px; background:var(--border); border-radius:99px; overflow:hidden; } | |
| #loadbar { height:100%; width:0%; background:linear-gradient(90deg,var(--accent),var(--accent2)); transition:width .3s; } | |
| #out { display:none; margin-top:20px; } | |
| #text { padding:16px; border:2px solid var(--border); border-radius:12px; font-size:20px; font-weight:600; word-break:break-word; min-height:30px; } | |
| #copy { margin-top:10px; padding:8px 16px; font-size:14px; color:var(--text); background:transparent; border:1px solid var(--border); } | |
| #copy:hover { border-color:var(--accent); color:var(--accent); } | |
| #err { margin-top:12px; color:#dc2626; font-size:14px; } | |
| footer { margin-top:22px; text-align:center; font-size:12px; color:var(--muted); } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="card"> | |
| <h1>OCR Reader</h1> | |
| <p class="sub">Upload a picture of printed text and see the text the AI reads from it.</p> | |
| <p class="tip">Tip: this model reads one line of text at a time, so crop your image to a single line.</p> | |
| <div id="drop"> | |
| <img id="preview" alt="Your image"> | |
| <div id="dropText">Click here or drop an image</div> | |
| <input id="file" type="file" accept="image/*" hidden> | |
| </div> | |
| <button id="btn" disabled>Read text</button> | |
| <div id="status">Loading AI model, please wait...</div> | |
| <div class="track"><div id="loadbar"></div></div> | |
| <div id="err"></div> | |
| <div id="out"> | |
| <div id="text"></div> | |
| <button id="copy">Copy text</button> | |
| </div> | |
| <footer>Runs privately in your browser with Transformers.js. Your image never leaves your device.</footer> | |
| </div> | |
| <script type="module"> | |
| import { pipeline, env } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3"; | |
| env.allowLocalModels = false; | |
| const $ = (id) => document.getElementById(id); | |
| const drop = $("drop"), file = $("file"), preview = $("preview"), btn = $("btn"); | |
| const status = $("status"), loadbar = $("loadbar"), err = $("err"), out = $("out"), text = $("text"); | |
| let imageData = null; | |
| function loadFile(f) { | |
| err.textContent = ""; | |
| if (!f || !f.type.startsWith("image/")) { err.textContent = "Please choose an image file (JPG, PNG, etc.)."; return; } | |
| const reader = new FileReader(); | |
| reader.onload = () => { | |
| imageData = reader.result; | |
| preview.src = imageData; preview.style.display = "block"; | |
| $("dropText").textContent = "Click to choose a different image"; | |
| out.style.display = "none"; | |
| if (ocr) btn.disabled = false; | |
| }; | |
| reader.readAsDataURL(f); | |
| } | |
| drop.addEventListener("click", () => file.click()); | |
| file.addEventListener("change", () => loadFile(file.files[0])); | |
| drop.addEventListener("dragover", (e) => { e.preventDefault(); drop.classList.add("over"); }); | |
| drop.addEventListener("dragleave", () => drop.classList.remove("over")); | |
| drop.addEventListener("drop", (e) => { e.preventDefault(); drop.classList.remove("over"); loadFile(e.dataTransfer.files[0]); }); | |
| let ocr = null; | |
| try { | |
| ocr = await pipeline("image-to-text", "Xenova/trocr-small-printed", { | |
| progress_callback: (p) => { | |
| if (p.status === "progress" && typeof p.progress === "number") loadbar.style.width = p.progress.toFixed(0) + "%"; | |
| }, | |
| }); | |
| loadbar.style.width = "100%"; | |
| status.textContent = "✅ Model ready. Upload an image of one line of printed text."; | |
| if (imageData) btn.disabled = false; | |
| } catch (e) { | |
| status.textContent = ""; | |
| err.textContent = "Could not load the AI model. Check your internet connection and refresh the page."; | |
| } | |
| btn.addEventListener("click", async () => { | |
| err.textContent = ""; | |
| btn.disabled = true; btn.textContent = "Reading..."; | |
| try { | |
| const result = await ocr(imageData); | |
| text.textContent = result[0].generated_text.trim() || "(no text found)"; | |
| out.style.display = "block"; | |
| } catch (e) { | |
| err.textContent = "Sorry, the app could not read this image. Try a clearer, cropped one."; | |
| } | |
| btn.disabled = false; btn.textContent = "Read text"; | |
| }); | |
| $("copy").addEventListener("click", async () => { | |
| try { await navigator.clipboard.writeText(text.textContent); $("copy").textContent = "Copied!"; } | |
| catch (e) { $("copy").textContent = "Select and copy manually"; } | |
| setTimeout(() => { $("copy").textContent = "Copy text"; }, 1500); | |
| }); | |
| </script> | |
| </body> | |
| </html> |