luma-mcp 1.2.9 → 1.3.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/build/config.js CHANGED
@@ -15,28 +15,28 @@ export function loadConfig() {
15
15
  apiKey = process.env.SILICONFLOW_API_KEY;
16
16
  defaultModel = 'deepseek-ai/DeepSeek-OCR';
17
17
  if (!apiKey) {
18
- throw new Error('SILICONFLOW_API_KEY environment variable is required when using SiliconFlow provider');
18
+ throw new Error('SILICONFLOW_API_KEY environment variable is required. Please configure it in your MCP settings.');
19
19
  }
20
20
  }
21
21
  else if (provider === 'qwen') {
22
22
  apiKey = process.env.DASHSCOPE_API_KEY;
23
23
  defaultModel = 'qwen3-vl-flash';
24
24
  if (!apiKey) {
25
- throw new Error('DASHSCOPE_API_KEY environment variable is required when using Qwen provider');
25
+ throw new Error('DASHSCOPE_API_KEY environment variable is required. Please configure it in your MCP settings.');
26
26
  }
27
27
  }
28
28
  else if (provider === 'volcengine') {
29
29
  apiKey = process.env.VOLCENGINE_API_KEY;
30
30
  defaultModel = 'doubao-seed-1-6-flash-250828';
31
31
  if (!apiKey) {
32
- throw new Error('VOLCENGINE_API_KEY environment variable is required when using Volcengine provider');
32
+ throw new Error('VOLCENGINE_API_KEY environment variable is required. Please configure it in your MCP settings.');
33
33
  }
34
34
  }
35
35
  else {
36
36
  apiKey = process.env.ZHIPU_API_KEY;
37
37
  defaultModel = 'glm-4.6v';
38
38
  if (!apiKey) {
39
- throw new Error('ZHIPU_API_KEY environment variable is required when using Zhipu provider');
39
+ throw new Error('ZHIPU_API_KEY environment variable is required. Please configure it in your MCP settings.');
40
40
  }
41
41
  }
42
42
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,aAAa;IACb,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,IAAI,OAAO,CAAkB,CAAC;IAEzF,kBAAkB;IAClB,IAAI,MAA0B,CAAC;IAC/B,IAAI,YAAoB,CAAC;IAEzB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC/B,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACzC,YAAY,GAAG,0BAA0B,CAAC;QAE1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,sFAAsF,CAAC,CAAC;QAC1G,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QACvC,YAAY,GAAG,gBAAgB,CAAC;QAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QACrC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACxC,YAAY,GAAG,8BAA8B,CAAC;QAE9C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACnC,YAAY,GAAG,UAAU,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ;QACR,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,YAAY;QAC7C,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1D,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,KAAK,CAAC;QACzD,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC;QAC9C,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,OAAO;QACvD,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;KAC/C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,aAAa;IACb,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,IAAI,OAAO,CAAkB,CAAC;IAEzF,kBAAkB;IAClB,IAAI,MAA0B,CAAC;IAC/B,IAAI,YAAoB,CAAC;IAEzB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC/B,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACzC,YAAY,GAAG,0BAA0B,CAAC;QAE1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAC;QACrH,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QACvC,YAAY,GAAG,gBAAgB,CAAC;QAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,+FAA+F,CAAC,CAAC;QACnH,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QACrC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACxC,YAAY,GAAG,8BAA8B,CAAC;QAE9C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,gGAAgG,CAAC,CAAC;QACpH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACnC,YAAY,GAAG,UAAU,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;QAC/G,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ;QACR,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,YAAY;QAC7C,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1D,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,KAAK,CAAC;QACzD,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC;QAC9C,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,OAAO;QACvD,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;KAC/C,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "luma-mcp",
3
- "version": "1.2.9",
3
+ "version": "1.3.0",
4
4
  "description": "Multi-model vision understanding MCP server. Supports GLM-4.6V (Zhipu), DeepSeek-OCR (SiliconFlow - Free), Qwen3-VL-Flash (Aliyun), and Doubao-Seed-1.6 (Volcengine)",
5
5
  "type": "module",
6
+ "files": [
7
+ "build/",
8
+ "package.json",
9
+ "README.md"
10
+ ],
6
11
  "bin": {
7
12
  "luma-mcp": "build/index.js"
8
13
  },
