image-vision-mcp 1.0.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 +21 -0
- package/README.md +252 -0
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/imageProxy.d.ts +1 -0
- package/dist/proxy/imageProxy.js +346 -0
- package/dist/proxy/imageProxy.js.map +1 -0
- package/dist/schemas.d.ts +26 -0
- package/dist/schemas.js +32 -0
- package/dist/schemas.js.map +1 -0
- package/dist/services/clipboard.d.ts +16 -0
- package/dist/services/clipboard.js +196 -0
- package/dist/services/clipboard.js.map +1 -0
- package/dist/services/image.d.ts +19 -0
- package/dist/services/image.js +216 -0
- package/dist/services/image.js.map +1 -0
- package/dist/services/moonshot.d.ts +9 -0
- package/dist/services/moonshot.js +71 -0
- package/dist/services/moonshot.js.map +1 -0
- package/dist/tools/describeClipboard.d.ts +2 -0
- package/dist/tools/describeClipboard.js +106 -0
- package/dist/tools/describeClipboard.js.map +1 -0
- package/dist/tools/describeImage.d.ts +2 -0
- package/dist/tools/describeImage.js +105 -0
- package/dist/tools/describeImage.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import http from "http";
|
|
2
|
+
import https from "https";
|
|
3
|
+
import { URL } from "url";
|
|
4
|
+
import zlib from "zlib";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import os from "os";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
import { callMoonshot } from "../services/moonshot.js";
|
|
10
|
+
// ────────────────────── 日志 ──────────────────────
|
|
11
|
+
// 日志文件路径:优先用环境变量,否则放系统临时目录(跨平台、无需权限处理)
|
|
12
|
+
const LOG_FILE = process.env.VISION_MCP_LOG_FILE ||
|
|
13
|
+
path.join(os.tmpdir(), "vision-mcp-proxy.log");
|
|
14
|
+
const LOG_MAX_SIZE = 10 * 1024 * 1024; // 10MB,超过后清空旧日志
|
|
15
|
+
function log(msg) {
|
|
16
|
+
const line = `[${new Date().toISOString()}] ${msg}\n`;
|
|
17
|
+
console.error(line.trim());
|
|
18
|
+
fs.stat(LOG_FILE, (statErr, stats) => {
|
|
19
|
+
if (statErr || stats.size < LOG_MAX_SIZE) {
|
|
20
|
+
fs.appendFile(LOG_FILE, line, () => { });
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// 超过大小限制,覆盖写入(保留最近日志,丢弃旧的)
|
|
24
|
+
fs.writeFile(LOG_FILE, line, () => { });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// ────────────────────── 配置 ──────────────────────
|
|
29
|
+
// 代理监听端口:从 ANTHROPIC_BASE_URL 解析,与 Claude Code 端保持一致
|
|
30
|
+
// 没设 ANTHROPIC_BASE_URL 时用默认 8787(纯 MCP 工具模式,代理无人连接)
|
|
31
|
+
function getProxyPort() {
|
|
32
|
+
const baseUrl = process.env.ANTHROPIC_BASE_URL;
|
|
33
|
+
if (baseUrl) {
|
|
34
|
+
try {
|
|
35
|
+
const port = new URL(baseUrl).port;
|
|
36
|
+
if (port)
|
|
37
|
+
return parseInt(port, 10);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// 忽略解析错误,回退到默认
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return 8787;
|
|
44
|
+
}
|
|
45
|
+
const PROXY_PORT = getProxyPort();
|
|
46
|
+
// 代理转发目标:用户必须设置 UPSTREAM_BASE_URL,否则代理功能不可用(MCP 工具仍可用)
|
|
47
|
+
const UPSTREAM_BASE_URL = process.env.UPSTREAM_BASE_URL || "";
|
|
48
|
+
const UPSTREAM_AUTH_TOKEN = process.env.UPSTREAM_AUTH_TOKEN ||
|
|
49
|
+
process.env.ANTHROPIC_AUTH_TOKEN ||
|
|
50
|
+
"";
|
|
51
|
+
const IMAGE_DESC_PROMPT = process.env.IMAGE_DESC_PROMPT ||
|
|
52
|
+
"请详细描述这张图片的内容。如果是图表/截图,请提取关键信息;如果包含文字,请提取文字内容;如果是 UI 界面,请描述界面元素和布局。描述要简洁准确。";
|
|
53
|
+
// ────────────────────── 图片识别 ──────────────────────
|
|
54
|
+
async function describeImage(base64Data, mimeType) {
|
|
55
|
+
const dataUrl = `data:${mimeType};base64,${base64Data}`;
|
|
56
|
+
const apiKey = process.env.MOONSHOT_API_KEY || "";
|
|
57
|
+
if (!apiKey) {
|
|
58
|
+
throw new Error("MOONSHOT_API_KEY 未设置");
|
|
59
|
+
}
|
|
60
|
+
const response = await callMoonshot({
|
|
61
|
+
apiKey,
|
|
62
|
+
messages: [
|
|
63
|
+
{
|
|
64
|
+
role: "user",
|
|
65
|
+
content: [
|
|
66
|
+
{ type: "image_url", image_url: { url: dataUrl } },
|
|
67
|
+
{ type: "text", text: IMAGE_DESC_PROMPT },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
maxTokens: 2048,
|
|
72
|
+
});
|
|
73
|
+
const description = response.choices?.[0]?.message?.content || "";
|
|
74
|
+
if (!description) {
|
|
75
|
+
throw new Error("Moonshot API 返回空内容");
|
|
76
|
+
}
|
|
77
|
+
return description;
|
|
78
|
+
}
|
|
79
|
+
async function processContent(content) {
|
|
80
|
+
if (typeof content === "string")
|
|
81
|
+
return content;
|
|
82
|
+
if (!Array.isArray(content))
|
|
83
|
+
return content;
|
|
84
|
+
// 日志:记录所有 block 类型,方便排查
|
|
85
|
+
const blockTypes = content.map((b) => b?.type || "unknown");
|
|
86
|
+
log(`[image-proxy] content blocks: ${JSON.stringify(blockTypes)}`);
|
|
87
|
+
const newContent = [];
|
|
88
|
+
for (const block of content) {
|
|
89
|
+
// 格式1: Anthropic 标准 {"type":"image","source":{"type":"base64",...}}
|
|
90
|
+
if (block?.type === "image" && block.source?.type === "base64") {
|
|
91
|
+
const { media_type, data } = block.source;
|
|
92
|
+
try {
|
|
93
|
+
const description = await describeImage(data, media_type);
|
|
94
|
+
newContent.push({
|
|
95
|
+
type: "text",
|
|
96
|
+
text: `[以下是用户粘贴的图片内容描述]\n${description}\n[图片描述结束]`,
|
|
97
|
+
});
|
|
98
|
+
log(`[image-proxy] 图片已识别 (${media_type}, ${Math.round((data.length * 0.75) / 1024)} KB)`);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
log(`[image-proxy] 图片识别失败: ${err.message}`);
|
|
102
|
+
newContent.push({
|
|
103
|
+
type: "text",
|
|
104
|
+
text: `[图片识别失败: ${err.message}]`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 格式2: OpenAI 风格 {"type":"image_url","image_url":{"url":"data:image/png;base64,..."}}
|
|
109
|
+
else if (block?.type === "image_url" &&
|
|
110
|
+
block.image_url?.url?.startsWith("data:image")) {
|
|
111
|
+
const url = block.image_url.url;
|
|
112
|
+
const match = url.match(/^data:(image\/[a-z+]+);base64,(.+)$/i);
|
|
113
|
+
if (match) {
|
|
114
|
+
const [, media_type, data] = match;
|
|
115
|
+
try {
|
|
116
|
+
const description = await describeImage(data, media_type);
|
|
117
|
+
newContent.push({
|
|
118
|
+
type: "text",
|
|
119
|
+
text: `[以下是截图内容描述]\n${description}\n[图片描述结束]`,
|
|
120
|
+
});
|
|
121
|
+
log(`[image-proxy] image_url 图片已识别 (${media_type})`);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
log(`[image-proxy] image_url 图片识别失败: ${err.message}`);
|
|
125
|
+
newContent.push({
|
|
126
|
+
type: "text",
|
|
127
|
+
text: `[图片识别失败: ${err.message}]`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
newContent.push(block);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// 格式3: tool_result 里嵌套图片(MCP 工具返回的截图)
|
|
136
|
+
else if (block?.type === "tool_result" && Array.isArray(block.content)) {
|
|
137
|
+
const toolContent = block.content;
|
|
138
|
+
const processed = await processContent(toolContent);
|
|
139
|
+
newContent.push({ ...block, content: processed });
|
|
140
|
+
}
|
|
141
|
+
else if (block?.type === "image" && block.source && !block.source.type?.startsWith("base64")) {
|
|
142
|
+
log(`[image-proxy] 未识别的 image source type: ${block.source.type}`);
|
|
143
|
+
newContent.push(block);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
newContent.push(block);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return newContent;
|
|
150
|
+
}
|
|
151
|
+
async function processMessages(messages) {
|
|
152
|
+
if (!Array.isArray(messages))
|
|
153
|
+
return messages;
|
|
154
|
+
for (const message of messages) {
|
|
155
|
+
if (message && typeof message === "object" && message.content !== undefined) {
|
|
156
|
+
message.content = await processContent(message.content);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return messages;
|
|
160
|
+
}
|
|
161
|
+
// ────────────────────── 转发请求 ──────────────────────
|
|
162
|
+
function forwardRequest(req, res, body) {
|
|
163
|
+
const baseUrl = new URL(UPSTREAM_BASE_URL);
|
|
164
|
+
const basePath = baseUrl.pathname.replace(/\/+$/, "");
|
|
165
|
+
const fullPath = basePath + (req.url || "");
|
|
166
|
+
const isHttps = baseUrl.protocol === "https:";
|
|
167
|
+
const lib = isHttps ? https : http;
|
|
168
|
+
const headers = { ...req.headers };
|
|
169
|
+
delete headers["host"];
|
|
170
|
+
delete headers["content-length"];
|
|
171
|
+
// body 已被解压/修改,必须删除原压缩标记和逐跳头,否则上游会尝试解压明文导致失败
|
|
172
|
+
delete headers["content-encoding"];
|
|
173
|
+
delete headers["transfer-encoding"];
|
|
174
|
+
headers["host"] = baseUrl.host;
|
|
175
|
+
if (UPSTREAM_AUTH_TOKEN) {
|
|
176
|
+
headers["authorization"] = `Bearer ${UPSTREAM_AUTH_TOKEN}`;
|
|
177
|
+
headers["x-api-key"] = UPSTREAM_AUTH_TOKEN;
|
|
178
|
+
}
|
|
179
|
+
if (body) {
|
|
180
|
+
headers["content-length"] = String(Buffer.byteLength(body));
|
|
181
|
+
}
|
|
182
|
+
const options = {
|
|
183
|
+
method: req.method,
|
|
184
|
+
hostname: baseUrl.hostname,
|
|
185
|
+
port: baseUrl.port || (isHttps ? 443 : 80),
|
|
186
|
+
path: fullPath,
|
|
187
|
+
headers,
|
|
188
|
+
};
|
|
189
|
+
const proxyReq = lib.request(options, (proxyRes) => {
|
|
190
|
+
res.writeHead(proxyRes.statusCode || 502, proxyRes.headers);
|
|
191
|
+
proxyRes.pipe(res);
|
|
192
|
+
});
|
|
193
|
+
proxyReq.on("error", (err) => {
|
|
194
|
+
log(`[image-proxy] 转发失败: ${err.message}`);
|
|
195
|
+
if (!res.headersSent) {
|
|
196
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
197
|
+
res.end(JSON.stringify({ error: { type: "proxy_error", message: err.message } }));
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
if (body) {
|
|
201
|
+
proxyReq.write(body);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
req.pipe(proxyReq);
|
|
205
|
+
}
|
|
206
|
+
proxyReq.end();
|
|
207
|
+
}
|
|
208
|
+
// ────────────────────── 端口清理 ──────────────────────
|
|
209
|
+
function killProcessOnPort(port) {
|
|
210
|
+
try {
|
|
211
|
+
if (process.platform === "win32") {
|
|
212
|
+
execSync(`powershell -NoProfile -Command "Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }"`, { stdio: "ignore", timeout: 5000 });
|
|
213
|
+
}
|
|
214
|
+
else if (process.platform === "darwin" || process.platform === "linux") {
|
|
215
|
+
// macOS/Linux: lsof 找到占用端口的 PID 并 kill -9
|
|
216
|
+
// lsof 不存在时静默失败,|| true 保证命令返回 0
|
|
217
|
+
execSync(`lsof -ti :${port} 2>/dev/null | xargs kill -9 2>/dev/null || true`, {
|
|
218
|
+
stdio: "ignore",
|
|
219
|
+
timeout: 5000,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
log(`[image-proxy] 已清理占用端口 ${port} 的旧进程`);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
// 忽略错误
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
// ────────────────────── 启动代理 ──────────────────────
|
|
234
|
+
export function startImageProxy() {
|
|
235
|
+
return new Promise((resolve) => {
|
|
236
|
+
if (!UPSTREAM_BASE_URL) {
|
|
237
|
+
log("[image-proxy] 未设置 UPSTREAM_BASE_URL,代理功能不可用(MCP 工具仍可用)");
|
|
238
|
+
resolve();
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const server = http.createServer(async (req, res) => {
|
|
242
|
+
const isMessagesEndpoint = req.method === "POST" && (req.url || "").includes("/v1/messages");
|
|
243
|
+
if (!isMessagesEndpoint) {
|
|
244
|
+
forwardRequest(req, res, null);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const chunks = [];
|
|
248
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
249
|
+
req.on("end", async () => {
|
|
250
|
+
const buffer = Buffer.concat(chunks);
|
|
251
|
+
const contentEncoding = (req.headers["content-encoding"] || "").toLowerCase();
|
|
252
|
+
// 解压请求体(支持 gzip / deflate / br),否则 JSON.parse 会失败
|
|
253
|
+
let rawBody;
|
|
254
|
+
try {
|
|
255
|
+
if (contentEncoding.includes("gzip")) {
|
|
256
|
+
rawBody = zlib.gunzipSync(buffer).toString("utf8");
|
|
257
|
+
}
|
|
258
|
+
else if (contentEncoding.includes("deflate")) {
|
|
259
|
+
rawBody = zlib.inflateSync(buffer).toString("utf8");
|
|
260
|
+
}
|
|
261
|
+
else if (contentEncoding.includes("br")) {
|
|
262
|
+
rawBody = zlib.brotliDecompressSync(buffer).toString("utf8");
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
rawBody = buffer.toString("utf8");
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
log(`[image-proxy] 请求体解压失败: ${err.message}`);
|
|
270
|
+
if (!res.headersSent) {
|
|
271
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
272
|
+
res.end(JSON.stringify({
|
|
273
|
+
error: { type: "proxy_error", message: "请求体解压失败" },
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
const requestData = JSON.parse(rawBody);
|
|
280
|
+
let hasImage = false;
|
|
281
|
+
if (Array.isArray(requestData.messages)) {
|
|
282
|
+
for (const msg of requestData.messages) {
|
|
283
|
+
if (Array.isArray(msg.content)) {
|
|
284
|
+
for (const block of msg.content) {
|
|
285
|
+
// 检测所有可能的图片格式
|
|
286
|
+
if (block?.type === "image" ||
|
|
287
|
+
block?.type === "image_url" ||
|
|
288
|
+
(block?.type === "tool_result" && Array.isArray(block.content))) {
|
|
289
|
+
hasImage = true;
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (hasImage)
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (hasImage) {
|
|
299
|
+
log(`[image-proxy] 检测到图片,开始识别...`);
|
|
300
|
+
requestData.messages = await processMessages(requestData.messages);
|
|
301
|
+
const newBody = JSON.stringify(requestData);
|
|
302
|
+
forwardRequest(req, res, newBody);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
forwardRequest(req, res, rawBody);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
log(`[image-proxy] 处理失败: ${err.message}`);
|
|
310
|
+
if (!res.headersSent) {
|
|
311
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
312
|
+
res.end(JSON.stringify({
|
|
313
|
+
error: { type: "proxy_error", message: err.message },
|
|
314
|
+
}));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
req.on("error", (err) => {
|
|
319
|
+
log(`[image-proxy] 请求错误: ${err.message}`);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
let retried = false;
|
|
323
|
+
server.on("error", (err) => {
|
|
324
|
+
const msg = err.message;
|
|
325
|
+
if (msg.includes("EADDRINUSE") && !retried) {
|
|
326
|
+
retried = true;
|
|
327
|
+
log(`[image-proxy] 端口 ${PROXY_PORT} 被占用,清理旧进程后重试...`);
|
|
328
|
+
killProcessOnPort(PROXY_PORT);
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
server.listen(PROXY_PORT, "127.0.0.1");
|
|
331
|
+
}, 1000);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// 其他错误或重试仍失败,不阻塞 MCP 启动
|
|
335
|
+
log(`[image-proxy] 代理启动失败(MCP 工具仍可用): ${msg}`);
|
|
336
|
+
resolve();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
server.listen(PROXY_PORT, "127.0.0.1", () => {
|
|
340
|
+
log(`[image-proxy] 代理已启动: http://127.0.0.1:${PROXY_PORT}`);
|
|
341
|
+
log(`[image-proxy] 上游 API: ${UPSTREAM_BASE_URL}`);
|
|
342
|
+
resolve();
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=imageProxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imageProxy.js","sourceRoot":"","sources":["../../src/proxy/imageProxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const DescribeImageInputSchema: z.ZodObject<{
|
|
3
|
+
image: z.ZodString;
|
|
4
|
+
prompt: z.ZodDefault<z.ZodString>;
|
|
5
|
+
max_tokens: z.ZodDefault<z.ZodNumber>;
|
|
6
|
+
}, "strict", z.ZodTypeAny, {
|
|
7
|
+
image: string;
|
|
8
|
+
prompt: string;
|
|
9
|
+
max_tokens: number;
|
|
10
|
+
}, {
|
|
11
|
+
image: string;
|
|
12
|
+
prompt?: string | undefined;
|
|
13
|
+
max_tokens?: number | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export type DescribeImageInput = z.infer<typeof DescribeImageInputSchema>;
|
|
16
|
+
export declare const DescribeClipboardInputSchema: z.ZodObject<{
|
|
17
|
+
prompt: z.ZodDefault<z.ZodString>;
|
|
18
|
+
max_tokens: z.ZodDefault<z.ZodNumber>;
|
|
19
|
+
}, "strict", z.ZodTypeAny, {
|
|
20
|
+
prompt: string;
|
|
21
|
+
max_tokens: number;
|
|
22
|
+
}, {
|
|
23
|
+
prompt?: string | undefined;
|
|
24
|
+
max_tokens?: number | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
export type DescribeClipboardInput = z.infer<typeof DescribeClipboardInputSchema>;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DEFAULT_PROMPT } from "./constants.js";
|
|
3
|
+
export const DescribeImageInputSchema = z.object({
|
|
4
|
+
image: z.string()
|
|
5
|
+
.min(1, "image is required")
|
|
6
|
+
.describe("图片路径或 URL。支持本地文件路径(如 C:/Users/user/screenshot.png 或 /tmp/img.jpg)或 http(s):// 开头的图片 URL"),
|
|
7
|
+
prompt: z.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.max(4000)
|
|
10
|
+
.default(DEFAULT_PROMPT)
|
|
11
|
+
.describe("询问图片的问题或识图指令,例如 '描述图片内容'、'图片中有哪些文字'、'这是什么图表'、'提取图片中的所有文字'"),
|
|
12
|
+
max_tokens: z.number()
|
|
13
|
+
.int()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(8192)
|
|
16
|
+
.default(2048)
|
|
17
|
+
.describe("返回描述的最大 token 数,1-8192 之间,默认 2048"),
|
|
18
|
+
}).strict();
|
|
19
|
+
export const DescribeClipboardInputSchema = z.object({
|
|
20
|
+
prompt: z.string()
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(4000)
|
|
23
|
+
.default(DEFAULT_PROMPT)
|
|
24
|
+
.describe("询问图片的问题或识图指令,例如 '描述图片内容'、'图片中有哪些文字'、'这是什么图表'、'提取图片中的所有文字'"),
|
|
25
|
+
max_tokens: z.number()
|
|
26
|
+
.int()
|
|
27
|
+
.min(1)
|
|
28
|
+
.max(8192)
|
|
29
|
+
.default(2048)
|
|
30
|
+
.describe("返回描述的最大 token 数,1-8192 之间,默认 2048"),
|
|
31
|
+
}).strict();
|
|
32
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;SACd,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC;SAC3B,QAAQ,CAAC,yFAAyF,CAAC;IACtG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;SACf,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,OAAO,CAAC,cAAc,CAAC;SACvB,QAAQ,CAAC,2DAA2D,CAAC;IACxE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;SACnB,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,mCAAmC,CAAC;CACjD,CAAC,CAAC,MAAM,EAAE,CAAC;AAIZ,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;SACf,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,OAAO,CAAC,cAAc,CAAC;SACvB,QAAQ,CAAC,2DAA2D,CAAC;IACxE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;SACnB,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,mCAAmC,CAAC;CACjD,CAAC,CAAC,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImageLoadResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 跨平台读取剪贴板图片
|
|
4
|
+
*
|
|
5
|
+
* - Windows: PowerShell System.Windows.Forms.Clipboard
|
|
6
|
+
* - macOS: pngpaste (优先) 或 osascript
|
|
7
|
+
* - Linux: xclip (优先) 或 xsel
|
|
8
|
+
*/
|
|
9
|
+
export declare function readClipboardImage(): Promise<ImageLoadResult>;
|
|
10
|
+
/**
|
|
11
|
+
* 清理上次进程异常退出残留的临时图片文件
|
|
12
|
+
*
|
|
13
|
+
* readClipboardImage 用 finally 清理临时文件,但进程被 SIGKILL 时来不及执行。
|
|
14
|
+
* 启动时调一次,扫掉 os.tmpdir() 里所有 kimi_clipboard_*.png。
|
|
15
|
+
*/
|
|
16
|
+
export declare function cleanupOldTempImages(): Promise<void>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import fs from "fs/promises";
|
|
6
|
+
import { IMAGE_MAX_SIZE_BYTES } from "../constants.js";
|
|
7
|
+
import { imageBufferToDataUrl, detectMimeTypeFromPath } from "./image.js";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
/**
|
|
10
|
+
* 生成临时图片路径
|
|
11
|
+
*/
|
|
12
|
+
function getTempImagePath() {
|
|
13
|
+
const timestamp = Date.now();
|
|
14
|
+
return path.join(os.tmpdir(), `kimi_clipboard_${timestamp}.png`);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 从临时文件加载图片为 data URL,并清理临时文件
|
|
18
|
+
*/
|
|
19
|
+
async function loadTempImage(tempPath) {
|
|
20
|
+
let buffer;
|
|
21
|
+
try {
|
|
22
|
+
buffer = await fs.readFile(tempPath);
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
// 无论成功与否都尝试清理临时文件
|
|
26
|
+
fs.unlink(tempPath).catch(() => { });
|
|
27
|
+
}
|
|
28
|
+
if (buffer.length > IMAGE_MAX_SIZE_BYTES) {
|
|
29
|
+
throw new Error(`剪贴板图片过大: ${(buffer.length / 1024 / 1024).toFixed(2)} MB,最大支持 ${IMAGE_MAX_SIZE_BYTES / 1024 / 1024} MB`);
|
|
30
|
+
}
|
|
31
|
+
const mimeType = detectMimeTypeFromPath(tempPath); // .png → image/png
|
|
32
|
+
return {
|
|
33
|
+
dataUrl: imageBufferToDataUrl(buffer, mimeType),
|
|
34
|
+
mimeType,
|
|
35
|
+
sizeBytes: buffer.length,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// ────────────────────── Windows ──────────────────────
|
|
39
|
+
async function readClipboardWindows() {
|
|
40
|
+
const tempPath = getTempImagePath();
|
|
41
|
+
// PowerShell 单引号字符串里所有字符都是字面量(含 \ $ 反引号),单引号本身转义为 ''
|
|
42
|
+
// 这样避免路径含特殊字符时被 PowerShell 解释,比双引号 + 反斜杠转义更安全
|
|
43
|
+
const safePath = tempPath.replace(/'/g, "''");
|
|
44
|
+
const psScript = `
|
|
45
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
46
|
+
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
|
47
|
+
if ($img -eq $null) {
|
|
48
|
+
exit 1
|
|
49
|
+
}
|
|
50
|
+
$img.Save('${safePath}')
|
|
51
|
+
$img.Dispose()
|
|
52
|
+
exit 0
|
|
53
|
+
`.trim();
|
|
54
|
+
try {
|
|
55
|
+
await execFileAsync("powershell", [
|
|
56
|
+
"-NoProfile",
|
|
57
|
+
"-NonInteractive",
|
|
58
|
+
"-Command",
|
|
59
|
+
psScript,
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err.code === 1) {
|
|
64
|
+
throw new Error("剪贴板中没有图片");
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`PowerShell 读取剪贴板图片失败: ${err.message}`);
|
|
67
|
+
}
|
|
68
|
+
return loadTempImage(tempPath);
|
|
69
|
+
}
|
|
70
|
+
// ────────────────────── macOS ──────────────────────
|
|
71
|
+
async function readClipboardMac() {
|
|
72
|
+
const tempPath = getTempImagePath();
|
|
73
|
+
// 优先尝试 pngpaste(brew install pngpaste)
|
|
74
|
+
try {
|
|
75
|
+
await execFileAsync("pngpaste", [tempPath]);
|
|
76
|
+
return loadTempImage(tempPath);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
// pngpaste 不可用或执行失败(如剪贴板无图片),回退到 osascript
|
|
80
|
+
console.error(`[vision-mcp] pngpaste 不可用,回退到 osascript: ${err.message}`);
|
|
81
|
+
}
|
|
82
|
+
// 使用 AppleScript 从剪贴板读取 PNG 图片
|
|
83
|
+
const appleScript = `
|
|
84
|
+
try
|
|
85
|
+
set theFile to (open for access POSIX file "${tempPath}" with write permission)
|
|
86
|
+
try
|
|
87
|
+
write (the clipboard as «class PNGf») to theFile
|
|
88
|
+
on error
|
|
89
|
+
close access theFile
|
|
90
|
+
error "NoImage"
|
|
91
|
+
end try
|
|
92
|
+
close access theFile
|
|
93
|
+
on error errMsg
|
|
94
|
+
if errMsg is "NoImage" then
|
|
95
|
+
error "NoImage"
|
|
96
|
+
else
|
|
97
|
+
error errMsg
|
|
98
|
+
end if
|
|
99
|
+
end try
|
|
100
|
+
`.trim();
|
|
101
|
+
try {
|
|
102
|
+
await execFileAsync("osascript", ["-e", appleScript]);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
const msg = err.message || "";
|
|
106
|
+
if (msg.includes("NoImage") || msg.includes("clipboard")) {
|
|
107
|
+
throw new Error("剪贴板中没有图片");
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`osascript 读取剪贴板图片失败: ${msg}`);
|
|
110
|
+
}
|
|
111
|
+
return loadTempImage(tempPath);
|
|
112
|
+
}
|
|
113
|
+
// ────────────────────── Linux ──────────────────────
|
|
114
|
+
async function readClipboardLinux() {
|
|
115
|
+
const tempPath = getTempImagePath();
|
|
116
|
+
// 尝试 xclip
|
|
117
|
+
try {
|
|
118
|
+
const { stdout } = await execFileAsync("xclip", [
|
|
119
|
+
"-selection",
|
|
120
|
+
"clipboard",
|
|
121
|
+
"-t",
|
|
122
|
+
"image/png",
|
|
123
|
+
"-o",
|
|
124
|
+
], { encoding: "buffer" });
|
|
125
|
+
if (!stdout || stdout.length === 0) {
|
|
126
|
+
throw new Error("剪贴板中没有图片");
|
|
127
|
+
}
|
|
128
|
+
await fs.writeFile(tempPath, stdout);
|
|
129
|
+
return loadTempImage(tempPath);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (err.message?.includes("剪贴板中没有图片")) {
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
// xclip 不可用或执行失败,尝试 xsel
|
|
136
|
+
}
|
|
137
|
+
// 尝试 xsel
|
|
138
|
+
try {
|
|
139
|
+
const { stdout } = await execFileAsync("xsel", [
|
|
140
|
+
"--clipboard",
|
|
141
|
+
"--output",
|
|
142
|
+
], { encoding: "buffer" });
|
|
143
|
+
if (!stdout || stdout.length === 0) {
|
|
144
|
+
throw new Error("剪贴板中没有图片");
|
|
145
|
+
}
|
|
146
|
+
await fs.writeFile(tempPath, stdout);
|
|
147
|
+
return loadTempImage(tempPath);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
if (err.message?.includes("剪贴板中没有图片")) {
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
throw new Error("Linux 剪贴板读取失败,请安装 xclip 或 xsel: sudo apt install xclip");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ────────────────────── 统一入口 ──────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* 跨平台读取剪贴板图片
|
|
159
|
+
*
|
|
160
|
+
* - Windows: PowerShell System.Windows.Forms.Clipboard
|
|
161
|
+
* - macOS: pngpaste (优先) 或 osascript
|
|
162
|
+
* - Linux: xclip (优先) 或 xsel
|
|
163
|
+
*/
|
|
164
|
+
export async function readClipboardImage() {
|
|
165
|
+
const platform = process.platform;
|
|
166
|
+
switch (platform) {
|
|
167
|
+
case "win32":
|
|
168
|
+
return readClipboardWindows();
|
|
169
|
+
case "darwin":
|
|
170
|
+
return readClipboardMac();
|
|
171
|
+
case "linux":
|
|
172
|
+
return readClipboardLinux();
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`不支持的平台: ${platform}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 清理上次进程异常退出残留的临时图片文件
|
|
179
|
+
*
|
|
180
|
+
* readClipboardImage 用 finally 清理临时文件,但进程被 SIGKILL 时来不及执行。
|
|
181
|
+
* 启动时调一次,扫掉 os.tmpdir() 里所有 kimi_clipboard_*.png。
|
|
182
|
+
*/
|
|
183
|
+
export async function cleanupOldTempImages() {
|
|
184
|
+
const tmpDir = os.tmpdir();
|
|
185
|
+
try {
|
|
186
|
+
const files = await fs.readdir(tmpDir);
|
|
187
|
+
const pattern = /^kimi_clipboard_\d+\.png$/;
|
|
188
|
+
await Promise.all(files
|
|
189
|
+
.filter((f) => pattern.test(f))
|
|
190
|
+
.map((f) => fs.unlink(path.join(tmpDir, f)).catch(() => { })));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// 忽略错误
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/services/clipboard.ts"],"names":[],"mappings":"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"}
|