@spacex110/core 0.1.11
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/dist/index.d.ts +620 -0
- package/dist/index.js +6401 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +16 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +41 -0
- package/src/api.ts +158 -0
- package/src/channel-manager.ts +790 -0
- package/src/config.ts +104 -0
- package/src/i18n.ts +66 -0
- package/src/index.ts +97 -0
- package/src/models.ts +202 -0
- package/src/providers.ts +249 -0
- package/src/storage.ts +135 -0
- package/src/strategies.ts +469 -0
- package/src/styles.css +246 -0
- package/src/types.ts +163 -0
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spacex110/core",
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"description": "Framework-agnostic AI Provider Selector core utilities",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js",
|
|
11
|
+
"./styles.css": "./src/styles.css"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "vite build",
|
|
19
|
+
"dev": "vite build --watch",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/crypto-js": "^4.2.2",
|
|
24
|
+
"typescript": "^5.3.0",
|
|
25
|
+
"vite": "^6.4.1",
|
|
26
|
+
"vite-plugin-dts": "^3.9.1"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"ai",
|
|
30
|
+
"provider",
|
|
31
|
+
"openai",
|
|
32
|
+
"anthropic",
|
|
33
|
+
"gemini",
|
|
34
|
+
"deepseek",
|
|
35
|
+
"selector"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"crypto-js": "^4.2.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Selector - API Functions
|
|
3
|
+
* Connection testing and model fetching logic
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Provider,
|
|
8
|
+
Model,
|
|
9
|
+
TestConnectionOptions,
|
|
10
|
+
TestConnectionResult,
|
|
11
|
+
FetchModelsOptions
|
|
12
|
+
} from './types';
|
|
13
|
+
import { getStaticModels } from './models';
|
|
14
|
+
import { getStrategy, defaultParseModelsResponse } from './strategies';
|
|
15
|
+
|
|
16
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Test connection to an AI provider
|
|
20
|
+
*/
|
|
21
|
+
export async function testConnection(options: TestConnectionOptions): Promise<TestConnectionResult> {
|
|
22
|
+
const { provider, apiKey, model, baseUrl, proxyUrl } = options;
|
|
23
|
+
const actualBaseUrl = baseUrl || provider.baseUrl;
|
|
24
|
+
const startTime = Date.now();
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// If proxy URL is provided, use it
|
|
28
|
+
if (proxyUrl) {
|
|
29
|
+
const response = await fetch(`${proxyUrl}/test`, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
provider_id: provider.id,
|
|
34
|
+
api_key: apiKey,
|
|
35
|
+
model: model || '',
|
|
36
|
+
base_url: baseUrl || provider.baseUrl,
|
|
37
|
+
api_format: provider.apiFormat,
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
return {
|
|
42
|
+
success: data.success,
|
|
43
|
+
latencyMs: data.latency_ms || (Date.now() - startTime),
|
|
44
|
+
message: data.message,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Direct API call (for browser-compatible providers)
|
|
49
|
+
const strategy = getStrategy(provider.apiFormat);
|
|
50
|
+
const targetModel = model || '';
|
|
51
|
+
|
|
52
|
+
// If no model provided, we cannot test (user must select model first)
|
|
53
|
+
if (!targetModel) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
latencyMs: 0,
|
|
57
|
+
message: '请先选择模型 (Please select a model)'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const headers = strategy.buildHeaders(apiKey);
|
|
62
|
+
// 使用聊天接口进行测试,发送最简单的请求
|
|
63
|
+
const testPayload = strategy.buildChatPayload(targetModel, [{ role: 'user', content: 'Hi' }]);
|
|
64
|
+
const endpoint = strategy.getChatEndpoint(actualBaseUrl, apiKey, targetModel);
|
|
65
|
+
|
|
66
|
+
const response = await fetch(endpoint, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers,
|
|
69
|
+
body: JSON.stringify(testPayload),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const latencyMs = Date.now() - startTime;
|
|
73
|
+
|
|
74
|
+
if (response.ok) {
|
|
75
|
+
return { success: true, latencyMs, message: '连接成功' };
|
|
76
|
+
} else {
|
|
77
|
+
const errorText = await response.text();
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
latencyMs,
|
|
81
|
+
message: `HTTP ${response.status}: ${errorText.slice(0, 200)}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
latencyMs: Date.now() - startTime,
|
|
88
|
+
message: error instanceof Error ? error.message : String(error),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Fetch available models from a provider
|
|
95
|
+
*/
|
|
96
|
+
export async function fetchModels(options: FetchModelsOptions): Promise<Model[]> {
|
|
97
|
+
const { provider, apiKey, baseUrl, proxyUrl, fallbackToStatic = true } = options;
|
|
98
|
+
|
|
99
|
+
// If proxy URL is provided, use it
|
|
100
|
+
if (proxyUrl) {
|
|
101
|
+
try {
|
|
102
|
+
const response = await fetch(`${proxyUrl}/models`, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: { 'Content-Type': 'application/json' },
|
|
105
|
+
body: JSON.stringify({
|
|
106
|
+
provider_id: provider.id,
|
|
107
|
+
api_key: apiKey || undefined,
|
|
108
|
+
base_url: baseUrl || provider.baseUrl,
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
const data = await response.json();
|
|
112
|
+
if (data.success && data.models?.length > 0) {
|
|
113
|
+
return data.models;
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.warn('Failed to fetch models via proxy:', error);
|
|
117
|
+
if (!fallbackToStatic) throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Direct API call
|
|
122
|
+
if (!proxyUrl && provider.supportsModelsApi) {
|
|
123
|
+
try {
|
|
124
|
+
const strategy = getStrategy(provider.apiFormat);
|
|
125
|
+
if (strategy.getModelsEndpoint) {
|
|
126
|
+
const endpoint = strategy.getModelsEndpoint(baseUrl || provider.baseUrl, apiKey || '');
|
|
127
|
+
const headers = strategy.buildHeaders(apiKey || '');
|
|
128
|
+
|
|
129
|
+
const response = await fetch(endpoint, {
|
|
130
|
+
method: 'GET',
|
|
131
|
+
headers
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (response.ok) {
|
|
135
|
+
const data = await response.json();
|
|
136
|
+
const parser = strategy.parseModelsResponse || defaultParseModelsResponse;
|
|
137
|
+
return parser(data);
|
|
138
|
+
} else {
|
|
139
|
+
// 解析响应体获取详细错误信息
|
|
140
|
+
const body = await response.json().catch(() => ({}));
|
|
141
|
+
const errorMsg = body.error?.message || `HTTP ${response.status}`;
|
|
142
|
+
console.warn('Model fetch failed:', errorMsg);
|
|
143
|
+
if (!fallbackToStatic) throw new Error(errorMsg);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.warn('Failed to fetch models directly:', e);
|
|
148
|
+
if (!fallbackToStatic) throw e;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!fallbackToStatic && provider.supportsModelsApi) {
|
|
153
|
+
throw new Error('Failed to fetch models');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Fallback to static models
|
|
157
|
+
return getStaticModels(provider.id);
|
|
158
|
+
}
|