Archie0099 commited on
Commit
4306e95
·
verified ·
1 Parent(s): 23f65ce

Disable local handwriting gracefully when packages absent

Browse files
Files changed (3) hide show
  1. app.py +28 -0
  2. static/index.html +25 -7
  3. static/styles.css +6 -0
app.py CHANGED
@@ -75,6 +75,34 @@ async def index():
75
  return FileResponse(str(INDEX_HTML))
76
 
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  @app.post("/api/upload")
79
  async def upload(
80
  file: UploadFile = File(...),
 
75
  return FileResponse(str(INDEX_HTML))
76
 
77
 
78
+ # Cache the (deterministic) optional-feature probe so torch/transformers are
79
+ # imported at most once.
80
+ _CAPABILITIES: dict = {}
81
+
82
+
83
+ @app.get("/api/capabilities")
84
+ async def capabilities():
85
+ """Report which optional features are usable in THIS deployment.
86
+
87
+ Local handwriting (TrOCR) needs torch + transformers, which the lean hosted
88
+ build omits. The front-end reads this to disable the handwriting toggle
89
+ gracefully and point users to online OCR, instead of letting a page fail
90
+ mid-extraction with a missing-dependency error.
91
+ """
92
+ if "handwriting" not in _CAPABILITIES:
93
+ from pipeline.jobs import _EXECUTOR
94
+ from pipeline.handwriting import is_available
95
+
96
+ loop = asyncio.get_running_loop()
97
+ try:
98
+ _CAPABILITIES["handwriting"] = await loop.run_in_executor(
99
+ _EXECUTOR, is_available
100
+ )
101
+ except Exception:
102
+ _CAPABILITIES["handwriting"] = False
103
+ return {"handwriting": bool(_CAPABILITIES["handwriting"])}
104
+
105
+
106
  @app.post("/api/upload")
107
  async def upload(
108
  file: UploadFile = File(...),
static/index.html CHANGED
@@ -18,12 +18,29 @@
18
  }
19
  document.addEventListener("DOMContentLoaded", function () {
20
  var btn = document.getElementById("themeToggle");
21
- if (!btn) return;
22
- btn.addEventListener("click", function () {
23
- var next = root.getAttribute("data-theme") === "light" ? "dark" : "light";
24
- root.setAttribute("data-theme", next);
25
- try { localStorage.setItem("theme", next); } catch (e) {}
26
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  });
28
  })();
29
  </script>
@@ -140,7 +157,7 @@
140
  <svg class="accordion-chevron" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"></path></svg>
141
  </summary>
142
  <div class="accordion-body">
143
- <div class="setting setting-row">
144
  <div>
145
  <label class="setting-label" for="handwritingToggle">Handwriting (local) <span class="beta-tag">beta</span></label>
146
  <p class="hint">Read handwritten pages with a local model (English, ~73% on real cursive). Much slower; first use downloads a model once. For far better handwriting, use Online Gemini below instead &mdash; you don't need both.</p>
@@ -150,6 +167,7 @@
150
  <span class="slider" aria-hidden="true"></span>
151
  </label>
152
  </div>
 
153
 
154
  <div class="setting setting-row">
155
  <div>
 
18
  }
19
  document.addEventListener("DOMContentLoaded", function () {
20
  var btn = document.getElementById("themeToggle");
21
+ if (btn) {
22
+ btn.addEventListener("click", function () {
23
+ var next = root.getAttribute("data-theme") === "light" ? "dark" : "light";
24
+ root.setAttribute("data-theme", next);
25
+ try { localStorage.setItem("theme", next); } catch (e) {}
26
+ });
27
+ }
28
+
29
+ /* Disable local-handwriting gracefully where its packages aren't
30
+ installed (e.g. the lean hosted build) and point users to Gemini,
31
+ instead of letting a page fail mid-extraction. */
32
+ fetch("/api/capabilities")
33
+ .then(function (r) { return r.json(); })
34
+ .then(function (caps) {
35
+ if (!caps || caps.handwriting !== false) return;
36
+ var hw = document.getElementById("handwritingToggle");
37
+ if (hw) { hw.checked = false; hw.disabled = true; }
38
+ var row = document.getElementById("handwritingRow");
39
+ if (row) row.classList.add("is-unavailable");
40
+ var note = document.getElementById("hwUnavailable");
41
+ if (note) note.hidden = false;
42
+ })
43
+ .catch(function () {});
44
  });
45
  })();
46
  </script>
 
157
  <svg class="accordion-chevron" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"></path></svg>
158
  </summary>
159
  <div class="accordion-body">
160
+ <div class="setting setting-row" id="handwritingRow">
161
  <div>
162
  <label class="setting-label" for="handwritingToggle">Handwriting (local) <span class="beta-tag">beta</span></label>
163
  <p class="hint">Read handwritten pages with a local model (English, ~73% on real cursive). Much slower; first use downloads a model once. For far better handwriting, use Online Gemini below instead &mdash; you don't need both.</p>
 
167
  <span class="slider" aria-hidden="true"></span>
168
  </label>
169
  </div>
170
+ <p class="hint hw-note" id="hwUnavailable" hidden>Local handwriting isn't installed in this build &mdash; use <strong>Online vision OCR (Gemini)</strong> below for handwriting.</p>
171
 
172
  <div class="setting setting-row">
173
  <div>
static/styles.css CHANGED
@@ -294,6 +294,12 @@ html[data-theme="light"] .theme-toggle .icon-moon { display: block; }
294
  }
295
  .switch input:checked + .slider::before { transform: translateX(20px); }
296
  .switch input:focus-visible + .slider { box-shadow: 0 0 0 3px var(--accent-ring); }
 
 
 
 
 
 
297
 
298
  /* ---------------- Work area ---------------- */
299
  .work { min-width: 0; display: flex; flex-direction: column; gap: 18px; }
 
294
  }
295
  .switch input:checked + .slider::before { transform: translateX(20px); }
296
  .switch input:focus-visible + .slider { box-shadow: 0 0 0 3px var(--accent-ring); }
297
+ .switch input:disabled + .slider { opacity: 0.45; cursor: not-allowed; }
298
+
299
+ /* a feature that isn't available in this build */
300
+ .setting-row.is-unavailable .setting-label { color: var(--text-dim); }
301
+ .hw-note { color: var(--accent); }
302
+ .hw-note strong { color: var(--accent); font-weight: 700; }
303
 
304
  /* ---------------- Work area ---------------- */
305
  .work { min-width: 0; display: flex; flex-direction: column; gap: 18px; }