@zqagent/core 0.2.20 → 0.3.6
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/README.md +1 -1
- package/README.oss.en.md +3 -3
- package/README.oss.md +8 -3
- package/README.oss.zh-TW.md +3 -3
- package/dist/McpClient-CEQBUPuC.d.cts +145 -0
- package/dist/McpClient-CEQBUPuC.d.ts +145 -0
- package/dist/{ToolRegistry-C3pTFiaJ.d.cts → ToolRegistry-Cy0fQxrb.d.ts} +2 -111
- package/dist/{ToolRegistry-C3pTFiaJ.d.ts → ToolRegistry-DouDvn9E.d.cts} +2 -111
- package/dist/{explore-RtZtb-V6.d.ts → TurnEngine-BPKhWuSI.d.cts} +108 -73
- package/dist/{explore-BgRhj6SP.d.cts → TurnEngine-DtGEuVLT.d.ts} +108 -73
- package/dist/conflictGuard-BBOOIxxK.d.cts +42 -0
- package/dist/conflictGuard-BBOOIxxK.d.ts +42 -0
- package/dist/index.cjs +5418 -1096
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +577 -195
- package/dist/index.d.ts +577 -195
- package/dist/index.js +5299 -1011
- package/dist/index.js.map +1 -1
- package/dist/internal/crypto/secrets.cjs +25 -0
- package/dist/internal/crypto/secrets.cjs.map +1 -0
- package/dist/internal/crypto/secrets.d.cts +2 -0
- package/dist/internal/crypto/secrets.d.ts +2 -0
- package/dist/internal/crypto/secrets.js +3 -0
- package/dist/internal/crypto/secrets.js.map +1 -0
- package/dist/internal/engine/FileLogHook.cjs +179 -0
- package/dist/internal/engine/FileLogHook.cjs.map +1 -0
- package/dist/internal/engine/FileLogHook.d.cts +67 -0
- package/dist/internal/engine/FileLogHook.d.ts +67 -0
- package/dist/internal/engine/FileLogHook.js +144 -0
- package/dist/internal/engine/FileLogHook.js.map +1 -0
- package/dist/internal/engine/approvalView.cjs +25 -0
- package/dist/internal/engine/approvalView.cjs.map +1 -0
- package/dist/internal/engine/approvalView.d.cts +1 -0
- package/dist/internal/engine/approvalView.d.ts +1 -0
- package/dist/internal/engine/approvalView.js +3 -0
- package/dist/internal/engine/approvalView.js.map +1 -0
- package/dist/internal/engine/limits.cjs +59 -0
- package/dist/internal/engine/limits.cjs.map +1 -0
- package/dist/internal/engine/limits.d.cts +32 -0
- package/dist/internal/engine/limits.d.ts +32 -0
- package/dist/internal/engine/limits.js +31 -0
- package/dist/internal/engine/limits.js.map +1 -0
- package/dist/internal/engine/sessionNaming.cjs +47 -0
- package/dist/internal/engine/sessionNaming.cjs.map +1 -0
- package/dist/internal/engine/sessionNaming.d.cts +25 -0
- package/dist/internal/engine/sessionNaming.d.ts +25 -0
- package/dist/internal/engine/sessionNaming.js +20 -0
- package/dist/internal/engine/sessionNaming.js.map +1 -0
- package/dist/internal/llmConfig.cjs +561 -0
- package/dist/internal/llmConfig.cjs.map +1 -0
- package/dist/internal/llmConfig.d.cts +75 -0
- package/dist/internal/llmConfig.d.ts +75 -0
- package/dist/internal/llmConfig.js +535 -0
- package/dist/internal/llmConfig.js.map +1 -0
- package/dist/internal/mcp/builtin/index.cjs +685 -0
- package/dist/internal/mcp/builtin/index.cjs.map +1 -0
- package/dist/internal/mcp/builtin/index.d.cts +21 -0
- package/dist/internal/mcp/builtin/index.d.ts +21 -0
- package/dist/internal/mcp/builtin/index.js +652 -0
- package/dist/internal/mcp/builtin/index.js.map +1 -0
- package/dist/internal/mcp/config.cjs +278 -0
- package/dist/internal/mcp/config.cjs.map +1 -0
- package/dist/internal/mcp/config.d.cts +61 -0
- package/dist/internal/mcp/config.d.ts +61 -0
- package/dist/internal/mcp/config.js +235 -0
- package/dist/internal/mcp/config.js.map +1 -0
- package/dist/internal/mcp/presets.cjs +184 -0
- package/dist/internal/mcp/presets.cjs.map +1 -0
- package/dist/internal/mcp/presets.d.cts +39 -0
- package/dist/internal/mcp/presets.d.ts +39 -0
- package/dist/internal/mcp/presets.js +158 -0
- package/dist/internal/mcp/presets.js.map +1 -0
- package/dist/internal/node-name.cjs +45 -0
- package/dist/internal/node-name.cjs.map +1 -0
- package/dist/internal/node-name.d.cts +3 -0
- package/dist/internal/node-name.d.ts +3 -0
- package/dist/internal/node-name.js +10 -0
- package/dist/internal/node-name.js.map +1 -0
- package/dist/internal/paths.cjs +63 -0
- package/dist/internal/paths.cjs.map +1 -0
- package/dist/internal/paths.d.cts +17 -0
- package/dist/internal/paths.d.ts +17 -0
- package/dist/internal/paths.js +25 -0
- package/dist/internal/paths.js.map +1 -0
- package/dist/internal/providers/diagnostics.cjs +288 -0
- package/dist/internal/providers/diagnostics.cjs.map +1 -0
- package/dist/internal/providers/diagnostics.d.cts +103 -0
- package/dist/internal/providers/diagnostics.d.ts +103 -0
- package/dist/internal/providers/diagnostics.js +250 -0
- package/dist/internal/providers/diagnostics.js.map +1 -0
- package/dist/internal/providers/models.cjs +699 -0
- package/dist/internal/providers/models.cjs.map +1 -0
- package/dist/internal/providers/models.d.cts +136 -0
- package/dist/internal/providers/models.d.ts +136 -0
- package/dist/internal/providers/models.js +654 -0
- package/dist/internal/providers/models.js.map +1 -0
- package/dist/internal/terminal.cjs +161 -0
- package/dist/internal/terminal.cjs.map +1 -0
- package/dist/internal/terminal.d.cts +58 -0
- package/dist/internal/terminal.d.ts +58 -0
- package/dist/internal/terminal.js +128 -0
- package/dist/internal/terminal.js.map +1 -0
- package/dist/internal/tools/execAsync.cjs +187 -0
- package/dist/internal/tools/execAsync.cjs.map +1 -0
- package/dist/internal/tools/execAsync.d.cts +30 -0
- package/dist/internal/tools/execAsync.d.ts +30 -0
- package/dist/internal/tools/execAsync.js +162 -0
- package/dist/internal/tools/execAsync.js.map +1 -0
- package/dist/internal/tools/git.cjs +935 -0
- package/dist/internal/tools/git.cjs.map +1 -0
- package/dist/internal/tools/git.d.cts +206 -0
- package/dist/internal/tools/git.d.ts +206 -0
- package/dist/internal/tools/git.js +883 -0
- package/dist/internal/tools/git.js.map +1 -0
- package/dist/internal/tools/pathSafety.cjs +99 -0
- package/dist/internal/tools/pathSafety.cjs.map +1 -0
- package/dist/internal/tools/pathSafety.d.cts +44 -0
- package/dist/internal/tools/pathSafety.d.ts +44 -0
- package/dist/internal/tools/pathSafety.js +61 -0
- package/dist/internal/tools/pathSafety.js.map +1 -0
- package/dist/internal/tools/plan.cjs +146 -0
- package/dist/internal/tools/plan.cjs.map +1 -0
- package/dist/internal/tools/plan.d.cts +48 -0
- package/dist/internal/tools/plan.d.ts +48 -0
- package/dist/internal/tools/plan.js +117 -0
- package/dist/internal/tools/plan.js.map +1 -0
- package/dist/internal/tools/ripgrep.cjs +118 -0
- package/dist/internal/tools/ripgrep.cjs.map +1 -0
- package/dist/internal/tools/ripgrep.d.cts +6 -0
- package/dist/internal/tools/ripgrep.d.ts +6 -0
- package/dist/internal/tools/ripgrep.js +89 -0
- package/dist/internal/tools/ripgrep.js.map +1 -0
- package/dist/internal/tools/sandbox.cjs +253 -0
- package/dist/internal/tools/sandbox.cjs.map +1 -0
- package/dist/internal/tools/sandbox.d.cts +67 -0
- package/dist/internal/tools/sandbox.d.ts +67 -0
- package/dist/internal/tools/sandbox.js +213 -0
- package/dist/internal/tools/sandbox.js.map +1 -0
- package/dist/internal/tools/shell.cjs +771 -0
- package/dist/internal/tools/shell.cjs.map +1 -0
- package/dist/internal/tools/shell.d.cts +47 -0
- package/dist/internal/tools/shell.d.ts +47 -0
- package/dist/internal/tools/shell.js +731 -0
- package/dist/internal/tools/shell.js.map +1 -0
- package/dist/internal/tools/shellRuntime.cjs +220 -0
- package/dist/internal/tools/shellRuntime.cjs.map +1 -0
- package/dist/internal/tools/shellRuntime.d.cts +67 -0
- package/dist/internal/tools/shellRuntime.d.ts +67 -0
- package/dist/internal/tools/shellRuntime.js +181 -0
- package/dist/internal/tools/shellRuntime.js.map +1 -0
- package/dist/internal/update/controller.cjs +1035 -0
- package/dist/internal/update/controller.cjs.map +1 -0
- package/dist/internal/update/controller.d.cts +150 -0
- package/dist/internal/update/controller.d.ts +150 -0
- package/dist/internal/update/controller.js +991 -0
- package/dist/internal/update/controller.js.map +1 -0
- package/dist/internal/update/platform.cjs +234 -0
- package/dist/internal/update/platform.cjs.map +1 -0
- package/dist/internal/update/platform.d.cts +77 -0
- package/dist/internal/update/platform.d.ts +77 -0
- package/dist/internal/update/platform.js +184 -0
- package/dist/internal/update/platform.js.map +1 -0
- package/dist/tools/ask.d.cts +3 -1
- package/dist/tools/ask.d.ts +3 -1
- package/dist/tools/diff.cjs +17 -6
- package/dist/tools/diff.cjs.map +1 -1
- package/dist/tools/diff.d.cts +5 -2
- package/dist/tools/diff.d.ts +5 -2
- package/dist/tools/diff.js +17 -6
- package/dist/tools/diff.js.map +1 -1
- package/dist/tools/directories.d.cts +3 -1
- package/dist/tools/directories.d.ts +3 -1
- package/dist/tools/explore.cjs +1778 -204
- package/dist/tools/explore.cjs.map +1 -1
- package/dist/tools/explore.d.cts +82 -2
- package/dist/tools/explore.d.ts +82 -2
- package/dist/tools/explore.js +1780 -204
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/files.cjs +56 -21
- package/dist/tools/files.cjs.map +1 -1
- package/dist/tools/files.d.cts +6 -3
- package/dist/tools/files.d.ts +6 -3
- package/dist/tools/files.js +56 -21
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/git.cjs +34 -25
- package/dist/tools/git.cjs.map +1 -1
- package/dist/tools/git.d.cts +4 -204
- package/dist/tools/git.d.ts +4 -204
- package/dist/tools/git.js +34 -25
- package/dist/tools/git.js.map +1 -1
- package/dist/tools/media.cjs +280 -3
- package/dist/tools/media.cjs.map +1 -1
- package/dist/tools/media.d.cts +3 -1
- package/dist/tools/media.d.ts +3 -1
- package/dist/tools/media.js +278 -1
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/plan.cjs +62 -0
- package/dist/tools/plan.cjs.map +1 -1
- package/dist/tools/plan.d.cts +4 -17
- package/dist/tools/plan.d.ts +4 -17
- package/dist/tools/plan.js +59 -0
- package/dist/tools/plan.js.map +1 -1
- package/dist/tools/search.cjs +3 -0
- package/dist/tools/search.cjs.map +1 -1
- package/dist/tools/search.d.cts +3 -1
- package/dist/tools/search.d.ts +3 -1
- package/dist/tools/search.js +3 -0
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/shell.cjs +76 -11
- package/dist/tools/shell.cjs.map +1 -1
- package/dist/tools/shell.d.cts +5 -39
- package/dist/tools/shell.d.ts +5 -39
- package/dist/tools/shell.js +75 -11
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/todo.d.cts +3 -1
- package/dist/tools/todo.d.ts +3 -1
- package/dist/tools/web.cjs +279 -5
- package/dist/tools/web.cjs.map +1 -1
- package/dist/tools/web.d.cts +3 -1
- package/dist/tools/web.d.ts +3 -1
- package/dist/tools/web.js +275 -3
- package/dist/tools/web.js.map +1 -1
- package/dist/types-BYyXWWPW.d.cts +237 -0
- package/dist/types-BYyXWWPW.d.ts +237 -0
- package/package.json +26 -37
- package/bin/zqagent +0 -2
- package/dist/cli/index.cjs +0 -25218
- package/dist/cli/index.cjs.map +0 -1
- package/dist/cli/index.d.cts +0 -2
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -25201
- package/dist/cli/index.js.map +0 -1
- package/dist/server/index.cjs +0 -20510
- package/dist/server/index.cjs.map +0 -1
- package/dist/server/index.d.cts +0 -2
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +0 -20493
- package/dist/server/index.js.map +0 -1
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/mcp/builtin/index.ts
|
|
31
|
+
var builtin_exports = {};
|
|
32
|
+
__export(builtin_exports, {
|
|
33
|
+
createBuiltinTransport: () => createBuiltinTransport,
|
|
34
|
+
listBuiltinServers: () => listBuiltinServers
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(builtin_exports);
|
|
37
|
+
var import_inMemory = require("@modelcontextprotocol/sdk/inMemory.js");
|
|
38
|
+
|
|
39
|
+
// src/mcp/builtin/ocr.ts
|
|
40
|
+
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
41
|
+
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
42
|
+
|
|
43
|
+
// src/mcp/builtin/ocrEngine.ts
|
|
44
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
45
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
46
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
47
|
+
var import_node_child_process = require("child_process");
|
|
48
|
+
var import_openai = __toESM(require("openai"), 1);
|
|
49
|
+
|
|
50
|
+
// src/tools/shellRuntime.ts
|
|
51
|
+
var path = __toESM(require("path"), 1);
|
|
52
|
+
var WINDOWS_SUFFIXES = [".exe", ".cmd", ".bat", ".com", ""];
|
|
53
|
+
function pathApi(platform) {
|
|
54
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
55
|
+
}
|
|
56
|
+
function joinPath(platform, ...parts) {
|
|
57
|
+
return pathApi(platform).join(...parts);
|
|
58
|
+
}
|
|
59
|
+
function findExecutable(name, ctx) {
|
|
60
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
61
|
+
return ctx.fileExists(name) ? name : null;
|
|
62
|
+
}
|
|
63
|
+
const suffixes = ctx.platform === "win32" ? WINDOWS_SUFFIXES : [""];
|
|
64
|
+
const delimiter = ctx.platform === "win32" ? ";" : ":";
|
|
65
|
+
const dirs = (ctx.env.PATH ?? "").split(delimiter).filter((d) => d.length > 0);
|
|
66
|
+
for (const dir of dirs) {
|
|
67
|
+
for (const suffix of suffixes) {
|
|
68
|
+
const candidate = joinPath(ctx.platform, dir, name + suffix);
|
|
69
|
+
if (ctx.fileExists(candidate)) return candidate;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/mcp/builtin/ocrEngine.ts
|
|
76
|
+
var DEFAULT_MAX_PAGES = 5;
|
|
77
|
+
var MAX_MAX_PAGES = 50;
|
|
78
|
+
var DEFAULT_DPI = 150;
|
|
79
|
+
var MAX_DPI = 400;
|
|
80
|
+
var CMD_TIMEOUT_MS = 12e4;
|
|
81
|
+
var COMPILE_TIMEOUT_MS = 18e4;
|
|
82
|
+
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
83
|
+
var VISION_SOURCE = `import Foundation
|
|
84
|
+
import Vision
|
|
85
|
+
import AppKit
|
|
86
|
+
import PDFKit
|
|
87
|
+
import CoreGraphics
|
|
88
|
+
|
|
89
|
+
struct PageResult: Codable { let page: Int; let text: String }
|
|
90
|
+
struct Output: Codable { let pages: [PageResult] }
|
|
91
|
+
|
|
92
|
+
func recognize(_ image: CGImage) -> String {
|
|
93
|
+
func run(_ langs: [String]?) throws -> [VNRecognizedTextObservation] {
|
|
94
|
+
let request = VNRecognizeTextRequest()
|
|
95
|
+
request.recognitionLevel = .accurate
|
|
96
|
+
request.usesLanguageCorrection = true
|
|
97
|
+
if let langs = langs { request.recognitionLanguages = langs }
|
|
98
|
+
let handler = VNImageRequestHandler(cgImage: image, options: [:])
|
|
99
|
+
try handler.perform([request])
|
|
100
|
+
return request.results ?? []
|
|
101
|
+
}
|
|
102
|
+
let observations = (try? run(["zh-Hans", "zh-Hant", "en-US"])) ?? (try? run(nil)) ?? []
|
|
103
|
+
let lines = observations.compactMap { $0.topCandidates(1).first?.string }
|
|
104
|
+
return lines.joined(separator: "\\n")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
func imageFromFile(_ p: String) -> CGImage? {
|
|
108
|
+
guard let src = CGImageSourceCreateWithURL(URL(fileURLWithPath: p) as CFURL, nil) else { return nil }
|
|
109
|
+
return CGImageSourceCreateImageAtIndex(src, 0, nil)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let args = CommandLine.arguments
|
|
113
|
+
guard args.count >= 2 else {
|
|
114
|
+
FileHandle.standardError.write("usage: ocr-vision <file> [maxPages] [dpi]\\n".data(using: .utf8)!)
|
|
115
|
+
exit(2)
|
|
116
|
+
}
|
|
117
|
+
let file = args[1]
|
|
118
|
+
let maxPages = args.count > 2 ? (Int(args[2]) ?? 5) : 5
|
|
119
|
+
let dpi = args.count > 3 ? (Int(args[3]) ?? 150) : 150
|
|
120
|
+
|
|
121
|
+
var pages: [PageResult] = []
|
|
122
|
+
if file.lowercased().hasSuffix(".pdf"), let doc = PDFDocument(url: URL(fileURLWithPath: file)) {
|
|
123
|
+
let count = min(doc.pageCount, max(1, maxPages))
|
|
124
|
+
let scale = CGFloat(dpi) / 72.0
|
|
125
|
+
for i in 0..<count {
|
|
126
|
+
guard let page = doc.page(at: i) else { continue }
|
|
127
|
+
let bounds = page.bounds(for: .mediaBox)
|
|
128
|
+
let w = Int(bounds.width * scale)
|
|
129
|
+
let h = Int(bounds.height * scale)
|
|
130
|
+
guard w > 0, h > 0 else { continue }
|
|
131
|
+
guard let ctx = CGContext(
|
|
132
|
+
data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: 0,
|
|
133
|
+
space: CGColorSpaceCreateDeviceRGB(),
|
|
134
|
+
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
|
|
135
|
+
) else { continue }
|
|
136
|
+
ctx.setFillColor(CGColor(red: 1, green: 1, blue: 1, alpha: 1))
|
|
137
|
+
ctx.fill(CGRect(x: 0, y: 0, width: w, height: h))
|
|
138
|
+
ctx.scaleBy(x: scale, y: scale)
|
|
139
|
+
page.draw(with: .mediaBox, to: ctx)
|
|
140
|
+
guard let image = ctx.makeImage() else { continue }
|
|
141
|
+
pages.append(PageResult(page: i + 1, text: recognize(image)))
|
|
142
|
+
}
|
|
143
|
+
} else if let image = imageFromFile(file) {
|
|
144
|
+
pages.append(PageResult(page: 1, text: recognize(image)))
|
|
145
|
+
} else {
|
|
146
|
+
FileHandle.standardError.write("unsupported or unreadable image: \\(file)\\n".data(using: .utf8)!)
|
|
147
|
+
exit(3)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let encoder = JSONEncoder()
|
|
151
|
+
encoder.outputFormatting = [.withoutEscapingSlashes]
|
|
152
|
+
if let data = try? encoder.encode(Output(pages: pages)) {
|
|
153
|
+
FileHandle.standardOutput.write(data)
|
|
154
|
+
} else {
|
|
155
|
+
exit(4)
|
|
156
|
+
}
|
|
157
|
+
`;
|
|
158
|
+
function defaultRun(command, args, opts = {}) {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
(0, import_node_child_process.execFile)(
|
|
161
|
+
command,
|
|
162
|
+
args,
|
|
163
|
+
{
|
|
164
|
+
timeout: opts.timeoutMs ?? CMD_TIMEOUT_MS,
|
|
165
|
+
cwd: opts.cwd,
|
|
166
|
+
maxBuffer: MAX_BUFFER,
|
|
167
|
+
encoding: "utf8"
|
|
168
|
+
},
|
|
169
|
+
(err, stdout, stderr) => {
|
|
170
|
+
if (err) {
|
|
171
|
+
const e = err;
|
|
172
|
+
e.message = `${import_node_path.default.basename(command)} \u6267\u884C\u5931\u8D25: ${e.message}${stderr ? `
|
|
173
|
+
${stderr.trim()}` : ""}`;
|
|
174
|
+
reject(e);
|
|
175
|
+
} else {
|
|
176
|
+
resolve({ stdout, stderr });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function makeRuntime(ctx) {
|
|
183
|
+
const overrides = ctx.ocr ?? {};
|
|
184
|
+
const platform = overrides.platform ?? process.platform;
|
|
185
|
+
const env = overrides.env ?? ctx.env ?? process.env;
|
|
186
|
+
const workspace = ctx.workspace ?? env.WORKSPACE ?? process.cwd();
|
|
187
|
+
const fileExists = overrides.fileExists ?? ((p) => {
|
|
188
|
+
try {
|
|
189
|
+
return import_node_fs.default.statSync(p).isFile();
|
|
190
|
+
} catch {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
const which = overrides.which ?? ((name) => findExecutable(name, { platform, env, fileExists }));
|
|
195
|
+
return {
|
|
196
|
+
platform,
|
|
197
|
+
env,
|
|
198
|
+
workspace,
|
|
199
|
+
llm: ctx.llm,
|
|
200
|
+
overrides,
|
|
201
|
+
which,
|
|
202
|
+
run: overrides.run ?? defaultRun,
|
|
203
|
+
fileExists
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function clampInt(value, fallback, min, max) {
|
|
207
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
208
|
+
if (!Number.isFinite(n)) return fallback;
|
|
209
|
+
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
210
|
+
}
|
|
211
|
+
function isPdfFile(file) {
|
|
212
|
+
if (file.toLowerCase().endsWith(".pdf")) return true;
|
|
213
|
+
try {
|
|
214
|
+
const fd = import_node_fs.default.openSync(file, "r");
|
|
215
|
+
try {
|
|
216
|
+
const buf = Buffer.alloc(5);
|
|
217
|
+
const read = import_node_fs.default.readSync(fd, buf, 0, 5, 0);
|
|
218
|
+
return read >= 5 && buf.toString("latin1") === "%PDF-";
|
|
219
|
+
} finally {
|
|
220
|
+
import_node_fs.default.closeSync(fd);
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function detectMime(file) {
|
|
227
|
+
try {
|
|
228
|
+
const fd = import_node_fs.default.openSync(file, "r");
|
|
229
|
+
try {
|
|
230
|
+
const buf = Buffer.alloc(12);
|
|
231
|
+
import_node_fs.default.readSync(fd, buf, 0, 12, 0);
|
|
232
|
+
if (buf[0] === 137 && buf[1] === 80) return "image/png";
|
|
233
|
+
if (buf[0] === 255 && buf[1] === 216) return "image/jpeg";
|
|
234
|
+
if (buf.toString("latin1", 0, 4) === "RIFF") return "image/webp";
|
|
235
|
+
if (buf.toString("latin1", 0, 4) === "GIF8") return "image/gif";
|
|
236
|
+
} finally {
|
|
237
|
+
import_node_fs.default.closeSync(fd);
|
|
238
|
+
}
|
|
239
|
+
} catch {
|
|
240
|
+
}
|
|
241
|
+
const ext = import_node_path.default.extname(file).toLowerCase();
|
|
242
|
+
if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
|
|
243
|
+
if (ext === ".webp") return "image/webp";
|
|
244
|
+
if (ext === ".gif") return "image/gif";
|
|
245
|
+
return "image/png";
|
|
246
|
+
}
|
|
247
|
+
function toDataUrl(file) {
|
|
248
|
+
return `data:${detectMime(file)};base64,${import_node_fs.default.readFileSync(file).toString("base64")}`;
|
|
249
|
+
}
|
|
250
|
+
function dataUrlToBuffer(value) {
|
|
251
|
+
const m = /^data:([^;,]+);base64,([\s\S]*)$/.exec(value.trim());
|
|
252
|
+
const mime = m?.[1] ?? "image/png";
|
|
253
|
+
const b64 = m?.[2] ?? value.trim();
|
|
254
|
+
const ext = mime === "image/jpeg" ? ".jpg" : mime === "image/webp" ? ".webp" : mime === "image/gif" ? ".gif" : mime === "application/pdf" ? ".pdf" : ".png";
|
|
255
|
+
return { buffer: Buffer.from(b64, "base64"), ext };
|
|
256
|
+
}
|
|
257
|
+
function naturalCompare(a, b) {
|
|
258
|
+
return a.localeCompare(b, void 0, { numeric: true });
|
|
259
|
+
}
|
|
260
|
+
async function downloadToFile(url, dest, runtime) {
|
|
261
|
+
const fetchImpl = runtime.overrides.fetchImpl ?? globalThis.fetch;
|
|
262
|
+
if (!fetchImpl) throw new Error("\u5F53\u524D\u8FD0\u884C\u65F6\u4E0D\u652F\u6301 fetch\uFF0C\u65E0\u6CD5\u4E0B\u8F7D imageUrl");
|
|
263
|
+
const res = await fetchImpl(url);
|
|
264
|
+
if (!res.ok) throw new Error(`\u4E0B\u8F7D\u56FE\u7247\u5931\u8D25\uFF1AHTTP ${res.status}`);
|
|
265
|
+
import_node_fs.default.writeFileSync(dest, Buffer.from(await res.arrayBuffer()));
|
|
266
|
+
}
|
|
267
|
+
async function materializeInput(input, runtime) {
|
|
268
|
+
const root = runtime.overrides.tmpDir ?? import_node_os.default.tmpdir();
|
|
269
|
+
const tmpDir = import_node_fs.default.mkdtempSync(import_node_path.default.join(root, "zqagent-ocr-"));
|
|
270
|
+
const cleanup = () => {
|
|
271
|
+
try {
|
|
272
|
+
import_node_fs.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
try {
|
|
277
|
+
if (typeof input.imagePath === "string" && input.imagePath.trim()) {
|
|
278
|
+
const file = import_node_path.default.isAbsolute(input.imagePath) ? input.imagePath : import_node_path.default.resolve(runtime.workspace, input.imagePath);
|
|
279
|
+
if (!runtime.fileExists(file) && !import_node_fs.default.existsSync(file))
|
|
280
|
+
throw new Error(`\u56FE\u7247\u4E0D\u5B58\u5728\uFF1A${file}`);
|
|
281
|
+
return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
|
|
282
|
+
}
|
|
283
|
+
if (typeof input.imageBase64 === "string" && input.imageBase64.trim()) {
|
|
284
|
+
const { buffer, ext } = dataUrlToBuffer(input.imageBase64);
|
|
285
|
+
const file = import_node_path.default.join(tmpDir, `input${ext}`);
|
|
286
|
+
import_node_fs.default.writeFileSync(file, buffer);
|
|
287
|
+
return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
|
|
288
|
+
}
|
|
289
|
+
if (typeof input.imageUrl === "string" && input.imageUrl.trim()) {
|
|
290
|
+
const url = input.imageUrl.trim();
|
|
291
|
+
const ext = import_node_path.default.extname(new URL(url).pathname).toLowerCase() || ".png";
|
|
292
|
+
const file = import_node_path.default.join(tmpDir, `input${ext}`);
|
|
293
|
+
await downloadToFile(url, file, runtime);
|
|
294
|
+
return { file, isPdf: isPdfFile(file), tmpDir, cleanup };
|
|
295
|
+
}
|
|
296
|
+
throw new Error("\u7F3A\u5C11\u8F93\u5165\uFF1A\u8BF7\u63D0\u4F9B imagePath / imageBase64 / imageUrl \u4E4B\u4E00");
|
|
297
|
+
} catch (err) {
|
|
298
|
+
cleanup();
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function pdfToImages(file, tmpDir, input, runtime) {
|
|
303
|
+
const pdftoppm = runtime.which("pdftoppm");
|
|
304
|
+
if (!pdftoppm) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"PDF \u9700\u8981 poppler \u7684 pdftoppm\uFF08macOS \u53EF\u4F7F\u7528\u5185\u7F6E Vision \u5F15\u64CE\uFF0C\u65E0\u9700\u8BE5\u4F9D\u8D56\uFF09"
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
const pagesDir = import_node_path.default.join(tmpDir, "pages");
|
|
310
|
+
import_node_fs.default.mkdirSync(pagesDir, { recursive: true });
|
|
311
|
+
const maxPages = clampInt(
|
|
312
|
+
input.maxPages,
|
|
313
|
+
DEFAULT_MAX_PAGES,
|
|
314
|
+
1,
|
|
315
|
+
MAX_MAX_PAGES
|
|
316
|
+
);
|
|
317
|
+
const dpi = clampInt(input.dpi, DEFAULT_DPI, 36, MAX_DPI);
|
|
318
|
+
await runtime.run(
|
|
319
|
+
pdftoppm,
|
|
320
|
+
[
|
|
321
|
+
"-r",
|
|
322
|
+
String(dpi),
|
|
323
|
+
"-png",
|
|
324
|
+
"-f",
|
|
325
|
+
"1",
|
|
326
|
+
"-l",
|
|
327
|
+
String(maxPages),
|
|
328
|
+
file,
|
|
329
|
+
import_node_path.default.join(pagesDir, "page")
|
|
330
|
+
],
|
|
331
|
+
{ timeoutMs: CMD_TIMEOUT_MS }
|
|
332
|
+
);
|
|
333
|
+
const images = import_node_fs.default.readdirSync(pagesDir).filter((f) => /^page.*\.png$/i.test(f)).sort(naturalCompare).map((f) => import_node_path.default.join(pagesDir, f));
|
|
334
|
+
if (images.length === 0) throw new Error("PDF \u8F6C\u56FE\u7247\u5931\u8D25\uFF08\u672A\u751F\u6210\u9875\u9762\uFF09");
|
|
335
|
+
return images;
|
|
336
|
+
}
|
|
337
|
+
var visionBuilds = /* @__PURE__ */ new Map();
|
|
338
|
+
function conciseError(err) {
|
|
339
|
+
const lines = err.message.split("\n").map((l) => l.trim()).filter((l) => /error:|fatal error:/i.test(l));
|
|
340
|
+
const pick = lines.length > 0 ? lines[lines.length - 1] : err.message;
|
|
341
|
+
return pick.slice(0, 500);
|
|
342
|
+
}
|
|
343
|
+
async function ensureVisionBinary(runtime) {
|
|
344
|
+
if (runtime.platform !== "darwin")
|
|
345
|
+
return { binary: null, error: "\u4EC5 macOS \u53EF\u7528" };
|
|
346
|
+
const swiftc = runtime.which("swiftc");
|
|
347
|
+
if (!swiftc)
|
|
348
|
+
return {
|
|
349
|
+
binary: null,
|
|
350
|
+
error: "\u672A\u627E\u5230 swiftc\uFF08\u9700\u8981 Xcode Command Line Tools\uFF09"
|
|
351
|
+
};
|
|
352
|
+
const dir = import_node_path.default.join(runtime.workspace, ".agent", "bin");
|
|
353
|
+
const srcPath = import_node_path.default.join(dir, "ocr-vision.swift");
|
|
354
|
+
const binPath = import_node_path.default.join(dir, "ocr-vision");
|
|
355
|
+
const cacheKey = binPath;
|
|
356
|
+
const cached = visionBuilds.get(cacheKey);
|
|
357
|
+
if (cached) return cached;
|
|
358
|
+
const build = (async () => {
|
|
359
|
+
try {
|
|
360
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
361
|
+
let changed = true;
|
|
362
|
+
try {
|
|
363
|
+
changed = import_node_fs.default.readFileSync(srcPath, "utf8") !== VISION_SOURCE;
|
|
364
|
+
} catch {
|
|
365
|
+
changed = true;
|
|
366
|
+
}
|
|
367
|
+
if (changed) import_node_fs.default.writeFileSync(srcPath, VISION_SOURCE, "utf8");
|
|
368
|
+
if (changed || !runtime.fileExists(binPath)) {
|
|
369
|
+
await runtime.run(swiftc, ["-O", "-o", binPath, srcPath], {
|
|
370
|
+
timeoutMs: COMPILE_TIMEOUT_MS
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return runtime.fileExists(binPath) ? { binary: binPath } : { binary: null, error: "Vision \u7F16\u8BD1\u672A\u751F\u6210\u53EF\u6267\u884C\u6587\u4EF6" };
|
|
374
|
+
} catch (err) {
|
|
375
|
+
return { binary: null, error: `Vision \u7F16\u8BD1\u5931\u8D25: ${conciseError(err)}` };
|
|
376
|
+
}
|
|
377
|
+
})();
|
|
378
|
+
visionBuilds.set(cacheKey, build);
|
|
379
|
+
return build;
|
|
380
|
+
}
|
|
381
|
+
async function runVision(binary, file, input, runtime) {
|
|
382
|
+
const maxPages = clampInt(
|
|
383
|
+
input.maxPages,
|
|
384
|
+
DEFAULT_MAX_PAGES,
|
|
385
|
+
1,
|
|
386
|
+
MAX_MAX_PAGES
|
|
387
|
+
);
|
|
388
|
+
const dpi = clampInt(input.dpi, DEFAULT_DPI, 36, MAX_DPI);
|
|
389
|
+
const { stdout } = await runtime.run(
|
|
390
|
+
binary,
|
|
391
|
+
[file, String(maxPages), String(dpi)],
|
|
392
|
+
{ timeoutMs: CMD_TIMEOUT_MS }
|
|
393
|
+
);
|
|
394
|
+
const parsed = JSON.parse(stdout);
|
|
395
|
+
const pages = Array.isArray(parsed.pages) ? parsed.pages : [];
|
|
396
|
+
if (pages.length === 0) throw new Error("Vision \u672A\u8FD4\u56DE\u8BC6\u522B\u7ED3\u679C");
|
|
397
|
+
return pages.map((p) => ({
|
|
398
|
+
page: Number(p.page) || 1,
|
|
399
|
+
text: typeof p.text === "string" ? p.text : ""
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
async function runTesseract(file, isPdf, input, runtime, tmpDir) {
|
|
403
|
+
const tesseract = runtime.which("tesseract");
|
|
404
|
+
if (!tesseract) throw new Error("\u672A\u627E\u5230 tesseract");
|
|
405
|
+
const lang = input.lang ?? runtime.env.OCR_LANG ?? "chi_sim+eng";
|
|
406
|
+
const images = isPdf ? await pdfToImages(file, tmpDir, input, runtime) : [file];
|
|
407
|
+
const pages = [];
|
|
408
|
+
for (let i = 0; i < images.length; i += 1) {
|
|
409
|
+
const { stdout } = await runtime.run(
|
|
410
|
+
tesseract,
|
|
411
|
+
[images[i], "stdout", "-l", lang, "--psm", "3"],
|
|
412
|
+
{ timeoutMs: CMD_TIMEOUT_MS }
|
|
413
|
+
);
|
|
414
|
+
pages.push({ page: i + 1, text: stdout.trim() });
|
|
415
|
+
}
|
|
416
|
+
return pages;
|
|
417
|
+
}
|
|
418
|
+
function resolveLlmConfig(runtime) {
|
|
419
|
+
const llm = runtime.llm;
|
|
420
|
+
const apiKey = llm?.apiKey ?? runtime.env.OPENAI_API_KEY ?? runtime.env.OCR_API_KEY ?? "";
|
|
421
|
+
const model = llm?.model ?? runtime.env.OCR_MODEL ?? runtime.env.OPENAI_MODEL ?? "";
|
|
422
|
+
const baseURL = llm?.baseURL ?? runtime.env.OPENAI_BASE_URL ?? runtime.env.OCR_BASE_URL;
|
|
423
|
+
if (!apiKey || !model) return null;
|
|
424
|
+
return { apiKey, model, baseURL };
|
|
425
|
+
}
|
|
426
|
+
async function defaultLlmComplete(req) {
|
|
427
|
+
const client = new import_openai.default({
|
|
428
|
+
apiKey: req.apiKey ?? "",
|
|
429
|
+
...req.baseURL ? { baseURL: req.baseURL } : {}
|
|
430
|
+
});
|
|
431
|
+
const res = await client.chat.completions.create({
|
|
432
|
+
model: req.model,
|
|
433
|
+
messages: [
|
|
434
|
+
{
|
|
435
|
+
role: "user",
|
|
436
|
+
content: [
|
|
437
|
+
{ type: "text", text: req.prompt },
|
|
438
|
+
{ type: "image_url", image_url: { url: req.imageDataUrl } }
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
});
|
|
443
|
+
return res.choices?.[0]?.message?.content ?? "";
|
|
444
|
+
}
|
|
445
|
+
async function runLlm(file, isPdf, input, runtime, tmpDir) {
|
|
446
|
+
const cfg = resolveLlmConfig(runtime);
|
|
447
|
+
if (!cfg) {
|
|
448
|
+
throw new Error("\u672A\u914D\u7F6E\u591A\u6A21\u6001\u6A21\u578B\uFF08\u7F3A\u5C11 API key \u6216 model\uFF09");
|
|
449
|
+
}
|
|
450
|
+
const images = isPdf ? await pdfToImages(file, tmpDir, input, runtime) : [file];
|
|
451
|
+
const prompt = "\u8BF7\u9010\u5B57\u63D0\u53D6\u8FD9\u5F20\u56FE\u7247\u4E2D\u7684\u5168\u90E8\u6587\u5B57\uFF0C\u4FDD\u6301\u539F\u6709\u6362\u884C\u4E0E\u987A\u5E8F\u3002\u53EA\u8F93\u51FA\u6587\u5B57\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002";
|
|
452
|
+
const complete = runtime.overrides.llmComplete ?? defaultLlmComplete;
|
|
453
|
+
const pages = [];
|
|
454
|
+
for (let i = 0; i < images.length; i += 1) {
|
|
455
|
+
const text = await complete({
|
|
456
|
+
model: cfg.model,
|
|
457
|
+
prompt,
|
|
458
|
+
imageDataUrl: toDataUrl(images[i]),
|
|
459
|
+
baseURL: cfg.baseURL,
|
|
460
|
+
apiKey: cfg.apiKey
|
|
461
|
+
});
|
|
462
|
+
pages.push({ page: i + 1, text: text.trim() });
|
|
463
|
+
}
|
|
464
|
+
return pages;
|
|
465
|
+
}
|
|
466
|
+
function joinPages(pages) {
|
|
467
|
+
if (pages.length === 1) return pages[0].text;
|
|
468
|
+
return pages.map((p) => `--- page ${p.page} ---
|
|
469
|
+
${p.text}`).join("\n\n");
|
|
470
|
+
}
|
|
471
|
+
function howToFix(platform) {
|
|
472
|
+
if (platform === "darwin")
|
|
473
|
+
return [
|
|
474
|
+
"macOS \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
|
|
475
|
+
"1) \u5B89\u88C5 Xcode Command Line Tools \u4EE5\u542F\u7528\u5185\u7F6E Vision\uFF1Axcode-select --install",
|
|
476
|
+
"2) \u5B89\u88C5 tesseract \u4E0E poppler\uFF1Abrew install tesseract tesseract-lang poppler",
|
|
477
|
+
"3) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
|
|
478
|
+
].join("\n");
|
|
479
|
+
if (platform === "win32")
|
|
480
|
+
return [
|
|
481
|
+
"Windows \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
|
|
482
|
+
"1) \u5B89\u88C5 tesseract\uFF1Awinget install UB-Mannheim.TesseractOCR",
|
|
483
|
+
"2) \u5B89\u88C5 poppler\uFF08PDF \u9700\u8981\uFF09\u5E76\u52A0\u5165 PATH",
|
|
484
|
+
"3) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
|
|
485
|
+
].join("\n");
|
|
486
|
+
return [
|
|
487
|
+
"Linux \u53EF\u4EFB\u9009\u5176\u4E00\uFF1A",
|
|
488
|
+
"1) apt-get install -y tesseract-ocr tesseract-ocr-chi-sim poppler-utils",
|
|
489
|
+
"2) \u7528 /connect \u914D\u7F6E\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u591A\u6A21\u6001\u6A21\u578B\u540E\u91CD\u8BD5"
|
|
490
|
+
].join("\n");
|
|
491
|
+
}
|
|
492
|
+
function engineOrder(runtime) {
|
|
493
|
+
const forced = (runtime.env.OCR_ENGINE ?? "").toLowerCase();
|
|
494
|
+
if (forced === "vision" || forced === "tesseract" || forced === "llm")
|
|
495
|
+
return [forced];
|
|
496
|
+
return ["vision", "tesseract", "llm"];
|
|
497
|
+
}
|
|
498
|
+
async function recognizeOcr(input, ctx = {}) {
|
|
499
|
+
const runtime = makeRuntime(ctx);
|
|
500
|
+
let materialized;
|
|
501
|
+
try {
|
|
502
|
+
materialized = await materializeInput(input, runtime);
|
|
503
|
+
} catch (err) {
|
|
504
|
+
return {
|
|
505
|
+
ok: false,
|
|
506
|
+
error: err.message,
|
|
507
|
+
how_to_fix: howToFix(runtime.platform),
|
|
508
|
+
attempts: []
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const attempts = [];
|
|
512
|
+
try {
|
|
513
|
+
for (const engine of engineOrder(runtime)) {
|
|
514
|
+
try {
|
|
515
|
+
let pages;
|
|
516
|
+
if (engine === "vision") {
|
|
517
|
+
const build = await ensureVisionBinary(runtime);
|
|
518
|
+
if (!build.binary) {
|
|
519
|
+
attempts.push({ engine, error: build.error ?? "\u4E0D\u53EF\u7528" });
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
pages = await runVision(
|
|
523
|
+
build.binary,
|
|
524
|
+
materialized.file,
|
|
525
|
+
input,
|
|
526
|
+
runtime
|
|
527
|
+
);
|
|
528
|
+
} else if (engine === "tesseract") {
|
|
529
|
+
pages = await runTesseract(
|
|
530
|
+
materialized.file,
|
|
531
|
+
materialized.isPdf,
|
|
532
|
+
input,
|
|
533
|
+
runtime,
|
|
534
|
+
materialized.tmpDir
|
|
535
|
+
);
|
|
536
|
+
} else {
|
|
537
|
+
pages = await runLlm(
|
|
538
|
+
materialized.file,
|
|
539
|
+
materialized.isPdf,
|
|
540
|
+
input,
|
|
541
|
+
runtime,
|
|
542
|
+
materialized.tmpDir
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
if (pages.length === 0) throw new Error("\u672A\u8BC6\u522B\u5230\u4EFB\u4F55\u9875\u9762");
|
|
546
|
+
return {
|
|
547
|
+
ok: true,
|
|
548
|
+
text: joinPages(pages),
|
|
549
|
+
engine,
|
|
550
|
+
pages
|
|
551
|
+
};
|
|
552
|
+
} catch (err) {
|
|
553
|
+
attempts.push({ engine, error: err.message });
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
ok: false,
|
|
558
|
+
error: attempts.length > 0 ? `\u6CA1\u6709\u53EF\u7528\u7684 OCR \u5F15\u64CE: ${attempts.map((a) => `${a.engine}: ${a.error}`).join("; ")}` : "\u6CA1\u6709\u53EF\u7528\u7684 OCR \u5F15\u64CE",
|
|
559
|
+
how_to_fix: howToFix(runtime.platform),
|
|
560
|
+
attempts
|
|
561
|
+
};
|
|
562
|
+
} finally {
|
|
563
|
+
materialized.cleanup();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/mcp/builtin/ocr.ts
|
|
568
|
+
var TOOL_NAME = "recognize";
|
|
569
|
+
var TOOL_DESCRIPTION = [
|
|
570
|
+
"\u4ECE\u56FE\u7247\u3001\u626B\u63CF\u4EF6\u6216 PDF \u4E2D\u63D0\u53D6\u6587\u5B57\uFF08OCR\uFF09\u3002",
|
|
571
|
+
"\u4F18\u5148\u4F20 imagePath\uFF08\u5DE5\u4F5C\u533A\u5185\u7684\u6587\u4EF6\u8DEF\u5F84\uFF09\uFF0C\u4E5F\u652F\u6301 imageBase64\uFF08\u53EF\u5E26 data URL \u524D\u7F00\uFF09\u6216 imageUrl\u3002",
|
|
572
|
+
"\u4F20\u5165 PDF \u4F1A\u9010\u9875\u8BC6\u522B\uFF08maxPages \u9ED8\u8BA4 5\uFF0Cdpi \u9ED8\u8BA4 150\uFF09\u3002",
|
|
573
|
+
"\u8BC6\u522B\u5F15\u64CE\u81EA\u52A8\u9009\u62E9\uFF1AmacOS Vision / tesseract+pdftoppm / \u5DF2\u914D\u7F6E\u7684\u591A\u6A21\u6001\u6A21\u578B\u3002"
|
|
574
|
+
].join("\n");
|
|
575
|
+
var INPUT_SCHEMA = {
|
|
576
|
+
type: "object",
|
|
577
|
+
properties: {
|
|
578
|
+
imagePath: {
|
|
579
|
+
type: "string",
|
|
580
|
+
description: "\u672C\u5730\u56FE\u7247\u6216 PDF \u8DEF\u5F84\uFF08\u76F8\u5BF9\u8DEF\u5F84\u6309\u5DE5\u4F5C\u533A\u89E3\u6790\uFF09"
|
|
581
|
+
},
|
|
582
|
+
imageBase64: {
|
|
583
|
+
type: "string",
|
|
584
|
+
description: "\u56FE\u7247\u7684 base64 \u7F16\u7801\uFF08\u53EF\u5E26 data URL \u524D\u7F00\uFF09"
|
|
585
|
+
},
|
|
586
|
+
imageUrl: {
|
|
587
|
+
type: "string",
|
|
588
|
+
description: "\u8FDC\u7A0B\u56FE\u7247\u6216 PDF \u7684 URL"
|
|
589
|
+
},
|
|
590
|
+
maxPages: {
|
|
591
|
+
type: "number",
|
|
592
|
+
description: "PDF \u6700\u591A\u8BC6\u522B\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 50\uFF09"
|
|
593
|
+
},
|
|
594
|
+
dpi: {
|
|
595
|
+
type: "number",
|
|
596
|
+
description: "PDF \u6E32\u67D3 DPI\uFF08\u9ED8\u8BA4 150\uFF0C\u4E0A\u9650 400\uFF09"
|
|
597
|
+
},
|
|
598
|
+
lang: {
|
|
599
|
+
type: "string",
|
|
600
|
+
description: "tesseract \u8BED\u8A00\u5305\uFF08\u9ED8\u8BA4 chi_sim+eng\uFF09"
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
function createOcrServer(ctx = {}) {
|
|
605
|
+
const server = new import_server.Server(
|
|
606
|
+
{ name: "zqagent-ocr", version: "0.1.0" },
|
|
607
|
+
{ capabilities: { tools: {} } }
|
|
608
|
+
);
|
|
609
|
+
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({
|
|
610
|
+
tools: [
|
|
611
|
+
{
|
|
612
|
+
name: TOOL_NAME,
|
|
613
|
+
description: TOOL_DESCRIPTION,
|
|
614
|
+
inputSchema: INPUT_SCHEMA
|
|
615
|
+
}
|
|
616
|
+
]
|
|
617
|
+
}));
|
|
618
|
+
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
619
|
+
if (request.params.name !== TOOL_NAME) {
|
|
620
|
+
return {
|
|
621
|
+
content: [
|
|
622
|
+
{
|
|
623
|
+
type: "text",
|
|
624
|
+
text: JSON.stringify({
|
|
625
|
+
error: `\u672A\u77E5\u5DE5\u5177 "${request.params.name}"\uFF0C\u53EF\u7528\u5DE5\u5177\uFF1A${TOOL_NAME}`
|
|
626
|
+
})
|
|
627
|
+
}
|
|
628
|
+
],
|
|
629
|
+
isError: true
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
const args = request.params.arguments ?? {};
|
|
633
|
+
const result = await recognizeOcr(args, ctx);
|
|
634
|
+
if (!result.ok) {
|
|
635
|
+
return {
|
|
636
|
+
content: [
|
|
637
|
+
{
|
|
638
|
+
type: "text",
|
|
639
|
+
text: JSON.stringify(
|
|
640
|
+
{
|
|
641
|
+
error: result.error,
|
|
642
|
+
how_to_fix: result.how_to_fix,
|
|
643
|
+
attempts: result.attempts
|
|
644
|
+
},
|
|
645
|
+
null,
|
|
646
|
+
2
|
|
647
|
+
)
|
|
648
|
+
}
|
|
649
|
+
],
|
|
650
|
+
isError: true
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
return {
|
|
654
|
+
content: [{ type: "text", text: result.text }]
|
|
655
|
+
};
|
|
656
|
+
});
|
|
657
|
+
return server;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/mcp/builtin/index.ts
|
|
661
|
+
var FACTORIES = {
|
|
662
|
+
ocr: createOcrServer
|
|
663
|
+
};
|
|
664
|
+
function listBuiltinServers() {
|
|
665
|
+
return Object.keys(FACTORIES);
|
|
666
|
+
}
|
|
667
|
+
async function createBuiltinTransport(config, ctx) {
|
|
668
|
+
const id = config.builtin ?? config.name;
|
|
669
|
+
const factory = FACTORIES[id];
|
|
670
|
+
if (!factory) {
|
|
671
|
+
throw new Error(
|
|
672
|
+
`\u672A\u77E5\u7684\u5185\u7F6E MCP server "${id}"\uFF08\u53EF\u7528: ${listBuiltinServers().join(", ")}\uFF09`
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
const [clientTransport, serverTransport] = import_inMemory.InMemoryTransport.createLinkedPair();
|
|
676
|
+
const server = factory(ctx);
|
|
677
|
+
await server.connect(serverTransport);
|
|
678
|
+
return clientTransport;
|
|
679
|
+
}
|
|
680
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
681
|
+
0 && (module.exports = {
|
|
682
|
+
createBuiltinTransport,
|
|
683
|
+
listBuiltinServers
|
|
684
|
+
});
|
|
685
|
+
//# sourceMappingURL=index.cjs.map
|