package/.env.example DELETED
@@ -1,33 +0,0 @@
1
- # 模型提供商选择:zhipu | siliconflow | qwen | volcengine
2
- MODEL_PROVIDER=zhipu
3
-
4
- # ========== Zhipu AI (推荐 - GLM-4.6V) ==========
5
- # 获取API Key: https://open.bigmodel.cn/
6
- ZHIPU_API_KEY=your-zhipu-api-key-here
7
- MODEL_NAME=glm-4.6v
8
-
9
- # ========== SiliconFlow (免费 - DeepSeek-OCR) ==========
10
- # 获取API Key: https://siliconflow.cn/
11
- # SILICONFLOW_API_KEY=your-siliconflow-api-key
12
- # MODEL_NAME=deepseek-ai/DeepSeek-OCR
13
-
14
- # ========== 阿里云 Qwen (Qwen3-VL-Flash) ==========
15
- # 获取API Key: https://dashscope.aliyun.com/
16
- # DASHSCOPE_API_KEY=your-dashscope-api-key
17
- # MODEL_NAME=qwen3-vl-flash
18
-
19
- # ========== 火山方舟 Volcengine (Doubao-Seed-1.6) ==========
20
- # 获取API Key: https://console.volcengine.com/ark
21
- # VOLCENGINE_API_KEY=your-volcengine-api-key
22
- # MODEL_NAME=doubao-seed-1-6-flash-250828
23
- # 可选模型:
24
- # - doubao-seed-1-6-flash-250828 (性价比高,256k上下文)
25
- # - doubao-seed-1-6-vision-250815 (视觉优化,64k输出)
26
- # - doubao-seed-1-6-lite-251015 (轻量级)
27
- # 注意: 使用控制台中的实际模型ID
28
-
29
- # ========== 通用参数 ==========
30
- MAX_TOKENS=16384
31
- TEMPERATURE=0.7
32
- TOP_P=0.7
33
- ENABLE_THINKING=true
@@ -1,49 +0,0 @@
1
- name: Create Release
2
-
3
- on:
4
- push:
5
- tags:
6
- - 'v*.*.*'
7
-
8
- jobs:
9
- release:
10
- runs-on: ubuntu-latest
11
- permissions:
12
- contents: write
13
-
14
- steps:
15
- - name: Checkout code
16
- uses: actions/checkout@v4
17
- with:
18
- fetch-depth: 0
19
-
20
- - name: Extract version from tag
21
- id: version
22
- run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
23
-
24
- - name: Extract changelog for this version
25
- id: changelog
26
- run: |
27
- VERSION=${{ steps.version.outputs.VERSION }}
28
- echo "Extracting changelog for version $VERSION"
29
-
30
- # Extract changelog content between version headers
31
- sed -n "/## \[${VERSION}\]/,/## \[/p" CHANGELOG.md | sed '$d' > release_notes.md
32
-
33
- # If empty, use a default message
34
- if [ ! -s release_notes.md ]; then
35
- echo "Release version ${VERSION}" > release_notes.md
36
- fi
37
-
38
- cat release_notes.md
39
-
40
- - name: Create GitHub Release
41
- uses: softprops/action-gh-release@v1
42
- with:
43
- tag_name: v${{ steps.version.outputs.VERSION }}
44
- name: Release v${{ steps.version.outputs.VERSION }}
45
- body_path: release_notes.md
46
- draft: false
47
- prerelease: false
48
- env:
49
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
package/CHANGELOG.md DELETED
@@ -1,273 +0,0 @@
1
- # Changelog
2
-
3
- 本项目的所有重大变更都将记录在此文件中。
4
-
5
- ## [1.2.9] - 2025-12-31
6
-
7
- ### Changed
8
-
9
- - ✨ **视觉基础提示词优化**: 重写默认视觉系统提示词,强调基于截图中可见事实进行结构/布局/组件分析,减少对实现细节和不可见交互的主观猜测
10
- - 📝 **工具说明收紧边界**: 更新 `analyze_image` 工具描述,建议上层模型直接传入用户原始问题,避免重复封装复杂视觉 prompt
11
-
12
- ### Technical Details
13
-
14
- - `src/index.ts`: 调整 `DEFAULT_BASE_VISION_PROMPT` 内容与结构,增加对“只说可见事实、推测需显式标注”的约束;完善工具描述文案
15
- - `src/config.ts`: 明确 `ENABLE_THINKING` 配置逻辑,默认启用思考模式,仅当环境变量显式设置为 `false` 时关闭
16
-
17
- ## [1.2.8] - 2025-12-23
18
-
19
- ### Fixed
20
-
21
- - 🐛 **修复 enableThinking 参数传递**: 修复 index.ts 中未将 enableThinking 参数传递给视觉模型客户端的问题
22
- - 🔧 **统一 thinking 逻辑**: 所有支持 thinking 的客户端(智谱、千问、火山方舟)现在使用统一的启用逻辑
23
- - 📝 **完善日志记录**: 千问客户端新增 API 调用日志,与其他客户端保持一致
24
-
25
- ### Changed
26
-
27
- - ♻️ **重构智谱客户端**: 优化 thinking 参数处理逻辑,使代码更清晰易懂
28
- - ♻️ **重构千问客户端**: 统一 thinking 启用逻辑,默认启用思考模式
29
- - ✨ **火山方舟 thinking 支持**: 火山方舟 Doubao 模型现在正确支持思考模式
30
-
31
- ### Technical Details
32
-
33
- - `src/index.ts`: 在 analyzeWithRetry 中正确传递 config.enableThinking 参数
34
- - `src/zhipu-client.ts`: 重构 thinking 逻辑,使用 `if (enableThinking !== false)` 统一判断
35
- - `src/qwen-client.ts`:
36
- - 统一 thinking 启用逻辑为 `if (enableThinking !== false)`
37
- - 新增 logger 导入和 API 调用日志
38
- - 添加成功/失败日志记录
39
- - `src/volcengine-client.ts`:
40
- - 新增 thinking 参数支持到 VolcengineRequest 接口
41
- - 实现 thinking 模式启用逻辑
42
- - 更新日志记录以反映实际 thinking 状态
43
-
44
- ### Thinking Mode Support
45
-
46
- 现在所有支持的模型都正确启用思考模式:
47
-
48
- | 模型 | Thinking 支持 | 实现方式 | 默认状态 |
49
- |-----------------------|---------------|---------------------------------|----------|
50
- | 智谱 GLM-4.6V | ✅ | `thinking: { type: "enabled" }` | 启用 |
51
- | 千问 Qwen3-VL | ✅ | `extra_body.enable_thinking` | 启用 |
52
- | 火山方舟 Doubao | ✅ | `thinking: { type: "enabled" }` | 启用 |
53
- | 硅基流动 DeepSeek-OCR | ❌ | 不支持 | N/A |
54
-
55
- 用户可通过 `ENABLE_THINKING=false` 环境变量禁用思考模式以提升速度和降低成本。
56
-
57
- ## [1.2.7] - 2025-12-17
58
-
59
- ### Added
60
-
61
- - 🆕 **火山方舟 Provider**: 新增第四个视觉模型提供商 - 火山方舟 Volcengine
62
- - 🎯 **Doubao-Seed-1.6 系列**: 支持 flash、vision、lite 多种版本
63
- - 🔧 **统一配置架构**: 客户端构造函数改为接受 LumaConfig 对象,实现配置集中管理
64
- - 🖼️ **完整图片格式支持**: 火山方舟支持 base64 数据、URL 链接和本地文件
65
-
66
- ### Changed
67
-
68
- - 🏗️ **架构重构**: 三个现有客户端(Zhipu、SiliconFlow、Qwen)重构为统一配置对象模式
69
- - 🗃️ **客户端优化**: 移除硬编码默认值,所有配置统一从环境变量读取
70
- - 📝 **API 格式统一**: 火山方舟客户端改为使用 Chat Completions API 格式,与其他 provider 保持一致
71
- - 📚 **文档完善**: 更新中英文 README,添加火山方舟配置示例和模型对比
72
-
73
- ### Technical Details
74
-
75
- - `src/config.ts`: 新增 volcengine provider 支持,添加 VOLCENGINE_API_KEY 环境变量
76
- - `src/volcengine-client.ts`: 新文件,完整实现 VolcengineClient 类,支持 Chat Completions API
77
- - `src/zhipu-client.ts`: 重构构造函数,移除硬编码参数,支持 LumaConfig
78
- - `src/siliconflow-client.ts`: 重构构造函数,支持统一配置对象
79
- - `src/qwen-client.ts`: 重构构造函数,支持统一配置对象
80
- - `src/index.ts`: 添加 VolcengineClient 导入和实例化逻辑
81
- - `.env.example`: 添加火山方舟配置示例和说明
82
- - `README.md` & `docs/README_EN.md`: 新增火山方舟特性说明和配置示例
83
-
84
- ### Provider Summary
85
-
86
- 现在支持 4 个视觉模型提供商:
87
-
88
- 1. **智谱 GLM-4.6V** (默认): 中文理解优秀,16384 tokens
89
- 2. **硅基流动 DeepSeek-OCR**: 免费使用,OCR 能力强
90
- 3. **阿里云 Qwen3-VL-Flash**: 速度快成本低,支持思考模式
91
- 4. **火山方舟 Doubao-Seed-1.6**: 性价比高,256k 上下文,支持多种版本
92
-
93
- ## [1.2.6] - 2025-12-16
94
-
95
- ### Changed
96
-
97
- - 🚀 **模型升级**: 更新智谱模型从 GLM-4.5V 升级至 GLM-4.6V,性能和理解能力提升
98
- - 📈 **Token 限制提升**: 默认 maxTokens 从 8192 提升至 16384,支持更详细的分析输出
99
- - 💡 **思考模式默认开启**: ENABLE_THINKING 默认为 true,提供更准确的分析结果
100
- - 🧹 **代码清理**: 移除 prompts.ts 提示词模板文件,简化架构
101
- - 🔧 **TypeScript 优化**: 清理未使用的类型导入,修复 TS6133 警告
102
- - 📝 **文档完善**: 更新中英文 README,强化三种使用方式说明(粘贴图片、本地路径、URL)
103
-
104
- ### Technical Details
105
-
106
- - `src/config.ts`: 更新默认模型为 glm-4.6v,默认 maxTokens 改为 16384,enableThinking 默认为 true
107
- - `src/zhipu-client.ts`: 更新模型引用,清理未使用导入
108
- - `src/siliconflow-client.ts`: 清理未使用的类型导入
109
- - `src/index.ts`: 简化 prompt 处理逻辑,直接使用原始提示词
110
- - 删除 `src/prompts.ts`: 移除 buildAnalysisPrompt 函数
111
- - README 更新: 模型信息、Token 配置、项目结构、思考模式配置
112
-
113
- ## [1.2.4] - 2025-12-16 (Reverted)
114
-
115
- ### Note
116
-
117
- 此版本因代码回滚问题被回退,所有优化内容已整合至 v1.2.6
118
-
119
- ## [1.2.3] - 2025-11-21
120
-
121
- ### Changed
122
-
123
- - 🧹 **代码清理**: 移除 Claude 特定调试注释和实验性代码
124
- - 📝 **工具描述优化**: 简化和专业化工具说明,提升 AI 模型调用成功率
125
- - 🔧 **路径处理通用化**: 重构 @ 前缀路径处理,移除平台特定命名
126
-
127
- ### Technical Details
128
-
129
- - 移除 Claude 资源读取相关的实验性代码
130
- - 重命名 `stripAtPrefix()` 为 `normalizeImageSourcePath()`
131
- - 清理所有客户端适配器中的调试日志和注释
132
- - 统一代码风格和注释规范
133
-
134
- ## [1.2.2] - 2025-11-20
135
-
136
- ### Added
137
-
138
- - ✨ **@ 路径支持**: 自动处理 Claude Code 的 @ 文件引用前缀,修复第一次调用失败的问题
139
- - 📝 **智能 Prompt**: 通用请求自动添加详细指引,保证全面分析
140
-
141
- ### Changed
142
-
143
- - 🔧 **Prompt 统一**: 简化为单一通用 prompt,智能处理不同场景
144
- - ✨ **表述优化**: 融合 Minimax 的经典表述,强调“不遗漏细节”和“完整提取”
145
- - 📚 **文档更新**: 更新项目结构,添加 qwen-client.ts 和测试文件
146
-
147
- ### Fixed
148
-
149
- - 🐛 **@ 路径问题**: 修复 Claude Code 中 `@folder/image.png` 导致的路径错误
150
- - 🐛 **编译错误**: 修复 image-processor.ts 中重复声明的变量
151
-
152
- ### Technical Details
153
-
154
- - 新增 `stripAtPrefix()` 函数处理 Claude Code 的文件引用语法
155
- - 简化 `buildAnalysisPrompt()` 从两套逻辑到单一逻辑
156
- - 添加智能请求检测,自动补充详细分析指引
157
-
158
- ## [1.2.1] - 2025-11-18
159
-
160
- ### Changed
161
-
162
- - 📝 **文档优化**: 精简 README,移除冲余配置文件路径说明
163
- - 📝 **更新日志简化**: 将 README 中的详细更新日志替换为 CHANGELOG.md 链接
164
- - ✨ **Qwen 测试示例**: 添加 Qwen3-VL-Flash 本地测试命令
165
- - 💰 **定价信息**: 添加阿里云通义千问定价参考链接
166
- - 📋 **模型对比**: 更新模型选择表,完善 Qwen3-VL-Flash 信息
167
- - 🔗 **API Key 获取**: 添加阿里云百炼 API Key 获取指南
168
- - 📚 **相关链接**: 新增阿里云百炼平台和 Qwen3-VL 文档链接
169
- - 🐛 **错误信息**: 优化 API 调用失败排查提示,包含阿里云账户
170
-
171
- ### Fixed
172
-
173
- - 🐛 **描述修正**: 修正 package.json 中模型名称为 qwen3-vl-flash
174
- - 📝 **注释精简**: 简化 prompts.ts 注释头
175
-
176
- ## [1.2.0] - 2025-11-17
177
-
178
- ### Added
179
-
180
- - 🎉 **第三个视觉模型**: 新增阿里云通义千问 Qwen3-VL-Flash 支持
181
- - 💡 **思考模式**: Qwen3-VL-Flash 支持深度思考模式(enable_thinking),提升复杂场景分析准确性
182
- - ⚡ **高性价比**: Flash 版本速度更快、成本更低,适合大量使用
183
- - 🔌 **OpenAI 兼容**: 使用阿里云百炼的 OpenAI 兼容 API,统一接口设计
184
- - 🌐 **多地域支持**: 默认使用北京地域,支持新加坡地域配置
185
-
186
- ### Changed
187
-
188
- - ⚙️ 新增 `MODEL_PROVIDER=qwen` 和 `DASHSCOPE_API_KEY` 环境变量配置
189
- - 📝 更新所有文档(中英文),添加 Qwen3-VL-Flash 配置示例
190
- - 💰 默认使用 qwen3-vl-flash 模型,兹顾性能与成本
191
- - 🏗️ 重构客户端构造函数,统一参数传递方式
192
-
193
- ### Technical Details
194
-
195
- - 新增文件:
196
- - `src/qwen-client.ts` - 阿里云通义千问 VL API 客户端实现
197
- - 修改文件:
198
- - `src/config.ts` - 添加 'qwen' 提供商支持
199
- - `src/zhipu-client.ts` - 重构构造函数,支持独立参数
200
- - `src/siliconflow-client.ts` - 重构构造函数,支持独立参数
201
- - `src/index.ts` - 添加 Qwen 客户端初始化逻辑
202
- - `package.json` - 更新版本至 1.2.0,添加 qwen/aliyun/dashscope 关键词
203
-
204
- ## [1.1.1] - 2025-11-13
205
-
206
- ### Added
207
-
208
- - 🖼️ **Data URI 支持**: 支持接收 base64 编码的图片数据 (data:image/png;base64,...)
209
- - 🚀 **为未来做准备**: 当 MCP 客户端支持时,可直接传递用户粘贴的图片
210
-
211
- ### Changed
212
-
213
- - 📝 更新工具描述,说明支持三种输入格式:本地路径、URL、Data URI
214
- - ✅ 新增 Data URI 格式验证(MIME 类型、大小限制)
215
-
216
- ## [1.1.0] - 2025-11-13
217
-
218
- ### Added
219
-
220
- - 🎉 **多模型支持**: 新增硅基流动 DeepSeek-OCR 支持
221
- - 🆓 **免费选项**: DeepSeek-OCR 通过硅基流动提供完全免费的 OCR 服务
222
- - 📐 **统一接口**: 创建 VisionClient 接口,支持灵活扩展更多视觉模型
223
- - ⚙️ **灵活配置**: 通过 `MODEL_PROVIDER` 环境变量轻松切换模型
224
-
225
- ### Changed
226
-
227
- - 🔧 环境变量命名优化,支持通用配置(`MODEL_NAME`、`MAX_TOKENS` 等)
228
- - 📝 更新文档,提供双模型配置说明和选择建议
229
- - 🏗️ 重构代码结构,提升可维护性
230
-
231
- ### Technical Details
232
-
233
- - 新增文件:
234
- - `src/vision-client.ts` - 视觉模型客户端统一接口
235
- - `src/siliconflow-client.ts` - 硅基流动 API 客户端实现
236
- - `.env.example` - 配置示例文件
237
- - 修改文件:
238
- - `src/config.ts` - 支持多提供商配置
239
- - `src/zhipu-client.ts` - 实现 VisionClient 接口
240
- - `src/index.ts` - 根据配置动态选择客户端
241
- - `README.md` - 完整的双模型使用文档
242
-
243
- ## [1.0.3] - 2025-11-12
244
-
245
- ### Features
246
-
247
- - 基于智谱 GLM-4.5V 的视觉理解能力
248
- - 支持本地文件和远程 URL
249
- - 内置重试机制
250
- - 思考模式支持
251
-
252
- ---
253
-
254
- **模型对比**:
255
-
256
- || 特性 | GLM-4.5V | DeepSeek-OCR | Qwen3-VL-Flash |
257
- ||----------|----------|--------------|----------------|
258
- || 提供商 | 智谱清言 | 硅基流动 | 阿里云百炼 |
259
- || 费用 | 收费 | **免费** | 收费 |
260
- || 中文理解 | 优秀 | 良好 | **优秀** |
261
- || OCR 能力 | 良好 | **优秀** | 优秀 |
262
- || 思考模式 | ✅ | ❌ | ✅ |
263
- || 速度/成本 | 中等 | 免费 | **快/低** |
264
- || 综合能力 | 良好 | OCR 专精 | **优秀** |
265
- || 3D 定位 | ❌ | ❌ | ✅ |
266
-
267
- **推荐使用场景**:
268
-
269
- - 需要 OCR/文字识别 → **DeepSeek-OCR** (免费)
270
- - 需要深度图片理解 → **Qwen3-VL-Flash** 或 **GLM-4.5V**
271
- - 需要思考模式 → **Qwen3-VL-Flash** 或 **GLM-4.5V**
272
- - 需要高性价比 → **Qwen3-VL-Flash** (速度快、成本低)
273
- - 需要 3D 定位/复杂分析 → **Qwen3-VL-Flash**
@@ -1,64 +0,0 @@
1
- /**
2
- * 测试 Data URI 支持
3
- */
4
-
5
- import { validateImageSource, imageToBase64 } from '../src/image-processor.js';
6
-
7
- // 一个有效的 1x1 像素 PNG 图片的 Data URI
8
- const validDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
9
-
10
- // 无效的 Data URI(不支持的格式)
11
- const invalidDataUri = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgc3R5bGU9ImZpbGw6I2ZmZiIgLz48L3N2Zz4=';
12
-
13
- async function testDataUri() {
14
- console.log('🧪 测试 Data URI 支持\n');
15
-
16
- // 测试 1: 验证有效的 Data URI
17
- try {
18
- console.log('测试 1: 验证有效的 PNG Data URI');
19
- await validateImageSource(validDataUri);
20
- console.log('✅ 通过:有效的 Data URI 验证成功\n');
21
- } catch (error) {
22
- console.log(`❌ 失败: ${error instanceof Error ? error.message : String(error)}\n`);
23
- }
24
-
25
- // 测试 2: 验证无效的 Data URI(不支持的格式)
26
- try {
27
- console.log('测试 2: 验证不支持的格式 (SVG)');
28
- await validateImageSource(invalidDataUri);
29
- console.log('❌ 失败:应该抛出错误\n');
30
- } catch (error) {
31
- console.log(`✅ 通过:正确拒绝不支持的格式 - ${error instanceof Error ? error.message : String(error)}\n`);
32
- }
33
-
34
- // 测试 3: Data URI 转换(应该直接返回)
35
- try {
36
- console.log('测试 3: Data URI 转换');
37
- const result = await imageToBase64(validDataUri);
38
- if (result === validDataUri) {
39
- console.log('✅ 通过:Data URI 正确传递(未修改)\n');
40
- } else {
41
- console.log('❌ 失败:Data URI 被修改了\n');
42
- }
43
- } catch (error) {
44
- console.log(`❌ 失败: ${error instanceof Error ? error.message : String(error)}\n`);
45
- }
46
-
47
- // 测试 4: 大小验证(创建一个超过10MB的Data URI)
48
- try {
49
- console.log('测试 4: 验证大小限制 (>10MB)');
50
- // 创建一个约 15MB 的 base64 字符串(20MB * 3/4 = 15MB)
51
- const largeBase64 = 'A'.repeat(20 * 1024 * 1024);
52
- const largeDataUri = `data:image/png;base64,${largeBase64}`;
53
- await validateImageSource(largeDataUri);
54
- console.log('❌ 失败:应该拒绝过大的文件\n');
55
- } catch (error) {
56
- console.log(`✅ 通过:正确拒绝超大文件 - ${error instanceof Error ? error.message : String(error)}\n`);
57
- }
58
-
59
- console.log('==========================================');
60
- console.log('✅ Data URI 测试完成!');
61
- console.log('==========================================\n');
62
- }
63
-
64
- testDataUri().catch(console.error);
@@ -1,100 +0,0 @@
1
- /**
2
- * 直接测试 DeepSeek-OCR API(无任何包装)
3
- */
4
-
5
- import axios from 'axios';
6
- import * as fs from 'fs';
7
- import * as path from 'path';
8
-
9
- async function testDeepSeekOCR(imagePath: string) {
10
- console.log('\n🧪 测试 DeepSeek-OCR API(原始调用)\n');
11
-
12
- const apiKey = process.env.SILICONFLOW_API_KEY;
13
-
14
- if (!apiKey) {
15
- console.error('❌ 错误: 需要设置 SILICONFLOW_API_KEY 环境变量');
16
- console.error('示例: $env:SILICONFLOW_API_KEY="your-api-key"');
17
- process.exit(1);
18
- }
19
-
20
- // 读取图片并转为 base64
21
- const imageBuffer = fs.readFileSync(imagePath);
22
- const base64Image = imageBuffer.toString('base64');
23
- const mimeType = imagePath.endsWith('.png') ? 'image/png' : 'image/jpeg';
24
- const imageDataUrl = `data:${mimeType};base64,${base64Image}`;
25
-
26
- console.log(`📸 图片: ${imagePath}`);
27
- console.log(`📦 大小: ${(imageBuffer.length / 1024).toFixed(2)} KB\n`);
28
-
29
- // 测试不同的 prompt
30
- const prompts = [
31
- '识别图片中的所有文字',
32
- 'OCR',
33
- 'Extract all text from this image',
34
- 'What do you see in this image?',
35
- '请详细描述这张图片'
36
- ];
37
-
38
- for (const prompt of prompts) {
39
- console.log(`\n🔍 测试 Prompt: "${prompt}"`);
40
- console.log('─'.repeat(50));
41
-
42
- try {
43
- const response = await axios.post(
44
- 'https://api.siliconflow.cn/v1/chat/completions',
45
- {
46
- model: 'deepseek-ai/DeepSeek-OCR',
47
- messages: [
48
- {
49
- role: 'user',
50
- content: [
51
- {
52
- type: 'image_url',
53
- image_url: {
54
- url: imageDataUrl,
55
- },
56
- },
57
- {
58
- type: 'text',
59
- text: prompt,
60
- },
61
- ],
62
- },
63
- ],
64
- temperature: 0.7,
65
- max_tokens: 4096,
66
- },
67
- {
68
- headers: {
69
- 'Authorization': `Bearer ${apiKey}`,
70
- 'Content-Type': 'application/json',
71
- },
72
- timeout: 60000,
73
- }
74
- );
75
-
76
- const result = response.data.choices[0].message.content;
77
- const usage = response.data.usage;
78
-
79
- console.log(`✅ Tokens: ${usage.total_tokens} (prompt: ${usage.prompt_tokens}, completion: ${usage.completion_tokens})`);
80
- console.log(`📝 响应长度: ${result?.length || 0} 字符`);
81
-
82
- if (result && result.trim().length > 0) {
83
- console.log('\n📊 结果:');
84
- console.log('─'.repeat(50));
85
- console.log(result);
86
- console.log('─'.repeat(50));
87
- console.log('\n✅ 找到有效响应!');
88
- break;
89
- } else {
90
- console.log('❌ 空响应');
91
- }
92
- } catch (error: any) {
93
- console.log(`❌ 错误: ${error.message}`);
94
- }
95
- }
96
- }
97
-
98
- // 运行测试
99
- const imagePath = path.join(process.cwd(), 'test.png');
100
- testDeepSeekOCR(imagePath).catch(console.error);
@@ -1,101 +0,0 @@
1
- /**
2
- * Luma MCP 本地测试脚本
3
- * 直接测试图片分析功能,不需要MCP客户端
4
- */
5
-
6
- import { loadConfig } from '../src/config.js';
7
- import type { VisionClient } from '../src/vision-client.js';
8
- import { ZhipuClient } from '../src/zhipu-client.js';
9
- import { SiliconFlowClient } from '../src/siliconflow-client.js';
10
- import { imageToBase64, validateImageSource } from '../src/image-processor.js';
11
- import { buildAnalysisPrompt } from '../src/prompts.js';
12
- import { logger } from '../src/utils/logger.js';
13
-
14
- async function testImageAnalysis(imagePath: string, question?: string) {
15
- console.log('\n==========================================');
16
- console.log('🧪 测试 Luma MCP 图片分析');
17
- console.log('==========================================\n');
18
-
19
- try {
20
- // 1. 加载配置
21
- console.log('📝 加载配置...');
22
- const config = loadConfig();
23
- console.log(`✅ 配置加载成功: 提供商 ${config.provider}, 模型 ${config.model}\n`);
24
-
25
- // 2. 验证图片
26
- console.log('🔍 验证图片来源...');
27
- await validateImageSource(imagePath);
28
- console.log(`✅ 图片验证通过: ${imagePath}\n`);
29
-
30
- // 3. 处理图片
31
- console.log('🖼️ 处理图片...');
32
- const imageDataUrl = await imageToBase64(imagePath);
33
- const isUrl = imagePath.startsWith('http');
34
- console.log(`✅ 图片处理完成: ${isUrl ? 'URL' : 'Base64编码'}\n`);
35
-
36
- // 4. 构建提示词
37
- console.log('💬 构建提示词...');
38
- // DeepSeek-OCR 需要简洁 prompt
39
- const prompt = config.provider === 'siliconflow'
40
- ? (question || '请详细分析这张图片的内容')
41
- : buildAnalysisPrompt(question);
42
- console.log(`✅ 提示词: ${question || '通用描述'}\n`);
43
-
44
- // 5. 创建客户端并调用API
45
- const client: VisionClient = config.provider === 'siliconflow'
46
- ? new SiliconFlowClient(config)
47
- : new ZhipuClient(config);
48
-
49
- const modelName = config.provider === 'siliconflow' ? 'DeepSeek-OCR' : 'GLM-4.5V';
50
- console.log(`🤖 调用 ${modelName} API...`);
51
- const result = await client.analyzeImage(imageDataUrl, prompt);
52
-
53
- // 6. 显示结果
54
- console.log('\n==========================================');
55
- console.log('📊 分析结果');
56
- console.log('==========================================\n');
57
- console.log(result);
58
- console.log('\n==========================================');
59
- console.log('✅ 测试完成!');
60
- console.log('==========================================\n');
61
-
62
- } catch (error) {
63
- console.error('\n❌ 测试失败:');
64
- console.error(error instanceof Error ? error.message : String(error));
65
- process.exit(1);
66
- }
67
- }
68
-
69
- // 解析命令行参数
70
- const args = process.argv.slice(2);
71
-
72
- if (args.length === 0) {
73
- console.log(`
74
- 使用方法:
75
- npm run test:local <图片路径或URL> [问题]
76
-
77
- 示例:
78
- # 分析本地图片
79
- npm run test:local ./test.png
80
-
81
- # 分析本地图片并提问
82
- npm run test:local ./code-error.png "这段代码为什么报错?"
83
-
84
- # 分析远程图片
85
- npm run test:local https://example.com/image.jpg
86
-
87
- 环境变量:
88
- # 使用智谱 GLM-4.5V
89
- ZHIPU_API_KEY=your-api-key
90
-
91
- # 使用硅基流动 DeepSeek-OCR
92
- MODEL_PROVIDER=siliconflow
93
- SILICONFLOW_API_KEY=your-api-key
94
- `);
95
- process.exit(1);
96
- }
97
-
98
- const imagePath = args[0];
99
- const question = args.slice(1).join(' ') || undefined;
100
-
101
- testImageAnalysis(imagePath, question);
package/test/test-qwen.ts DELETED
@@ -1,88 +0,0 @@
1
- /**
2
- * Qwen 客户端测试
3
- * 测试阿里云通义千问VL视觉理解
4
- */
5
-
6
- import { QwenClient } from '../src/qwen-client.js';
7
- import { imageToBase64 } from '../src/image-processor.js';
8
-
9
- async function testQwen() {
10
- const apiKey = process.env.DASHSCOPE_API_KEY;
11
-
12
- if (!apiKey) {
13
- console.error('❌ 错误: 需要设置 DASHSCOPE_API_KEY 环境变量');
14
- console.log('设置方法:');
15
- console.log(' macOS/Linux: export DASHSCOPE_API_KEY="your-api-key"');
16
- console.log(' Windows: $env:DASHSCOPE_API_KEY="your-api-key"');
17
- process.exit(1);
18
- }
19
-
20
- // 获取图片路径
21
- const imagePath = process.argv[2];
22
- if (!imagePath) {
23
- console.error('❌ 错误: 请提供图片路径');
24
- console.log('用法: tsx test/test-qwen.ts <图片路径>');
25
- console.log('示例: tsx test/test-qwen.ts ./test.png');
26
- process.exit(1);
27
- }
28
-
29
- console.log('🚀 开始测试 Qwen3-VL-Flash...\n');
30
-
31
- try {
32
- // 1. 初始化客户端
33
- console.log('1️⃣ 初始化 Qwen 客户端...');
34
- const client = new QwenClient(
35
- apiKey,
36
- 'qwen3-vl-flash', // 使用高性价比的 Flash 版本
37
- 4096,
38
- 0.7
39
- );
40
- console.log(`✅ 客户端初始化成功: ${client.getModelName()}\n`);
41
-
42
- // 2. 读取图片
43
- console.log('2️⃣ 读取图片...');
44
- const imageData = await imageToBase64(imagePath);
45
- console.log(`✅ 图片读取成功 (${imagePath})\n`);
46
-
47
- // 3. 测试基础分析
48
- console.log('3️⃣ 测试基础分析(不启用思考模式)...');
49
- const basicResult = await client.analyzeImage(
50
- imageData,
51
- '请详细分析这张图片的内容',
52
- false
53
- );
54
- console.log('📊 基础分析结果:');
55
- console.log(basicResult);
56
- console.log('\n');
57
-
58
- // 4. 测试思考模式
59
- console.log('4️⃣ 测试思考模式(enable_thinking=true)...');
60
- const thinkingResult = await client.analyzeImage(
61
- imageData,
62
- '请详细分析这张图片的内容,包括所有细节',
63
- true // 启用思考模式
64
- );
65
- console.log('🧠 思考模式分析结果:');
66
- console.log(thinkingResult);
67
- console.log('\n');
68
-
69
- // 5. 测试 OCR
70
- console.log('5️⃣ 测试 OCR 能力...');
71
- const ocrResult = await client.analyzeImage(
72
- imageData,
73
- '识别图片中的所有文字',
74
- false
75
- );
76
- console.log('📝 OCR 结果:');
77
- console.log(ocrResult);
78
- console.log('\n');
79
-
80
- console.log('✅ 所有测试完成!');
81
-
82
- } catch (error) {
83
- console.error('❌ 测试失败:', error instanceof Error ? error.message : error);
84
- process.exit(1);
85
- }
86
- }
87
-
88
- testQwen();