@showlotus/opencode-image-vision 1.0.1 → 1.0.2
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/package.json +1 -1
- package/src/concurrency.js +19 -0
- package/src/index.js +17 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@showlotus/opencode-image-vision",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP server that reads images from OpenCode's SQLite database and analyzes them via vision AI providers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@8.11.0",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// 并发执行任务,控制最大并发数,结果按原顺序返回
|
|
2
|
+
export async function mapWithConcurrency(items, concurrency, worker) {
|
|
3
|
+
const results = new Array(items.length)
|
|
4
|
+
let cursor = 0
|
|
5
|
+
|
|
6
|
+
// 单个执行器:循环领取下一个未处理的任务,直到全部完成
|
|
7
|
+
const run = async () => {
|
|
8
|
+
while (cursor < items.length) {
|
|
9
|
+
const i = cursor++
|
|
10
|
+
results[i] = await worker(items[i], i)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 启动不超过任务数量的并发执行器
|
|
15
|
+
await Promise.all(
|
|
16
|
+
Array.from({ length: Math.min(concurrency, items.length) }, run),
|
|
17
|
+
)
|
|
18
|
+
return results
|
|
19
|
+
}
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
5
5
|
import { z } from 'zod'
|
|
6
6
|
import { getDatabase, getImages } from './db.js'
|
|
7
7
|
import { createProvider } from './providers/index.js'
|
|
8
|
+
import { mapWithConcurrency } from './concurrency.js'
|
|
8
9
|
|
|
9
10
|
const DEFAULT_PROMPT =
|
|
10
11
|
process.env.prompt ||
|
|
@@ -17,6 +18,9 @@ const DEFAULT_PROMPT =
|
|
|
17
18
|
const DEFAULT_LIMIT = Number(process.env.limit) || 5
|
|
18
19
|
const MAX_LIMIT = Number(process.env.max_limit) || 20
|
|
19
20
|
|
|
21
|
+
// 并发分析图片的最大并发数,可通过环境变量 concurrency 覆盖
|
|
22
|
+
const DEFAULT_CONCURRENCY = Number(process.env.concurrency) || 5
|
|
23
|
+
|
|
20
24
|
let provider
|
|
21
25
|
try {
|
|
22
26
|
provider = createProvider()
|
|
@@ -60,16 +64,19 @@ server.tool(
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// 并发分析图片,单张失败不影响其他图片,结果保持原顺序
|
|
68
|
+
const results = await mapWithConcurrency(
|
|
69
|
+
images,
|
|
70
|
+
DEFAULT_CONCURRENCY,
|
|
71
|
+
async (img, i) => {
|
|
72
|
+
try {
|
|
73
|
+
const desc = await provider.analyze(img.base64, img.mime, analysisPrompt)
|
|
74
|
+
return `### Image ${i + 1}: ${img.filename}\n\n${desc}`
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return `### Image ${i + 1}: ${img.filename}\n\n[Analysis failed: ${e.message}]`
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
)
|
|
73
80
|
|
|
74
81
|
return {
|
|
75
82
|
content: [
|