@ganziliang/kb-model-setup 0.1.0 → 0.1.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/dist/index.js +107 -13
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1,19 +1,113 @@
|
|
|
1
|
+
const gatewayHost = "https://llm-gateway.zhizhengroup.com";
|
|
2
|
+
const statsUrl = `${gatewayHost}/apiStats/api/user-stats`;
|
|
1
3
|
const protocols = ["openai-responses", "anthropic-messages"];
|
|
4
|
+
function parseApiId(value) {
|
|
5
|
+
const input = value.trim();
|
|
6
|
+
if (!input)
|
|
7
|
+
throw new Error("apiId 不能为空");
|
|
8
|
+
if (input.includes("apiId=")) {
|
|
9
|
+
try {
|
|
10
|
+
const apiId = new URL(input).searchParams.get("apiId");
|
|
11
|
+
if (apiId)
|
|
12
|
+
return apiId;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new Error("无法解析 api-stats 页面地址");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (!/^[0-9a-f-]{20,}$/i.test(input)) {
|
|
19
|
+
throw new Error("apiId 格式不正确,请粘贴 api-stats 地址或 apiId 参数值");
|
|
20
|
+
}
|
|
21
|
+
return input;
|
|
22
|
+
}
|
|
23
|
+
function modelId(value) {
|
|
24
|
+
if (typeof value === "string")
|
|
25
|
+
return value.trim() || undefined;
|
|
26
|
+
if (!value || typeof value !== "object")
|
|
27
|
+
return undefined;
|
|
28
|
+
const item = value;
|
|
29
|
+
const id = item.id || item.model || item.modelId || item.name;
|
|
30
|
+
return typeof id === "string" && id.trim() ? id.trim() : undefined;
|
|
31
|
+
}
|
|
32
|
+
function modelList(value) {
|
|
33
|
+
if (Array.isArray(value))
|
|
34
|
+
return value;
|
|
35
|
+
if (!value || typeof value !== "object")
|
|
36
|
+
return [];
|
|
37
|
+
return Object.values(value).flatMap((entry) => Array.isArray(entry) ? entry : [entry]);
|
|
38
|
+
}
|
|
39
|
+
function availableModels(payload) {
|
|
40
|
+
const data = payload.data;
|
|
41
|
+
const models = data?.availableModels;
|
|
42
|
+
const toModels = (value) => {
|
|
43
|
+
const result = [];
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
for (const entry of modelList(value)) {
|
|
46
|
+
const id = modelId(entry);
|
|
47
|
+
if (!id || seen.has(id))
|
|
48
|
+
continue;
|
|
49
|
+
seen.add(id);
|
|
50
|
+
result.push({ id, ...(entry && typeof entry === "object" ? entry : {}) });
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
openai: toModels(models?.openai).filter((model) => model.id.toLowerCase().startsWith("gpt")),
|
|
56
|
+
anthropic: toModels(models?.anthropic ?? models?.availableModels).filter((model) => !model.id.toLowerCase().startsWith("gpt")),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function fetchAvailableModels(apiId) {
|
|
60
|
+
const response = await fetch(statsUrl, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: {
|
|
63
|
+
accept: "application/json, text/plain, */*",
|
|
64
|
+
"content-type": "application/json",
|
|
65
|
+
origin: gatewayHost,
|
|
66
|
+
referer: `${gatewayHost}/admin-next/api-stats?apiId=${encodeURIComponent(apiId)}`,
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify({ apiId }),
|
|
69
|
+
});
|
|
70
|
+
const body = await response.text();
|
|
71
|
+
let payload;
|
|
72
|
+
try {
|
|
73
|
+
payload = JSON.parse(body);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
throw new Error(`模型查询接口返回了非 JSON 响应(HTTP ${response.status})`);
|
|
77
|
+
}
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
const item = payload && typeof payload === "object" ? payload : {};
|
|
80
|
+
throw new Error(`模型查询失败(HTTP ${response.status})${item.message ? `:${String(item.message)}` : ""}`);
|
|
81
|
+
}
|
|
82
|
+
if (!payload || typeof payload !== "object")
|
|
83
|
+
throw new Error("模型查询接口返回格式不正确");
|
|
84
|
+
const result = payload;
|
|
85
|
+
if (result.success === false)
|
|
86
|
+
throw new Error(String(result.message || result.error || "模型查询失败"));
|
|
87
|
+
return availableModels(result);
|
|
88
|
+
}
|
|
2
89
|
export function createModelSetupExtension() {
|
|
3
90
|
return {
|
|
4
|
-
async configure(prompter
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
91
|
+
async configure(prompter) {
|
|
92
|
+
const apiIdInput = await prompter.ask("粘贴 api-stats 页面地址或 apiId:", "https://llm-gateway.zhizhengroup.com/admin-next/api-stats?apiId=...");
|
|
93
|
+
if (!apiIdInput.trim())
|
|
94
|
+
throw new Error("未提供 apiId");
|
|
95
|
+
const apiId = parseApiId(apiIdInput);
|
|
96
|
+
await prompter.notice("正在查询账户和可用模型……");
|
|
97
|
+
const models = await fetchAvailableModels(apiId);
|
|
98
|
+
const preferredOpenAI = models.openai.find((model) => model.id.toLowerCase() === "gpt-5.6-luna") ?? models.openai[0];
|
|
99
|
+
const selected = preferredOpenAI
|
|
100
|
+
? { provider: "company-gpt", api: "openai-responses", model: preferredOpenAI.id, baseURL: `${gatewayHost}/openai` }
|
|
101
|
+
: models.anthropic[0]
|
|
102
|
+
? { provider: "company-anthropic", api: "anthropic-messages", model: models.anthropic[0].id, baseURL: `${gatewayHost}/api` }
|
|
103
|
+
: undefined;
|
|
104
|
+
if (!selected)
|
|
105
|
+
throw new Error("接口返回中没有发现可用模型");
|
|
106
|
+
await prompter.notice(`已发现模型,默认使用 ${selected.provider}/${selected.model}`);
|
|
107
|
+
const apiKey = await prompter.ask("请输入 API Key:", "API Key");
|
|
108
|
+
if (!apiKey.trim())
|
|
109
|
+
throw new Error("API Key 不能为空");
|
|
110
|
+
return { ...selected, apiKey: apiKey.trim() };
|
|
17
111
|
},
|
|
18
112
|
validate(config) {
|
|
19
113
|
const errors = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ganziliang/kb-model-setup",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Interactive model configuration for the kb local knowledge base agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"files": [
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
15
17
|
"scripts": {
|
|
16
18
|
"build": "tsc -p tsconfig.json",
|
|
17
19
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
20
|
"test": "npm run build && node --test"
|
|
19
21
|
},
|
|
20
|
-
"engines": {
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22.5.0"
|
|
24
|
+
},
|
|
21
25
|
"devDependencies": {
|
|
22
26
|
"@types/node": "^22.10.0",
|
|
23
27
|
"typescript": "^5.7.2"
|