initial commit

This commit is contained in:
ray
2026-07-12 10:17:17 -04:00
commit dab5a4ebc6
1424 changed files with 330463 additions and 0 deletions
@@ -0,0 +1,85 @@
# Tesseract.js Client-Side Debugging Pattern
## The Problem
`Tesseract.recognize()` in the browser has multiple silent phases before "recognizing text":
1. `loading tesseract core` — downloads WASM from CDN
2. `initializing tesseract` — sets up the engine
3. `loading language traineddata` — downloads `eng.traineddata` from CDN
4. `initializing api` — final setup
5. `recognizing text` — actual OCR (the only phase with progress %)
If any phase fails (CSP block, CDN timeout, worker crash), the promise **never resolves or rejects**.
The UI just shows "Running OCR..." forever.
## The Fix: Promise.race + Full Phase Logger
```javascript
// Show ALL phases, not just "recognizing text"
const ocrResult = await Promise.race([
Tesseract.recognize(preprocessed, 'eng', {
logger: m => {
console.log(`[OCR] ${m.status} ${m.progress ? Math.round(m.progress*100)+'%' : ''}`);
if (m.status === 'recognizing text') {
progressText.textContent = `OCR: ${Math.round(m.progress*100)}%`;
} else {
progressText.textContent = `Tesseract: ${m.status}...`;
}
},
tessedit_pageseg_mode: '4'
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('OCR timed out after 90s')), 90000)
)
]);
```
**Why this works:**
- `Promise.race` breaks the hang — after 90s, it rejects with a clear error
- Full phase logging shows EXACTLY where it's stuck ("loading language traineddata..." = CDN issue)
- The console gets timestamped `[OCR]` logs for post-mortem debugging
## Performance: Adaptive Upscaling
3× upscale on HD screenshots creates massive canvases (5760×3240). Use adaptive scaling:
```javascript
// 2x for large images, 3x for small ones
const scale = (img.width * img.height > 1000000) ? 2 : 3;
canvas.width = img.width * scale;
canvas.height = img.height * scale;
```
This cuts pixel count by ~55% on typical screenshots while keeping 3× for small crops.
## Second OCR Pass (Date Extraction)
The date OCR pass uses PSM 11 (sparse text) and runs on the same preprocessed blob. Apply the same
pattern with a shorter timeout (30s):
```javascript
const dateOcrResult = await Promise.race([
Tesseract.recognize(preprocessed, 'eng', {
logger: m => { /* same pattern */ },
tessedit_pageseg_mode: '11'
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Date OCR timed out')), 30000)
)
]);
```
## Ollama Cold-Model 502 Retry
The VPS proxy may return 502 when the local model is unloaded (KEEP_ALIVE=5m). The model takes
~3-6s to load. Retry once after a 5s delay:
```javascript
for (let attempt = 0; attempt < 2; attempt++) {
const resp = await fetch(endpoint, { ... });
if (resp.ok) break;
if (resp.status !== 502 && resp.status !== 503) throw new Error(...);
await new Promise(r => setTimeout(r, 5000)); // wait for model load
}
```