File size: 1,707 Bytes
a920dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Text/image CAPTCHA solver — Tesseract.js running locally.
// Best fit: simple text-in-image CAPTCHAs. Trained data is pre-downloaded
// at build time to /app/tesseract-data.

let _workerPromise = null;

async function getWorker() {
  if (_workerPromise) return _workerPromise;
  _workerPromise = (async () => {
    const { createWorker } = require('tesseract.js');
    const worker = await createWorker('eng', 1, {
      langPath: process.env.TESSDATA_PREFIX || '/app/tesseract-data',
      cachePath: process.env.TESSDATA_PREFIX || '/app/tesseract-data',
      gzip: false,
    });
    await worker.setParameters({
      // Most CAPTCHAs are 4-8 chars; treat as a single line.
      tessedit_pageseg_mode: 7,
      // Restrict to alphanumerics — fewer hallucinations.
      tessedit_char_whitelist: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
    });
    return worker;
  })();
  return _workerPromise;
}

async function recognizeBuffer(imageBuffer) {
  const w = await getWorker();
  const { data } = await w.recognize(imageBuffer);
  return (data?.text || '').replace(/\s+/g, '').trim();
}

async function recognizeUrl(page, url) {
  const buf = await page.evaluate(async (u) => {
    const r = await fetch(u, { credentials: 'include' });
    if (!r.ok) throw new Error('image fetch failed: ' + r.status);
    const ab = await r.arrayBuffer();
    return Array.from(new Uint8Array(ab));
  }, url);
  return recognizeBuffer(Buffer.from(buf));
}

async function recognizeElement(page, selector) {
  const buf = await page.locator(selector).first().screenshot();
  return recognizeBuffer(buf);
}

module.exports = { recognizeBuffer, recognizeUrl, recognizeElement, getWorker };