zero-vision 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +163 -0
- package/dist/cdp/attach.js +121 -0
- package/dist/cdp/attach.js.map +1 -0
- package/dist/cdp/client.js +53 -0
- package/dist/cdp/client.js.map +1 -0
- package/dist/cdp/extract.js +197 -0
- package/dist/cdp/extract.js.map +1 -0
- package/dist/cli.js +223 -0
- package/dist/cli.js.map +1 -0
- package/dist/engines/apple-fm.js +103 -0
- package/dist/engines/apple-fm.js.map +1 -0
- package/dist/engines/apple-vision.js +89 -0
- package/dist/engines/apple-vision.js.map +1 -0
- package/dist/engines/cloud/index.js +41 -0
- package/dist/engines/cloud/index.js.map +1 -0
- package/dist/engines/index.js +71 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/local-vlm.js +46 -0
- package/dist/engines/local-vlm.js.map +1 -0
- package/dist/engines/tesseract.js +221 -0
- package/dist/engines/tesseract.js.map +1 -0
- package/dist/mcp.js +225 -0
- package/dist/mcp.js.map +1 -0
- package/dist/native.js +66 -0
- package/dist/native.js.map +1 -0
- package/dist/snap.js +30 -0
- package/dist/snap.js.map +1 -0
- package/dist/test/argv.test.js +22 -0
- package/dist/test/argv.test.js.map +1 -0
- package/dist/test/ax.test.js +28 -0
- package/dist/test/ax.test.js.map +1 -0
- package/dist/test/engines.test.js +81 -0
- package/dist/test/engines.test.js.map +1 -0
- package/dist/test/fetch.test.js +46 -0
- package/dist/test/fetch.test.js.map +1 -0
- package/dist/test/ocr.test.js +34 -0
- package/dist/test/ocr.test.js.map +1 -0
- package/dist/test/parity.test.js +33 -0
- package/dist/test/parity.test.js.map +1 -0
- package/dist/test/port.test.js +55 -0
- package/dist/test/port.test.js.map +1 -0
- package/dist/test/snap.test.js +13 -0
- package/dist/test/snap.test.js.map +1 -0
- package/dist/test/tesseract.test.js +17 -0
- package/dist/test/tesseract.test.js.map +1 -0
- package/docs/spec.md +549 -0
- package/package.json +40 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
const SKIP_ROLES = new Set(["none", "presentation", "InlineTextBox", "generic"]);
|
|
2
|
+
function prop(node, name) {
|
|
3
|
+
return node.properties?.find((p) => p.name === name)?.value?.value;
|
|
4
|
+
}
|
|
5
|
+
function interesting(n) {
|
|
6
|
+
if (n.ignored)
|
|
7
|
+
return false;
|
|
8
|
+
const role = String(n.role?.value ?? "");
|
|
9
|
+
if (SKIP_ROLES.has(role) && !n.name?.value)
|
|
10
|
+
return false;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
export function axToText(nodes) {
|
|
14
|
+
const byId = new Map(nodes.map((n) => [n.nodeId, n]));
|
|
15
|
+
const childOf = new Set();
|
|
16
|
+
for (const n of nodes)
|
|
17
|
+
for (const c of n.childIds ?? [])
|
|
18
|
+
childOf.add(c);
|
|
19
|
+
const roots = nodes.filter((n) => !childOf.has(n.nodeId));
|
|
20
|
+
let uid = 0;
|
|
21
|
+
const textLines = [];
|
|
22
|
+
const mdLines = [];
|
|
23
|
+
const yamlLines = [];
|
|
24
|
+
const walk = (id, depth) => {
|
|
25
|
+
const n = byId.get(id);
|
|
26
|
+
if (!n)
|
|
27
|
+
return;
|
|
28
|
+
const role = String(n.role?.value ?? "generic");
|
|
29
|
+
const name = String(n.name?.value ?? "").trim();
|
|
30
|
+
const value = n.value?.value != null ? String(n.value.value) : "";
|
|
31
|
+
const url = prop(n, "url");
|
|
32
|
+
const keep = interesting(n);
|
|
33
|
+
if (keep &&
|
|
34
|
+
role !== "RootWebArea" &&
|
|
35
|
+
role !== "WebArea" &&
|
|
36
|
+
(name || value || ["heading", "link", "button", "textbox", "checkbox"].includes(role))) {
|
|
37
|
+
const idn = `e${++uid}`;
|
|
38
|
+
const level = Number(prop(n, "level") ?? 0);
|
|
39
|
+
if (role === "heading") {
|
|
40
|
+
const hashes = "#".repeat(Math.min(Math.max(level || 1, 1), 6));
|
|
41
|
+
textLines.push(name);
|
|
42
|
+
mdLines.push(`${hashes} ${name}`);
|
|
43
|
+
yamlLines.push(`${" ".repeat(depth)}- heading ${JSON.stringify(name)} [level=${level || 1}] [uid=${idn}]`);
|
|
44
|
+
}
|
|
45
|
+
else if (role === "link") {
|
|
46
|
+
textLines.push(name);
|
|
47
|
+
mdLines.push(typeof url === "string" && url ? `[${name}](${url})` : name);
|
|
48
|
+
yamlLines.push(`${" ".repeat(depth)}- link ${JSON.stringify(name)} [uid=${idn}]`);
|
|
49
|
+
}
|
|
50
|
+
else if (role === "textbox") {
|
|
51
|
+
textLines.push(value ? `${name}: ${value}` : name);
|
|
52
|
+
mdLines.push(`**${name}:** ${value}`);
|
|
53
|
+
yamlLines.push(`${" ".repeat(depth)}- textbox ${JSON.stringify(name)} [uid=${idn}] [value=${JSON.stringify(value)}]`);
|
|
54
|
+
}
|
|
55
|
+
else if (role === "checkbox") {
|
|
56
|
+
const checked = Boolean(prop(n, "checked"));
|
|
57
|
+
textLines.push(`${checked ? "[x]" : "[ ]"} ${name}`);
|
|
58
|
+
mdLines.push(`- [${checked ? "x" : " "}] ${name}`);
|
|
59
|
+
yamlLines.push(`${" ".repeat(depth)}- checkbox ${JSON.stringify(name)} [uid=${idn}]`);
|
|
60
|
+
}
|
|
61
|
+
else if (role === "button") {
|
|
62
|
+
textLines.push(name);
|
|
63
|
+
mdLines.push(name);
|
|
64
|
+
yamlLines.push(`${" ".repeat(depth)}- button ${JSON.stringify(name)} [uid=${idn}]`);
|
|
65
|
+
}
|
|
66
|
+
else if (name) {
|
|
67
|
+
textLines.push(name);
|
|
68
|
+
mdLines.push(name);
|
|
69
|
+
yamlLines.push(`${" ".repeat(depth)}- ${role} ${JSON.stringify(name)} [uid=${idn}]`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const c of n.childIds ?? [])
|
|
73
|
+
walk(c, depth + (keep ? 1 : 0));
|
|
74
|
+
};
|
|
75
|
+
for (const r of roots)
|
|
76
|
+
walk(r.nodeId, 0);
|
|
77
|
+
const cap = (s) => (s.length > 24000 ? s.slice(0, 24000) + "\n…[truncated]" : s);
|
|
78
|
+
return {
|
|
79
|
+
text: cap(textLines.join("\n")),
|
|
80
|
+
markdown: cap(mdLines.join("\n")),
|
|
81
|
+
a11y: cap(yamlLines.join("\n")),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const OPAQUE_JS = `() => {
|
|
85
|
+
const area = (el) => {
|
|
86
|
+
const r = el.getBoundingClientRect();
|
|
87
|
+
return Math.max(0, r.width) * Math.max(0, r.height);
|
|
88
|
+
};
|
|
89
|
+
const vp = innerWidth * innerHeight || 1;
|
|
90
|
+
const nodes = [...document.querySelectorAll('canvas, video')];
|
|
91
|
+
let px = 0;
|
|
92
|
+
const reasons = [];
|
|
93
|
+
for (const el of nodes) {
|
|
94
|
+
const a = area(el);
|
|
95
|
+
if (a / vp >= 0.05) {
|
|
96
|
+
px += a;
|
|
97
|
+
reasons.push(el.tagName.toLowerCase());
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { fraction: px / vp, reasons: [...new Set(reasons)] };
|
|
101
|
+
}`;
|
|
102
|
+
export async function extractPage(client, sessionId, opts = {}) {
|
|
103
|
+
await client.send("Runtime.enable", {}, sessionId);
|
|
104
|
+
await client.send("Page.enable", {}, sessionId);
|
|
105
|
+
await client.send("Accessibility.enable", {}, sessionId);
|
|
106
|
+
const ready = (await client.send("Runtime.evaluate", { expression: "document.readyState", returnByValue: true }, sessionId));
|
|
107
|
+
if (ready.result?.value !== "complete") {
|
|
108
|
+
await Promise.race([
|
|
109
|
+
new Promise((resolve) => {
|
|
110
|
+
const onLoad = () => {
|
|
111
|
+
client.off("Page.loadEventFired", onLoad);
|
|
112
|
+
resolve();
|
|
113
|
+
};
|
|
114
|
+
client.on("Page.loadEventFired", onLoad);
|
|
115
|
+
}),
|
|
116
|
+
new Promise((resolve) => setTimeout(resolve, 8000)),
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
await Promise.race([
|
|
120
|
+
new Promise((resolve) => {
|
|
121
|
+
const onAx = () => {
|
|
122
|
+
client.off("Accessibility.loadComplete", onAx);
|
|
123
|
+
resolve();
|
|
124
|
+
};
|
|
125
|
+
client.on("Accessibility.loadComplete", onAx);
|
|
126
|
+
}),
|
|
127
|
+
new Promise((resolve) => setTimeout(resolve, 2000)),
|
|
128
|
+
]);
|
|
129
|
+
if (opts.waitMs)
|
|
130
|
+
await new Promise((r) => setTimeout(r, opts.waitMs));
|
|
131
|
+
if (opts.waitText) {
|
|
132
|
+
const deadline = Date.now() + 8000;
|
|
133
|
+
while (Date.now() < deadline) {
|
|
134
|
+
const ev = (await client.send("Runtime.evaluate", { expression: "document.body && document.body.innerText || ''", returnByValue: true }, sessionId));
|
|
135
|
+
if ((ev.result?.value ?? "").includes(opts.waitText))
|
|
136
|
+
break;
|
|
137
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (opts.scroll) {
|
|
141
|
+
await client.send("Runtime.evaluate", {
|
|
142
|
+
expression: "(async () => { const h = document.body.scrollHeight; for (let y=0; y<h; y+=800) { scrollTo(0,y); await new Promise(r=>setTimeout(r,150)); } })()",
|
|
143
|
+
awaitPromise: true,
|
|
144
|
+
}, sessionId);
|
|
145
|
+
}
|
|
146
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
147
|
+
const { nodes } = (await client.send("Accessibility.getFullAXTree", {}, sessionId));
|
|
148
|
+
const walked = axToText(nodes);
|
|
149
|
+
let opaque = { fraction: 0, reasons: [] };
|
|
150
|
+
try {
|
|
151
|
+
const ev = (await client.send("Runtime.evaluate", { expression: `(${OPAQUE_JS})()`, returnByValue: true }, sessionId));
|
|
152
|
+
if (ev.result?.value)
|
|
153
|
+
opaque = ev.result.value;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* page may deny */
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
await client.send("Accessibility.disable", {}, sessionId);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
/* ignore */
|
|
163
|
+
}
|
|
164
|
+
let a11y = walked.a11y;
|
|
165
|
+
if (opaque.fraction >= 0.3) {
|
|
166
|
+
a11y += `\nopaque: ${opaque.reasons[0] ?? "canvas"} ${opaque.fraction.toFixed(2)} viewport`;
|
|
167
|
+
}
|
|
168
|
+
if (opts.verbose) {
|
|
169
|
+
a11y += "\n--- raw ---\n" + JSON.stringify(nodes).slice(0, 8000);
|
|
170
|
+
}
|
|
171
|
+
return { text: walked.text, markdown: walked.markdown, a11y, opaque };
|
|
172
|
+
}
|
|
173
|
+
export async function captureScreenshot(client, sessionId) {
|
|
174
|
+
const result = (await client.send("Page.captureScreenshot", { format: "png" }, sessionId));
|
|
175
|
+
if (!result?.data)
|
|
176
|
+
throw new Error("Page.captureScreenshot returned no data");
|
|
177
|
+
return Buffer.from(result.data, "base64");
|
|
178
|
+
}
|
|
179
|
+
export async function fetchUrl(url) {
|
|
180
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
181
|
+
const html = await res.text();
|
|
182
|
+
const stripped = html
|
|
183
|
+
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
|
184
|
+
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
|
185
|
+
.replace(/<[^>]+>/g, " ")
|
|
186
|
+
.replace(/ /g, " ")
|
|
187
|
+
.replace(/&/g, "&")
|
|
188
|
+
.replace(/</g, "<")
|
|
189
|
+
.replace(/>/g, ">")
|
|
190
|
+
.replace(/\s+/g, " ")
|
|
191
|
+
.trim();
|
|
192
|
+
if (stripped.length < 200 && /id=["']root["']/.test(html)) {
|
|
193
|
+
throw Object.assign(new Error("page looks like a client render; open it in a debug Chrome and retry without --fetch"), { code: 1 });
|
|
194
|
+
}
|
|
195
|
+
return { text: stripped.slice(0, 24000), markdown: stripped.slice(0, 24000) };
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/cdp/extract.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { perceive, resolveEngine } from "./engines/index.js";
|
|
4
|
+
import { attach, findOpenPort, listTabs } from "./cdp/attach.js";
|
|
5
|
+
import { captureScreenshot, extractPage, fetchUrl } from "./cdp/extract.js";
|
|
6
|
+
import { interactiveCapture, runScreencapture } from "./snap.js";
|
|
7
|
+
const BOOL = new Set([
|
|
8
|
+
"md",
|
|
9
|
+
"a11y",
|
|
10
|
+
"json",
|
|
11
|
+
"navigate",
|
|
12
|
+
"fetch",
|
|
13
|
+
"ocr",
|
|
14
|
+
"ocr-opaque",
|
|
15
|
+
"scroll",
|
|
16
|
+
"clipboard",
|
|
17
|
+
"tabs",
|
|
18
|
+
"verbose",
|
|
19
|
+
"help",
|
|
20
|
+
]);
|
|
21
|
+
function usage() {
|
|
22
|
+
process.stderr.write(`zrv — read a page, a screenshot, or a video as text
|
|
23
|
+
zrv [--md|--a11y] [--tab id] [--url u] [--engine e] [--json]
|
|
24
|
+
zrv --tabs
|
|
25
|
+
zrv ocr <file> [--engine e] [--task transcribe|describe] [--mode scene|interval|all-idr] [--interval s] [--max-frames n]
|
|
26
|
+
zrv snap [--ocr] [--save path]
|
|
27
|
+
zrv mcp
|
|
28
|
+
`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
function isVideo(p) {
|
|
32
|
+
return /\.(mp4|mov|m4v|webm)$/i.test(p);
|
|
33
|
+
}
|
|
34
|
+
async function copyText(text) {
|
|
35
|
+
await new Promise((resolve) => {
|
|
36
|
+
const pb = spawn("pbcopy");
|
|
37
|
+
pb.stdin.write(text);
|
|
38
|
+
pb.stdin.end();
|
|
39
|
+
pb.on("close", () => resolve());
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function failCode(result) {
|
|
43
|
+
const err = result.error ?? "";
|
|
44
|
+
if (err.includes("cannot describe"))
|
|
45
|
+
return 1;
|
|
46
|
+
if (err.includes("unavailable") || err.includes("weights missing") || err.includes("unset"))
|
|
47
|
+
return 3;
|
|
48
|
+
if (err.includes("input missing") || err.includes("path required"))
|
|
49
|
+
return 2;
|
|
50
|
+
return 4;
|
|
51
|
+
}
|
|
52
|
+
function outResult(result, json) {
|
|
53
|
+
if (json) {
|
|
54
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
55
|
+
}
|
|
56
|
+
else if (result.ok) {
|
|
57
|
+
process.stdout.write(result.text + (result.text.endsWith("\n") ? "" : "\n"));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
process.stderr.write((result.error ?? "failed") + "\n");
|
|
61
|
+
}
|
|
62
|
+
process.exit(result.ok ? 0 : failCode(result));
|
|
63
|
+
}
|
|
64
|
+
export function parseArgv(raw) {
|
|
65
|
+
const flags = {};
|
|
66
|
+
const pos = [];
|
|
67
|
+
const langs = [];
|
|
68
|
+
for (let i = 0; i < raw.length; i++) {
|
|
69
|
+
const a = raw[i];
|
|
70
|
+
if (a === "-h" || a === "--help")
|
|
71
|
+
flags.help = true;
|
|
72
|
+
else if (a === "--lang" && i + 1 < raw.length)
|
|
73
|
+
langs.push(raw[++i]);
|
|
74
|
+
else if (a.startsWith("--") && BOOL.has(a.slice(2)))
|
|
75
|
+
flags[a.slice(2)] = true;
|
|
76
|
+
else if (a.startsWith("--") && i + 1 < raw.length)
|
|
77
|
+
flags[a.slice(2)] = raw[++i];
|
|
78
|
+
else if (a.startsWith("--"))
|
|
79
|
+
usage();
|
|
80
|
+
else
|
|
81
|
+
pos.push(a);
|
|
82
|
+
}
|
|
83
|
+
const cmd = pos[0] === "ocr" || pos[0] === "snap" || pos[0] === "mcp" ? pos.shift() : "page";
|
|
84
|
+
return { cmd, pos, flags, langs };
|
|
85
|
+
}
|
|
86
|
+
async function main() {
|
|
87
|
+
const argv0 = process.argv[1] ?? "";
|
|
88
|
+
const raw = process.argv.slice(2);
|
|
89
|
+
if (argv0.endsWith("/snap") || argv0 === "snap" || argv0.endsWith("\\snap"))
|
|
90
|
+
raw.unshift("snap");
|
|
91
|
+
const { cmd, pos, flags, langs } = parseArgv(raw);
|
|
92
|
+
if (flags.help)
|
|
93
|
+
usage();
|
|
94
|
+
if (cmd === "mcp") {
|
|
95
|
+
const { startMcp } = await import("./mcp.js");
|
|
96
|
+
await startMcp();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const engine = resolveEngine(typeof flags.engine === "string" ? flags.engine : undefined);
|
|
100
|
+
if (cmd === "snap") {
|
|
101
|
+
if (!flags.ocr && !flags.save) {
|
|
102
|
+
const code = await runScreencapture();
|
|
103
|
+
process.exit(code === 0 ? 0 : 130);
|
|
104
|
+
}
|
|
105
|
+
const save = typeof flags.save === "string" ? flags.save : undefined;
|
|
106
|
+
const file = await interactiveCapture({ save });
|
|
107
|
+
if (!file)
|
|
108
|
+
process.exit(130);
|
|
109
|
+
if (flags.ocr) {
|
|
110
|
+
const result = await perceive(engine, { kind: "image", path: file, task: "transcribe" });
|
|
111
|
+
if (!result.ok) {
|
|
112
|
+
process.stderr.write((result.error ?? "ocr failed") + "\n");
|
|
113
|
+
process.exit(failCode(result));
|
|
114
|
+
}
|
|
115
|
+
process.stdout.write(result.text + (result.text.endsWith("\n") ? "" : "\n"));
|
|
116
|
+
await copyText(result.text);
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (cmd === "ocr") {
|
|
121
|
+
const file = pos[0];
|
|
122
|
+
const task = flags.task === "describe" ? "describe" : "transcribe";
|
|
123
|
+
if (flags.clipboard) {
|
|
124
|
+
const result = await perceive(engine, {
|
|
125
|
+
kind: "clipboard",
|
|
126
|
+
task,
|
|
127
|
+
level: flags.level === "fast" ? "fast" : "accurate",
|
|
128
|
+
lang: langs.length ? langs : undefined,
|
|
129
|
+
});
|
|
130
|
+
outResult(result, Boolean(flags.json));
|
|
131
|
+
}
|
|
132
|
+
if (!file)
|
|
133
|
+
usage();
|
|
134
|
+
const kind = isVideo(file) ? "video" : "image";
|
|
135
|
+
const modeRaw = typeof flags.mode === "string" ? flags.mode : "scene";
|
|
136
|
+
const mode = modeRaw === "interval" || modeRaw === "all-idr" ? modeRaw : "scene";
|
|
137
|
+
const result = await perceive(engine, {
|
|
138
|
+
kind,
|
|
139
|
+
path: file,
|
|
140
|
+
task,
|
|
141
|
+
level: flags.level === "fast" ? "fast" : "accurate",
|
|
142
|
+
lang: langs.length ? langs : undefined,
|
|
143
|
+
...(kind === "video"
|
|
144
|
+
? {
|
|
145
|
+
video: {
|
|
146
|
+
mode,
|
|
147
|
+
interval: flags.interval ? Number(flags.interval) : 2,
|
|
148
|
+
maxFrames: flags["max-frames"] ? Number(flags["max-frames"]) : 60,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
});
|
|
153
|
+
outResult(result, Boolean(flags.json));
|
|
154
|
+
}
|
|
155
|
+
if (flags.tabs) {
|
|
156
|
+
const { port } = await findOpenPort(flags.port ? Number(flags.port) : undefined);
|
|
157
|
+
const tabs = await listTabs(port);
|
|
158
|
+
for (const t of tabs)
|
|
159
|
+
process.stdout.write(`${t.id}\t${t.title}\t${t.url}\n`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (flags.fetch && typeof flags.url === "string") {
|
|
163
|
+
const { text, markdown } = await fetchUrl(flags.url);
|
|
164
|
+
process.stdout.write((flags.md ? markdown : text) + "\n");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const attached = await attach({
|
|
168
|
+
port: flags.port ? Number(flags.port) : undefined,
|
|
169
|
+
tab: typeof flags.tab === "string" ? flags.tab : undefined,
|
|
170
|
+
url: typeof flags.url === "string" ? flags.url : undefined,
|
|
171
|
+
navigate: Boolean(flags.navigate),
|
|
172
|
+
});
|
|
173
|
+
process.stderr.write(`${attached.title}\t${attached.url}\n`);
|
|
174
|
+
try {
|
|
175
|
+
const extracted = await extractPage(attached.client, attached.sessionId, {
|
|
176
|
+
waitMs: flags["wait-ms"] ? Number(flags["wait-ms"]) : undefined,
|
|
177
|
+
waitText: typeof flags["wait-text"] === "string" ? flags["wait-text"] : undefined,
|
|
178
|
+
scroll: Boolean(flags.scroll),
|
|
179
|
+
verbose: Boolean(flags.verbose),
|
|
180
|
+
});
|
|
181
|
+
let body = extracted.text;
|
|
182
|
+
if (flags.a11y)
|
|
183
|
+
body = extracted.a11y;
|
|
184
|
+
else if (flags.md)
|
|
185
|
+
body = extracted.markdown;
|
|
186
|
+
if (flags["ocr-opaque"] && extracted.opaque.fraction >= 0.3) {
|
|
187
|
+
const png = await captureScreenshot(attached.client, attached.sessionId);
|
|
188
|
+
const ocr = await perceive(engine, { kind: "image", bytes: png, task: "transcribe" });
|
|
189
|
+
if (ocr.ok && ocr.text)
|
|
190
|
+
body += (body.endsWith("\n") ? "" : "\n") + "--- opaque ocr ---\n" + ocr.text;
|
|
191
|
+
}
|
|
192
|
+
if (flags.json) {
|
|
193
|
+
process.stdout.write(JSON.stringify({
|
|
194
|
+
ok: true,
|
|
195
|
+
source: "cdp",
|
|
196
|
+
port: attached.port,
|
|
197
|
+
targetId: attached.targetId,
|
|
198
|
+
title: attached.title,
|
|
199
|
+
url: attached.url,
|
|
200
|
+
text: body,
|
|
201
|
+
opaque: extracted.opaque,
|
|
202
|
+
}) + "\n");
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
process.stdout.write(body + (body.endsWith("\n") ? "" : "\n"));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
attached.client.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const isMain = process.argv[1]?.endsWith("cli.js") ||
|
|
213
|
+
process.argv[1]?.endsWith("cli.ts") ||
|
|
214
|
+
process.argv[1]?.endsWith("/zrv") ||
|
|
215
|
+
process.argv[1]?.endsWith("/snap");
|
|
216
|
+
if (isMain) {
|
|
217
|
+
main().catch((err) => {
|
|
218
|
+
const code = typeof err === "object" && err && "code" in err ? Number(err.code) : 1;
|
|
219
|
+
process.stderr.write((err instanceof Error ? err.message : String(err)) + "\n");
|
|
220
|
+
process.exit(Number.isFinite(code) && code > 0 ? code : 1);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
function runFm(argv) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const child = spawn("fm", argv, { stdio: ["ignore", "pipe", "pipe"] });
|
|
6
|
+
let stdout = "";
|
|
7
|
+
let stderr = "";
|
|
8
|
+
child.stdout.setEncoding("utf8");
|
|
9
|
+
child.stderr.setEncoding("utf8");
|
|
10
|
+
child.stdout.on("data", (c) => {
|
|
11
|
+
stdout += c;
|
|
12
|
+
});
|
|
13
|
+
child.stderr.on("data", (c) => {
|
|
14
|
+
stderr += c;
|
|
15
|
+
});
|
|
16
|
+
child.on("error", (err) => reject(err));
|
|
17
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stdout, stderr }));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export const appleFm = {
|
|
21
|
+
id: "apple-fm",
|
|
22
|
+
capabilities: ["transcribe", "describe"],
|
|
23
|
+
async perceive(input) {
|
|
24
|
+
const t0 = Date.now();
|
|
25
|
+
const task = input.task ?? "transcribe";
|
|
26
|
+
if (!existsSync("/usr/bin/fm")) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
engine: "apple-fm",
|
|
30
|
+
task,
|
|
31
|
+
text: "",
|
|
32
|
+
ms: 0,
|
|
33
|
+
error: "apple-fm unavailable",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (input.kind === "video") {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
engine: "apple-fm",
|
|
40
|
+
task,
|
|
41
|
+
text: "",
|
|
42
|
+
ms: 0,
|
|
43
|
+
error: "apple-fm does not OCR video; use apple-vision",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (input.kind === "clipboard" || !input.path) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
engine: "apple-fm",
|
|
50
|
+
task,
|
|
51
|
+
text: "",
|
|
52
|
+
ms: 0,
|
|
53
|
+
error: "apple-fm needs --image path (clipboard: snap to a file first)",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const prompt = task === "describe"
|
|
57
|
+
? "Describe this image. If it contains text, quote the text."
|
|
58
|
+
: "Transcribe all text verbatim. Do not paraphrase.";
|
|
59
|
+
try {
|
|
60
|
+
const { code, stdout, stderr } = await runFm([
|
|
61
|
+
"respond",
|
|
62
|
+
"--image",
|
|
63
|
+
input.path,
|
|
64
|
+
"--text",
|
|
65
|
+
prompt,
|
|
66
|
+
"--tool",
|
|
67
|
+
"ocr",
|
|
68
|
+
"--no-stream",
|
|
69
|
+
]);
|
|
70
|
+
const text = stdout.trim();
|
|
71
|
+
if (code !== 0 || !text) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
engine: "apple-fm",
|
|
75
|
+
task,
|
|
76
|
+
text: "",
|
|
77
|
+
ms: Date.now() - t0,
|
|
78
|
+
model: "system",
|
|
79
|
+
error: stderr.trim() || `fm exit ${code}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
ok: true,
|
|
84
|
+
engine: "apple-fm",
|
|
85
|
+
task,
|
|
86
|
+
text,
|
|
87
|
+
ms: Date.now() - t0,
|
|
88
|
+
model: "system",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
engine: "apple-fm",
|
|
95
|
+
task,
|
|
96
|
+
text: "",
|
|
97
|
+
ms: Date.now() - t0,
|
|
98
|
+
error: err instanceof Error ? err.message : String(err),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=apple-fm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apple-fm.js","sourceRoot":"","sources":["../../src/engines/apple-fm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { writeFileSync, mkdtempSync, rmSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { spawnNative } from "../native.js";
|
|
5
|
+
function parseJson(stdout) {
|
|
6
|
+
const line = stdout.trim().split("\n").filter(Boolean).at(-1) ?? "{}";
|
|
7
|
+
try {
|
|
8
|
+
const raw = JSON.parse(line);
|
|
9
|
+
return { ...raw, engine: "apple-vision", task: raw.task ?? "transcribe" };
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
engine: "apple-vision",
|
|
15
|
+
task: "transcribe",
|
|
16
|
+
text: "",
|
|
17
|
+
ms: 0,
|
|
18
|
+
error: `native json parse failed: ${line.slice(0, 200)}`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const appleVision = {
|
|
23
|
+
id: "apple-vision",
|
|
24
|
+
capabilities: ["transcribe"],
|
|
25
|
+
async perceive(input) {
|
|
26
|
+
const task = input.task ?? "transcribe";
|
|
27
|
+
const level = input.level ?? "accurate";
|
|
28
|
+
const langs = input.lang ?? ["en-US"];
|
|
29
|
+
const langArgs = langs.flatMap((l) => ["--lang", l]);
|
|
30
|
+
if (input.kind === "clipboard") {
|
|
31
|
+
const { stdout, stderr } = await spawnNative(["ocr-clipboard", "--level", level, ...langArgs, "--json"]);
|
|
32
|
+
return parseJson(stdout || stderr);
|
|
33
|
+
}
|
|
34
|
+
let path = input.path;
|
|
35
|
+
let tmp;
|
|
36
|
+
if (input.bytes) {
|
|
37
|
+
if (input.bytes.length > 30 * 1024 * 1024) {
|
|
38
|
+
return { ok: false, engine: "apple-vision", task, text: "", ms: 0, error: "input exceeds 30 MB" };
|
|
39
|
+
}
|
|
40
|
+
tmp = mkdtempSync(join(tmpdir(), "zrv-"));
|
|
41
|
+
path = join(tmp, "in.bin");
|
|
42
|
+
writeFileSync(path, input.bytes);
|
|
43
|
+
}
|
|
44
|
+
if (!path) {
|
|
45
|
+
return { ok: false, engine: "apple-vision", task, text: "", ms: 0, error: "path required" };
|
|
46
|
+
}
|
|
47
|
+
if (!tmp) {
|
|
48
|
+
try {
|
|
49
|
+
path = realpathSync(path);
|
|
50
|
+
if (!statSync(path).isFile()) {
|
|
51
|
+
return { ok: false, engine: "apple-vision", task, text: "", ms: 0, error: "path required" };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { ok: false, engine: "apple-vision", task, text: "", ms: 0, error: "input missing" };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
if (input.kind === "video") {
|
|
60
|
+
const mode = input.video?.mode ?? "scene";
|
|
61
|
+
const interval = String(input.video?.interval ?? 2);
|
|
62
|
+
const maxFrames = String(input.video?.maxFrames ?? 60);
|
|
63
|
+
const { stdout, stderr } = await spawnNative([
|
|
64
|
+
"ocr-video",
|
|
65
|
+
"--input",
|
|
66
|
+
path,
|
|
67
|
+
"--mode",
|
|
68
|
+
mode,
|
|
69
|
+
"--interval",
|
|
70
|
+
interval,
|
|
71
|
+
"--max-frames",
|
|
72
|
+
maxFrames,
|
|
73
|
+
"--level",
|
|
74
|
+
level,
|
|
75
|
+
...langArgs,
|
|
76
|
+
"--json",
|
|
77
|
+
], { timeoutMs: 180_000 });
|
|
78
|
+
return parseJson(stdout || stderr);
|
|
79
|
+
}
|
|
80
|
+
const { stdout, stderr } = await spawnNative(["ocr-image", "--input", path, "--level", level, ...langArgs, "--json"]);
|
|
81
|
+
return parseJson(stdout || stderr);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
if (tmp)
|
|
85
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=apple-vision.js.map
|