@lutery/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/README.md +428 -0
- package/dist/adapters/base-adapter.d.ts +69 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +143 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/claude-adapter.d.ts +38 -0
- package/dist/adapters/claude-adapter.d.ts.map +1 -0
- package/dist/adapters/claude-adapter.js +251 -0
- package/dist/adapters/claude-adapter.js.map +1 -0
- package/dist/adapters/glm-adapter.d.ts +15 -0
- package/dist/adapters/glm-adapter.d.ts.map +1 -0
- package/dist/adapters/glm-adapter.js +131 -0
- package/dist/adapters/glm-adapter.js.map +1 -0
- package/dist/adapters/modelscope-adapter.d.ts +20 -0
- package/dist/adapters/modelscope-adapter.d.ts.map +1 -0
- package/dist/adapters/modelscope-adapter.js +142 -0
- package/dist/adapters/modelscope-adapter.js.map +1 -0
- package/dist/adapters/openai-adapter.d.ts +20 -0
- package/dist/adapters/openai-adapter.d.ts.map +1 -0
- package/dist/adapters/openai-adapter.js +194 -0
- package/dist/adapters/openai-adapter.js.map +1 -0
- package/dist/adapters/siliconflow-adapter.d.ts +21 -0
- package/dist/adapters/siliconflow-adapter.d.ts.map +1 -0
- package/dist/adapters/siliconflow-adapter.js +145 -0
- package/dist/adapters/siliconflow-adapter.js.map +1 -0
- package/dist/config/model-config.d.ts +39 -0
- package/dist/config/model-config.d.ts.map +1 -0
- package/dist/config/model-config.js +115 -0
- package/dist/config/model-config.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +186 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/system.d.ts +75 -0
- package/dist/prompts/system.d.ts.map +1 -0
- package/dist/prompts/system.js +272 -0
- package/dist/prompts/system.js.map +1 -0
- package/dist/providers/provider-registry.d.ts +58 -0
- package/dist/providers/provider-registry.d.ts.map +1 -0
- package/dist/providers/provider-registry.js +173 -0
- package/dist/providers/provider-registry.js.map +1 -0
- package/dist/src/adapters/base-adapter.d.ts +59 -0
- package/dist/src/adapters/base-adapter.d.ts.map +1 -0
- package/dist/src/adapters/base-adapter.js +83 -0
- package/dist/src/adapters/base-adapter.js.map +1 -0
- package/dist/src/adapters/glm-adapter.d.ts +15 -0
- package/dist/src/adapters/glm-adapter.d.ts.map +1 -0
- package/dist/src/adapters/glm-adapter.js +116 -0
- package/dist/src/adapters/glm-adapter.js.map +1 -0
- package/dist/src/adapters/siliconflow-adapter.d.ts +21 -0
- package/dist/src/adapters/siliconflow-adapter.d.ts.map +1 -0
- package/dist/src/adapters/siliconflow-adapter.js +130 -0
- package/dist/src/adapters/siliconflow-adapter.js.map +1 -0
- package/dist/src/config/model-config.d.ts +40 -0
- package/dist/src/config/model-config.d.ts.map +1 -0
- package/dist/src/config/model-config.js +126 -0
- package/dist/src/config/model-config.js.map +1 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +188 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/prompts/system.d.ts +75 -0
- package/dist/src/prompts/system.d.ts.map +1 -0
- package/dist/src/prompts/system.js +272 -0
- package/dist/src/prompts/system.js.map +1 -0
- package/dist/src/tools/vision-tool.d.ts +91 -0
- package/dist/src/tools/vision-tool.d.ts.map +1 -0
- package/dist/src/tools/vision-tool.js +171 -0
- package/dist/src/tools/vision-tool.js.map +1 -0
- package/dist/src/utils/errors.d.ts +65 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +146 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/image-input.d.ts +45 -0
- package/dist/src/utils/image-input.d.ts.map +1 -0
- package/dist/src/utils/image-input.js +226 -0
- package/dist/src/utils/image-input.js.map +1 -0
- package/dist/src/utils/logger.d.ts +63 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +157 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/test/integration.test.d.ts +10 -0
- package/dist/test/integration.test.d.ts.map +1 -0
- package/dist/test/integration.test.js +270 -0
- package/dist/test/integration.test.js.map +1 -0
- package/dist/test/test-utils.d.ts +45 -0
- package/dist/test/test-utils.d.ts.map +1 -0
- package/dist/test/test-utils.js +107 -0
- package/dist/test/test-utils.js.map +1 -0
- package/dist/test/vision-tool.test.d.ts +9 -0
- package/dist/test/vision-tool.test.d.ts.map +1 -0
- package/dist/test/vision-tool.test.js +167 -0
- package/dist/test/vision-tool.test.js.map +1 -0
- package/dist/tools/vision-tool.d.ts +91 -0
- package/dist/tools/vision-tool.d.ts.map +1 -0
- package/dist/tools/vision-tool.js +167 -0
- package/dist/tools/vision-tool.js.map +1 -0
- package/dist/utils/data-url-parser.d.ts +27 -0
- package/dist/utils/data-url-parser.d.ts.map +1 -0
- package/dist/utils/data-url-parser.js +53 -0
- package/dist/utils/data-url-parser.js.map +1 -0
- package/dist/utils/errors.d.ts +65 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +146 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/image-input.d.ts +45 -0
- package/dist/utils/image-input.d.ts.map +1 -0
- package/dist/utils/image-input.js +238 -0
- package/dist/utils/image-input.js.map +1 -0
- package/dist/utils/logger.d.ts +63 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +157 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/thinking-extractors.d.ts +34 -0
- package/dist/utils/thinking-extractors.d.ts.map +1 -0
- package/dist/utils/thinking-extractors.js +83 -0
- package/dist/utils/thinking-extractors.js.map +1 -0
- package/dist/utils/thinking-filter.d.ts +32 -0
- package/dist/utils/thinking-filter.d.ts.map +1 -0
- package/dist/utils/thinking-filter.js +147 -0
- package/dist/utils/thinking-filter.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Registry
|
|
3
|
+
*
|
|
4
|
+
* @description 提供方注册表,集中管理所有支持的模型提供商
|
|
5
|
+
* 添加新提供商只需在这里注册,无需修改其他文件
|
|
6
|
+
*/
|
|
7
|
+
import { extractGLMThinking, extractOpenAIThinking, extractClaudeThinking } from '../utils/thinking-extractors.js';
|
|
8
|
+
import { GLM4VisionAdapter } from '../adapters/glm-adapter.js';
|
|
9
|
+
import { SiliconFlowAdapter } from '../adapters/siliconflow-adapter.js';
|
|
10
|
+
import { ModelScopeAdapter } from '../adapters/modelscope-adapter.js';
|
|
11
|
+
import { OpenAIAdapter } from '../adapters/openai-adapter.js';
|
|
12
|
+
import { ClaudeAdapter } from '../adapters/claude-adapter.js';
|
|
13
|
+
/**
|
|
14
|
+
* 提供商注册表
|
|
15
|
+
*/
|
|
16
|
+
class ProviderRegistry {
|
|
17
|
+
providers = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* 注册提供商
|
|
20
|
+
*/
|
|
21
|
+
register(provider) {
|
|
22
|
+
this.providers.set(provider.type, provider);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 获取提供商
|
|
26
|
+
*/
|
|
27
|
+
get(type) {
|
|
28
|
+
return this.providers.get(type);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 检查是否支持该类型
|
|
32
|
+
*/
|
|
33
|
+
has(type) {
|
|
34
|
+
return this.providers.has(type);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 获取所有支持的类型
|
|
38
|
+
*/
|
|
39
|
+
getSupportedTypes() {
|
|
40
|
+
return Array.from(this.providers.keys());
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// 创建全局注册表实例
|
|
44
|
+
export const registry = new ProviderRegistry();
|
|
45
|
+
// ========================================================================
|
|
46
|
+
// 注册内置提供商
|
|
47
|
+
// ========================================================================
|
|
48
|
+
// GLM-4.6V Provider
|
|
49
|
+
registry.register({
|
|
50
|
+
type: 'glm-4.6v',
|
|
51
|
+
displayName: 'GLM-4.6V',
|
|
52
|
+
defaults: {
|
|
53
|
+
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
|
|
54
|
+
modelName: 'glm-4.6v',
|
|
55
|
+
timeout: 60000,
|
|
56
|
+
maxRetries: 2
|
|
57
|
+
},
|
|
58
|
+
validateApiKey: (apiKey) => {
|
|
59
|
+
if (!apiKey.includes('.')) {
|
|
60
|
+
return 'GLM API Key should contain a dot (.)';
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
},
|
|
64
|
+
createAdapter: (config) => new GLM4VisionAdapter(config),
|
|
65
|
+
thinkingExtractor: extractGLMThinking,
|
|
66
|
+
enableThinking: true
|
|
67
|
+
});
|
|
68
|
+
// GLM alias for backward compatibility (allows using 'glm' instead of 'glm-4.6v')
|
|
69
|
+
registry.register({
|
|
70
|
+
type: 'glm',
|
|
71
|
+
displayName: 'GLM-4.6V (Alias)',
|
|
72
|
+
defaults: {
|
|
73
|
+
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
|
|
74
|
+
modelName: 'glm-4.6v',
|
|
75
|
+
timeout: 60000,
|
|
76
|
+
maxRetries: 2
|
|
77
|
+
},
|
|
78
|
+
validateApiKey: (apiKey) => {
|
|
79
|
+
if (!apiKey.includes('.')) {
|
|
80
|
+
return 'GLM API Key should contain a dot (.)';
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
},
|
|
84
|
+
createAdapter: (config) => new GLM4VisionAdapter({
|
|
85
|
+
...config,
|
|
86
|
+
type: 'glm-4.6v' // Use the full type for the adapter
|
|
87
|
+
}),
|
|
88
|
+
thinkingExtractor: extractGLMThinking,
|
|
89
|
+
enableThinking: true
|
|
90
|
+
});
|
|
91
|
+
// SiliconFlow Provider
|
|
92
|
+
registry.register({
|
|
93
|
+
type: 'siliconflow',
|
|
94
|
+
displayName: 'SiliconFlow',
|
|
95
|
+
defaults: {
|
|
96
|
+
baseUrl: 'https://api.siliconflow.cn/v1',
|
|
97
|
+
modelName: 'Qwen/Qwen2-VL-72B-Instruct',
|
|
98
|
+
timeout: 60000,
|
|
99
|
+
maxRetries: 2
|
|
100
|
+
},
|
|
101
|
+
validateApiKey: (apiKey) => {
|
|
102
|
+
if (!apiKey.startsWith('sk-')) {
|
|
103
|
+
return 'SiliconFlow API Key should start with "sk-"';
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
},
|
|
107
|
+
createAdapter: (config) => new SiliconFlowAdapter(config),
|
|
108
|
+
thinkingExtractor: extractOpenAIThinking,
|
|
109
|
+
enableThinking: false
|
|
110
|
+
});
|
|
111
|
+
// ModelScope Provider
|
|
112
|
+
registry.register({
|
|
113
|
+
type: 'modelscope',
|
|
114
|
+
displayName: 'ModelScope API-Inference',
|
|
115
|
+
defaults: {
|
|
116
|
+
baseUrl: 'https://api-inference.modelscope.cn/v1',
|
|
117
|
+
modelName: 'ZhipuAI/GLM-4.6V',
|
|
118
|
+
timeout: 60000,
|
|
119
|
+
maxRetries: 2
|
|
120
|
+
},
|
|
121
|
+
validateApiKey: (apiKey) => {
|
|
122
|
+
if (!apiKey.startsWith('ms-')) {
|
|
123
|
+
return 'ModelScope API Key should start with "ms-"';
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
},
|
|
127
|
+
createAdapter: (config) => new ModelScopeAdapter(config),
|
|
128
|
+
thinkingExtractor: extractOpenAIThinking,
|
|
129
|
+
enableThinking: false
|
|
130
|
+
});
|
|
131
|
+
// OpenAI Provider
|
|
132
|
+
registry.register({
|
|
133
|
+
type: 'openai',
|
|
134
|
+
displayName: 'OpenAI',
|
|
135
|
+
defaults: {
|
|
136
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
137
|
+
modelName: 'gpt-4o',
|
|
138
|
+
timeout: 60000,
|
|
139
|
+
maxRetries: 2
|
|
140
|
+
},
|
|
141
|
+
validateApiKey: (apiKey) => {
|
|
142
|
+
if (!apiKey.startsWith('sk-')) {
|
|
143
|
+
return 'OpenAI API Key should start with "sk-"';
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
},
|
|
147
|
+
createAdapter: (config) => new OpenAIAdapter(config),
|
|
148
|
+
thinkingExtractor: extractOpenAIThinking,
|
|
149
|
+
enableThinking: false
|
|
150
|
+
});
|
|
151
|
+
// Claude (Anthropic Messages API) Provider
|
|
152
|
+
registry.register({
|
|
153
|
+
type: 'claude',
|
|
154
|
+
displayName: 'Anthropic Claude',
|
|
155
|
+
defaults: {
|
|
156
|
+
baseUrl: 'https://api.anthropic.com',
|
|
157
|
+
modelName: 'claude-3-5-sonnet-20241022',
|
|
158
|
+
timeout: 60000,
|
|
159
|
+
maxRetries: 2
|
|
160
|
+
},
|
|
161
|
+
validateApiKey: (apiKey) => {
|
|
162
|
+
// Claude API key format: sk-ant-...
|
|
163
|
+
// Not strictly enforcing as some providers may use different formats
|
|
164
|
+
if (!apiKey.startsWith('sk-ant-')) {
|
|
165
|
+
return 'Claude API Key typically starts with "sk-ant-". Proxy providers may use different formats.';
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
},
|
|
169
|
+
createAdapter: (config) => new ClaudeAdapter(config),
|
|
170
|
+
thinkingExtractor: extractClaudeThinking,
|
|
171
|
+
enableThinking: false
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../src/providers/provider-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Vision Model Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description 定义模型适配器的统一接口和抽象基类
|
|
5
|
+
*/
|
|
6
|
+
import { ModelConfig } from '../config/model-config.js';
|
|
7
|
+
/**
|
|
8
|
+
* 模型响应接口
|
|
9
|
+
*/
|
|
10
|
+
export interface VisionModelResponse {
|
|
11
|
+
content: string;
|
|
12
|
+
usage?: {
|
|
13
|
+
promptTokens?: number;
|
|
14
|
+
completionTokens?: number;
|
|
15
|
+
totalTokens?: number;
|
|
16
|
+
};
|
|
17
|
+
model?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 模型适配器接口
|
|
21
|
+
*/
|
|
22
|
+
export interface VisionModelAdapter {
|
|
23
|
+
config: ModelConfig;
|
|
24
|
+
/**
|
|
25
|
+
* 分析图片
|
|
26
|
+
* @param imageData - 图片数据(URL 或 base64)
|
|
27
|
+
* @param prompt - 提示词
|
|
28
|
+
* @returns 模型响应
|
|
29
|
+
*/
|
|
30
|
+
analyze(imageData: string, prompt: string): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* 分析图片(带完整响应)
|
|
33
|
+
* @param imageData - 图片数据(URL 或 base64)
|
|
34
|
+
* @param prompt - 提示词
|
|
35
|
+
* @returns 完整响应
|
|
36
|
+
*/
|
|
37
|
+
analyzeWithResponse(imageData: string, prompt: string): Promise<VisionModelResponse>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 抽象基类实现通用功能
|
|
41
|
+
*/
|
|
42
|
+
export declare abstract class BaseVisionModelAdapter implements VisionModelAdapter {
|
|
43
|
+
config: ModelConfig;
|
|
44
|
+
constructor(config: ModelConfig);
|
|
45
|
+
abstract analyze(imageData: string, prompt: string): Promise<string>;
|
|
46
|
+
abstract analyzeWithResponse(imageData: string, prompt: string): Promise<VisionModelResponse>;
|
|
47
|
+
/**
|
|
48
|
+
* 带重试和超时控制的请求包装器
|
|
49
|
+
*/
|
|
50
|
+
protected withRetry<T>(operation: (signal: AbortSignal) => Promise<T>, config?: {
|
|
51
|
+
maxRetries?: number;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
}): Promise<T>;
|
|
54
|
+
/**
|
|
55
|
+
* 解析模型响应
|
|
56
|
+
*/
|
|
57
|
+
protected parseResponse(response: unknown): VisionModelResponse;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=base-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/base-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAIxD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IAEpB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5D;;;;;OAKG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACtF;AAED;;GAEG;AACH,8BAAsB,sBAAuB,YAAW,kBAAkB;IACrD,MAAM,EAAE,WAAW;gBAAnB,MAAM,EAAE,WAAW;IAEtC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAE7F;;OAEG;cACa,SAAS,CAAC,CAAC,EACzB,SAAS,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAC9C,MAAM,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACrD,OAAO,CAAC,CAAC,CAAC;IAsDb;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,mBAAmB;CA4BhE"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Vision Model Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description 定义模型适配器的统一接口和抽象基类
|
|
5
|
+
*/
|
|
6
|
+
import { ModelAPIError, TimeoutError } from '../utils/errors.js';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* 抽象基类实现通用功能
|
|
10
|
+
*/
|
|
11
|
+
export class BaseVisionModelAdapter {
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 带重试和超时控制的请求包装器
|
|
18
|
+
*/
|
|
19
|
+
async withRetry(operation, config = {}) {
|
|
20
|
+
const { maxRetries = this.config.maxRetries || 2, timeout = this.config.timeout || 60000 } = config;
|
|
21
|
+
let lastError;
|
|
22
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
23
|
+
try {
|
|
24
|
+
logger.debug(`Attempt ${attempt + 1}/${maxRetries + 1}`);
|
|
25
|
+
// 使用 AbortController 实现超时
|
|
26
|
+
const controller = new AbortController();
|
|
27
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
28
|
+
try {
|
|
29
|
+
const result = await operation(controller.signal);
|
|
30
|
+
clearTimeout(timeoutId);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
clearTimeout(timeoutId);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
lastError = error;
|
|
40
|
+
// 如果是 AbortError,转换为 TimeoutError
|
|
41
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
42
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`);
|
|
43
|
+
}
|
|
44
|
+
// 最后一次尝试失败,抛出错误
|
|
45
|
+
if (attempt === maxRetries) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
// 计算退避时间(指数退避)
|
|
49
|
+
const backoffTime = Math.min(1000 * Math.pow(2, attempt), 5000);
|
|
50
|
+
logger.warn(`Attempt ${attempt + 1} failed, retrying in ${backoffTime}ms`, {
|
|
51
|
+
error: lastError.message
|
|
52
|
+
});
|
|
53
|
+
// 等待后退时间
|
|
54
|
+
await new Promise(resolve => setTimeout(resolve, backoffTime));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw new ModelAPIError(`Failed after ${maxRetries + 1} attempts`, { lastError: lastError?.message });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 解析模型响应
|
|
61
|
+
*/
|
|
62
|
+
parseResponse(response) {
|
|
63
|
+
try {
|
|
64
|
+
// @ts-ignore - 检查响应结构
|
|
65
|
+
const content = response?.choices?.[0]?.message?.content;
|
|
66
|
+
if (!content || typeof content !== 'string') {
|
|
67
|
+
throw new ModelAPIError('Invalid response format: missing or invalid content', { response });
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
content,
|
|
71
|
+
// @ts-ignore
|
|
72
|
+
usage: response?.usage,
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
model: response?.model
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
logger.error('Failed to parse model response', error);
|
|
79
|
+
throw new ModelAPIError('Failed to parse model response', { response }, error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=base-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-adapter.js","sourceRoot":"","sources":["../../../src/adapters/base-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM-4.6V Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description GLM-4.6V 模型适配器实现,支持智谱 AI 开放平台的视觉模型
|
|
5
|
+
*/
|
|
6
|
+
import { BaseVisionModelAdapter } from './base-adapter.js';
|
|
7
|
+
import { ModelConfig } from '../config/model-config.js';
|
|
8
|
+
import { VisionModelResponse } from './base-adapter.js';
|
|
9
|
+
export declare class GLM4VisionAdapter extends BaseVisionModelAdapter {
|
|
10
|
+
constructor(config: ModelConfig);
|
|
11
|
+
analyze(imageData: string, prompt: string): Promise<string>;
|
|
12
|
+
analyzeWithResponse(imageData: string, prompt: string): Promise<VisionModelResponse>;
|
|
13
|
+
private callGLMAPI;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=glm-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glm-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/glm-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,qBAAa,iBAAkB,SAAQ,sBAAsB;gBAC/C,MAAM,EAAE,WAAW;IAazB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAuB3D,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAwB5E,UAAU;CAgEzB"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM-4.6V Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description GLM-4.6V 模型适配器实现,支持智谱 AI 开放平台的视觉模型
|
|
5
|
+
*/
|
|
6
|
+
import { BaseVisionModelAdapter } from './base-adapter.js';
|
|
7
|
+
import { ModelAPIError } from '../utils/errors.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
export class GLM4VisionAdapter extends BaseVisionModelAdapter {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
super(config);
|
|
12
|
+
if (config.type !== 'glm-4.6v') {
|
|
13
|
+
throw new Error('Invalid model type. Expected: glm-4.6v');
|
|
14
|
+
}
|
|
15
|
+
logger.info('Initialized GLM-4.6V adapter', {
|
|
16
|
+
model: config.name,
|
|
17
|
+
baseUrl: config.baseUrl
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async analyze(imageData, prompt) {
|
|
21
|
+
logger.logRequest('Analyzing image with GLM-4.6V', {
|
|
22
|
+
modelType: 'glm-4.6v',
|
|
23
|
+
imageLength: imageData.length
|
|
24
|
+
});
|
|
25
|
+
try {
|
|
26
|
+
return await this.withRetry(async (signal) => {
|
|
27
|
+
const response = await this.callGLMAPI(imageData, prompt, signal);
|
|
28
|
+
logger.logRequest('GLM-4.6V analysis completed', {
|
|
29
|
+
modelType: 'glm-4.6v',
|
|
30
|
+
responseLength: response.content.length
|
|
31
|
+
});
|
|
32
|
+
return response.content;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
logger.error('GLM-4.6V analysis failed', error);
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async analyzeWithResponse(imageData, prompt) {
|
|
41
|
+
logger.logRequest('Analyzing image with GLM-4.6V (full response)', {
|
|
42
|
+
modelType: 'glm-4.6v',
|
|
43
|
+
imageLength: imageData.length
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
return await this.withRetry(async (signal) => {
|
|
47
|
+
const response = await this.callGLMAPI(imageData, prompt, signal);
|
|
48
|
+
logger.logRequest('GLM-4.6V analysis completed', {
|
|
49
|
+
modelType: 'glm-4.6v',
|
|
50
|
+
responseLength: response.content.length,
|
|
51
|
+
usage: response.usage
|
|
52
|
+
});
|
|
53
|
+
return response;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logger.error('GLM-4.6V analysis failed', error);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async callGLMAPI(imageData, prompt, signal) {
|
|
62
|
+
// 构建请求 URL
|
|
63
|
+
const apiUrl = `${this.config.baseUrl}/chat/completions`;
|
|
64
|
+
// 构建请求体
|
|
65
|
+
const requestBody = {
|
|
66
|
+
model: this.config.name,
|
|
67
|
+
messages: [
|
|
68
|
+
{
|
|
69
|
+
role: 'user',
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: prompt
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'image_url',
|
|
77
|
+
image_url: {
|
|
78
|
+
url: imageData
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
...(this.config.thinking && {
|
|
85
|
+
thinking: this.config.thinking
|
|
86
|
+
})
|
|
87
|
+
};
|
|
88
|
+
logger.debug('Calling GLM-4.6V API', {
|
|
89
|
+
apiUrl,
|
|
90
|
+
model: this.config.name,
|
|
91
|
+
hasThinking: !!this.config.thinking
|
|
92
|
+
});
|
|
93
|
+
const response = await fetch(apiUrl, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: {
|
|
96
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
'Accept': 'application/json'
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify(requestBody),
|
|
101
|
+
signal
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
const errorText = await response.text().catch(() => 'Failed to get error details');
|
|
105
|
+
throw new ModelAPIError(`GLM API request failed: ${response.status} ${response.statusText}`, {
|
|
106
|
+
status: response.status,
|
|
107
|
+
statusText: response.statusText,
|
|
108
|
+
errorDetails: errorText,
|
|
109
|
+
endpoint: apiUrl
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const responseData = await response.json();
|
|
113
|
+
return this.parseResponse(responseData);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=glm-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glm-adapter.js","sourceRoot":"","sources":["../../../src/adapters/glm-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SiliconFlow Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description SiliconFlow 模型适配器实现,支持多种视觉模型(Qwen2-VL、InternVL 等)
|
|
5
|
+
*/
|
|
6
|
+
import { BaseVisionModelAdapter } from './base-adapter.js';
|
|
7
|
+
import { ModelConfig } from '../config/model-config.js';
|
|
8
|
+
import { VisionModelResponse } from './base-adapter.js';
|
|
9
|
+
export interface SiliconFlowAdapterOptions {
|
|
10
|
+
detail?: 'low' | 'high' | 'auto';
|
|
11
|
+
maxTokens?: number;
|
|
12
|
+
temperature?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class SiliconFlowAdapter extends BaseVisionModelAdapter {
|
|
15
|
+
private options;
|
|
16
|
+
constructor(config: ModelConfig, options?: SiliconFlowAdapterOptions);
|
|
17
|
+
analyze(imageData: string, prompt: string): Promise<string>;
|
|
18
|
+
analyzeWithResponse(imageData: string, prompt: string): Promise<VisionModelResponse>;
|
|
19
|
+
private callSiliconFlowAPI;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=siliconflow-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"siliconflow-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/siliconflow-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,kBAAmB,SAAQ,sBAAsB;IAC5D,OAAO,CAAC,OAAO,CAA4B;gBAE/B,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,yBAA8B;IAqBlE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3D,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YA0B5E,kBAAkB;CAkEjC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SiliconFlow Adapter
|
|
3
|
+
*
|
|
4
|
+
* @description SiliconFlow 模型适配器实现,支持多种视觉模型(Qwen2-VL、InternVL 等)
|
|
5
|
+
*/
|
|
6
|
+
import { BaseVisionModelAdapter } from './base-adapter.js';
|
|
7
|
+
import { ModelAPIError } from '../utils/errors.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
export class SiliconFlowAdapter extends BaseVisionModelAdapter {
|
|
10
|
+
options;
|
|
11
|
+
constructor(config, options = {}) {
|
|
12
|
+
super(config);
|
|
13
|
+
if (config.type !== 'siliconflow') {
|
|
14
|
+
throw new Error('Invalid model type. Expected: siliconflow');
|
|
15
|
+
}
|
|
16
|
+
this.options = {
|
|
17
|
+
detail: 'auto',
|
|
18
|
+
maxTokens: 2048,
|
|
19
|
+
temperature: 0.7,
|
|
20
|
+
...options
|
|
21
|
+
};
|
|
22
|
+
logger.info('Initialized SiliconFlow adapter', {
|
|
23
|
+
model: config.name,
|
|
24
|
+
baseUrl: config.baseUrl,
|
|
25
|
+
options: this.options
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async analyze(imageData, prompt) {
|
|
29
|
+
logger.logRequest('Analyzing image with SiliconFlow', {
|
|
30
|
+
modelType: 'siliconflow',
|
|
31
|
+
model: this.config.name,
|
|
32
|
+
imageLength: imageData.length
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
return await this.withRetry(async (signal) => {
|
|
36
|
+
const response = await this.callSiliconFlowAPI(imageData, prompt, signal);
|
|
37
|
+
logger.logRequest('SiliconFlow analysis completed', {
|
|
38
|
+
modelType: 'siliconflow',
|
|
39
|
+
model: this.config.name,
|
|
40
|
+
responseLength: response.content.length
|
|
41
|
+
});
|
|
42
|
+
return response.content;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
logger.error('SiliconFlow analysis failed', error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async analyzeWithResponse(imageData, prompt) {
|
|
51
|
+
logger.logRequest('Analyzing image with SiliconFlow (full response)', {
|
|
52
|
+
modelType: 'siliconflow',
|
|
53
|
+
model: this.config.name,
|
|
54
|
+
imageLength: imageData.length
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
return await this.withRetry(async (signal) => {
|
|
58
|
+
const response = await this.callSiliconFlowAPI(imageData, prompt, signal);
|
|
59
|
+
logger.logRequest('SiliconFlow analysis completed', {
|
|
60
|
+
modelType: 'siliconflow',
|
|
61
|
+
model: this.config.name,
|
|
62
|
+
responseLength: response.content.length,
|
|
63
|
+
usage: response.usage
|
|
64
|
+
});
|
|
65
|
+
return response;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
logger.error('SiliconFlow analysis failed', error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async callSiliconFlowAPI(imageData, prompt, signal) {
|
|
74
|
+
// 构建请求 URL
|
|
75
|
+
const apiUrl = `${this.config.baseUrl}/chat/completions`;
|
|
76
|
+
// 构建请求体(OpenAI 兼容格式)
|
|
77
|
+
const requestBody = {
|
|
78
|
+
model: this.config.name,
|
|
79
|
+
messages: [
|
|
80
|
+
{
|
|
81
|
+
role: 'user',
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: 'text',
|
|
85
|
+
text: prompt
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
type: 'image_url',
|
|
89
|
+
image_url: {
|
|
90
|
+
url: imageData,
|
|
91
|
+
detail: this.options.detail || 'auto'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
max_tokens: this.options.maxTokens,
|
|
98
|
+
temperature: this.options.temperature
|
|
99
|
+
};
|
|
100
|
+
logger.debug('Calling SiliconFlow API', {
|
|
101
|
+
apiUrl,
|
|
102
|
+
model: this.config.name,
|
|
103
|
+
detail: this.options.detail,
|
|
104
|
+
maxTokens: this.options.maxTokens,
|
|
105
|
+
temperature: this.options.temperature
|
|
106
|
+
});
|
|
107
|
+
const response = await fetch(apiUrl, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
111
|
+
'Content-Type': 'application/json',
|
|
112
|
+
'Accept': 'application/json'
|
|
113
|
+
},
|
|
114
|
+
body: JSON.stringify(requestBody),
|
|
115
|
+
signal
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
const errorText = await response.text().catch(() => 'Failed to get error details');
|
|
119
|
+
throw new ModelAPIError(`SiliconFlow API request failed: ${response.status} ${response.statusText}`, {
|
|
120
|
+
status: response.status,
|
|
121
|
+
statusText: response.statusText,
|
|
122
|
+
errorDetails: errorText,
|
|
123
|
+
endpoint: apiUrl
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const responseData = await response.json();
|
|
127
|
+
return this.parseResponse(responseData);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=siliconflow-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"siliconflow-adapter.js","sourceRoot":"","sources":["../../../src/adapters/siliconflow-adapter.ts"],"names":[],"mappings":"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"}
|