@visiblebase/core 0.2.0 → 0.2.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/bin/core/base/base.d.ts +8 -40
- package/bin/core/base/base.d.ts.map +1 -1
- package/bin/core/base/base.js +154 -96
- package/bin/core/base/base.js.map +1 -1
- package/bin/core/runtime.d.ts +10 -0
- package/bin/core/runtime.d.ts.map +1 -1
- package/bin/index.d.ts +5 -14
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +5 -14
- package/bin/index.js.map +1 -1
- package/bin/service/action.d.ts +44 -0
- package/bin/service/action.d.ts.map +1 -0
- package/bin/service/action.js +48 -0
- package/bin/service/action.js.map +1 -0
- package/bin/service/ai/ai-service.d.ts +21 -57
- package/bin/service/ai/ai-service.d.ts.map +1 -1
- package/bin/service/ai/ai-service.js +107 -105
- package/bin/service/ai/ai-service.js.map +1 -1
- package/bin/service/ai/provider.d.ts +24 -58
- package/bin/service/ai/provider.d.ts.map +1 -1
- package/bin/service/ai/provider.js +20 -41
- package/bin/service/ai/provider.js.map +1 -1
- package/bin/service/ai/types.d.ts +39 -35
- package/bin/service/ai/types.d.ts.map +1 -1
- package/bin/service/ai/types.js +1 -1
- package/bin/service/env/env-service.d.ts +0 -4
- package/bin/service/env/env-service.d.ts.map +1 -1
- package/bin/service/env/env-service.js +12 -22
- package/bin/service/env/env-service.js.map +1 -1
- package/bin/service/hook.d.ts +8 -5
- package/bin/service/hook.d.ts.map +1 -1
- package/bin/service/hook.js +11 -14
- package/bin/service/hook.js.map +1 -1
- package/bin/service/plugin.d.ts +12 -94
- package/bin/service/plugin.d.ts.map +1 -1
- package/bin/service/plugin.js +22 -59
- package/bin/service/plugin.js.map +1 -1
- package/bin/service/products/products-service.d.ts +0 -5
- package/bin/service/products/products-service.d.ts.map +1 -1
- package/bin/service/products/products-service.js +14 -20
- package/bin/service/products/products-service.js.map +1 -1
- package/bin/service/service.d.ts +59 -64
- package/bin/service/service.d.ts.map +1 -1
- package/bin/service/service.js +34 -80
- package/bin/service/service.js.map +1 -1
- package/bin/service/types.d.ts +2 -8
- package/bin/service/types.d.ts.map +1 -1
- package/bin/store/db.d.ts +5 -4
- package/bin/store/db.d.ts.map +1 -1
- package/bin/store/db.js +3 -2
- package/bin/store/db.js.map +1 -1
- package/package.json +8 -9
package/bin/index.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @visiblebase/core 公共入口。
|
|
3
|
-
*
|
|
4
|
-
* 按使用场景组织导出,方便开发者按需查找。
|
|
5
|
-
*
|
|
6
|
-
* 使用方式:
|
|
7
|
-
* ```ts
|
|
8
|
-
* import { Base, Service, AIService, type Context } from "@visiblebase/core";
|
|
9
|
-
* import { node } from "@visiblebase/node";
|
|
10
|
-
*
|
|
11
|
-
* const base = new Base({ runtime: node({ database: "sqlite:./data.sqlite" }) });
|
|
12
|
-
* ```
|
|
13
3
|
*/
|
|
14
4
|
// ===========================================================================
|
|
15
5
|
// 场景 1:创建 Base 实例
|
|
@@ -20,26 +10,27 @@ export { Base, VisibleBase } from "./core/base/base.js";
|
|
|
20
10
|
// ===========================================================================
|
|
21
11
|
export { Service } from "./service/service.js";
|
|
22
12
|
export { Plugin } from "./service/plugin.js";
|
|
13
|
+
export { Action } from "./service/action.js";
|
|
23
14
|
export { AIService } from "./service/ai/ai-service.js";
|
|
24
15
|
export { Provider } from "./service/ai/provider.js";
|
|
25
16
|
// ===========================================================================
|
|
26
|
-
// 场景
|
|
17
|
+
// 场景 3:用户鉴权与 Token
|
|
27
18
|
// ===========================================================================
|
|
28
19
|
export { TokenSigner } from "./core/auth/token-signer.js";
|
|
29
20
|
// ===========================================================================
|
|
30
|
-
// 场景
|
|
21
|
+
// 场景 4:管理 Product 与环境变量(内置 Service)
|
|
31
22
|
// ===========================================================================
|
|
32
23
|
export { EnvService } from "./service/env/env-service.js";
|
|
33
24
|
export { EnvStore } from "./service/env/env-store.js";
|
|
34
25
|
export { ProductsService } from "./service/products/products-service.js";
|
|
35
26
|
export { executeDDL } from "./store/db.js";
|
|
36
27
|
// ===========================================================================
|
|
37
|
-
// 场景
|
|
28
|
+
// 场景 6:内置表 Schema
|
|
38
29
|
// ===========================================================================
|
|
39
30
|
export { sqliteProducts, pgProducts } from "./service/products/schema.js";
|
|
40
31
|
export { sqliteEnv, pgEnv } from "./service/env/schema.js";
|
|
41
32
|
// ===========================================================================
|
|
42
|
-
// 场景
|
|
33
|
+
// 场景 7:工具函数
|
|
43
34
|
// ===========================================================================
|
|
44
35
|
export { randomSecret, base64UrlEncode, base64UrlDecode, base64UrlEncodeBytes, base64UrlDecodeBytes, timingSafeEqualBytes, httpError, normalizeEnvKey, bearerToken, parseDotenvEntries, } from "./utils/helpers.js";
|
|
45
36
|
//# sourceMappingURL=index.js.map
|
package/bin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIxD,8EAA8E;AAC9E,mCAAmC;AACnC,8EAA8E;AAE9E,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAmB7C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAQpD,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAS1D,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAQzE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE3D,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,SAAS,EACT,eAAe,EACf,WAAW,EACX,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action 模块。
|
|
3
|
+
*
|
|
4
|
+
* Action 是 Service 的一等能力单元。
|
|
5
|
+
* 每个 Action 有独立的 hook(before/after/onError),可独立被 client 调用。
|
|
6
|
+
*
|
|
7
|
+
* 使用方式:
|
|
8
|
+
* ```ts
|
|
9
|
+
* const zh2en = translateService.action("zh2en", async (ctx) => {
|
|
10
|
+
* return await translate(ctx.input.text, "zh", "en");
|
|
11
|
+
* });
|
|
12
|
+
* zh2en.before(checkBalance).after(deductFee);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { Hook } from "./hook.js";
|
|
16
|
+
import type { Context } from "./service.js";
|
|
17
|
+
/** Action 的业务逻辑函数 */
|
|
18
|
+
export type ActionFn = (ctx: Context) => unknown | Promise<unknown>;
|
|
19
|
+
/** Action 实例 */
|
|
20
|
+
export declare class Action {
|
|
21
|
+
/** Action 唯一 ID */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
/** Action 独立的 hook(before/after/onError) */
|
|
24
|
+
readonly hook: Hook;
|
|
25
|
+
/** 业务逻辑 */
|
|
26
|
+
private readonly _run;
|
|
27
|
+
constructor(id: string, fn: ActionFn);
|
|
28
|
+
/** 注册 before hook */
|
|
29
|
+
before(fn: HookFn): this;
|
|
30
|
+
/** 注册 after hook */
|
|
31
|
+
after(fn: HookFn): this;
|
|
32
|
+
/** 注册 onError hook */
|
|
33
|
+
onError(fn: HookFn): this;
|
|
34
|
+
/** 执行业务逻辑 */
|
|
35
|
+
run(ctx: Context): Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Hook 回调函数。
|
|
39
|
+
*
|
|
40
|
+
* 接收 Context,不返回值(返回 void 或 Promise<void>)。
|
|
41
|
+
* 如需修改 context,直接在 ctx 上改(如 ctx.output)。
|
|
42
|
+
*/
|
|
43
|
+
export type HookFn = (ctx: Context) => void | Promise<void>;
|
|
44
|
+
//# sourceMappingURL=action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/service/action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAqB;AACrB,MAAM,MAAM,QAAQ,GAAG,CACrB,GAAG,EAAE,OAAO,KACT,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,gBAAgB;AAChB,qBAAa,MAAM;IACjB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,OAAc;IAE3B,WAAW;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAW;gBAEpB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IAKpC,qBAAqB;IACrB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKxB,oBAAoB;IACpB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKvB,sBAAsB;IACtB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKzB,aAAa;IACP,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;CAG1C;AAED;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action 模块。
|
|
3
|
+
*
|
|
4
|
+
* Action 是 Service 的一等能力单元。
|
|
5
|
+
* 每个 Action 有独立的 hook(before/after/onError),可独立被 client 调用。
|
|
6
|
+
*
|
|
7
|
+
* 使用方式:
|
|
8
|
+
* ```ts
|
|
9
|
+
* const zh2en = translateService.action("zh2en", async (ctx) => {
|
|
10
|
+
* return await translate(ctx.input.text, "zh", "en");
|
|
11
|
+
* });
|
|
12
|
+
* zh2en.before(checkBalance).after(deductFee);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { Hook } from "./hook.js";
|
|
16
|
+
/** Action 实例 */
|
|
17
|
+
export class Action {
|
|
18
|
+
/** Action 唯一 ID */
|
|
19
|
+
id;
|
|
20
|
+
/** Action 独立的 hook(before/after/onError) */
|
|
21
|
+
hook = new Hook();
|
|
22
|
+
/** 业务逻辑 */
|
|
23
|
+
_run;
|
|
24
|
+
constructor(id, fn) {
|
|
25
|
+
this.id = id;
|
|
26
|
+
this._run = fn;
|
|
27
|
+
}
|
|
28
|
+
/** 注册 before hook */
|
|
29
|
+
before(fn) {
|
|
30
|
+
this.hook.before(fn);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/** 注册 after hook */
|
|
34
|
+
after(fn) {
|
|
35
|
+
this.hook.after(fn);
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
/** 注册 onError hook */
|
|
39
|
+
onError(fn) {
|
|
40
|
+
this.hook.onError(fn);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/** 执行业务逻辑 */
|
|
44
|
+
async run(ctx) {
|
|
45
|
+
return this._run(ctx);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.js","sourceRoot":"","sources":["../../src/service/action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,gBAAgB;AAChB,MAAM,OAAO,MAAM;IACjB,mBAAmB;IACV,EAAE,CAAS;IACpB,4CAA4C;IACnC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IAE3B,WAAW;IACM,IAAI,CAAW;IAEhC,YAAY,EAAU,EAAE,EAAY;QAClC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,qBAAqB;IACrB,MAAM,CAAC,EAAU;QACf,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,EAAU;QACd,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAsB;IACtB,OAAO,CAAC,EAAU;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,aAAa;IACb,KAAK,CAAC,GAAG,CAAC,GAAY;QACpB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -1,80 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AI Service 模块。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 通过
|
|
4
|
+
* AIService 处理所有 AI 通路(SDK 通路 + OpenAI 兼容通路)。
|
|
5
|
+
* 通过 action() 注册 modality action,通过 resolve() 匹配模型和 action。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - POST /
|
|
11
|
-
* - POST /
|
|
12
|
-
* - POST /
|
|
13
|
-
* - POST /
|
|
14
|
-
* -
|
|
7
|
+
* 鉴权由 Base 在路由入口统一强制执行。
|
|
8
|
+
*
|
|
9
|
+
* 路由(Base 自动生成):
|
|
10
|
+
* - POST /v1/s/ai/text — 文本生成
|
|
11
|
+
* - POST /v1/s/ai/stream — 流式生成
|
|
12
|
+
* - POST /v1/s/ai/image — 图片生成
|
|
13
|
+
* - POST /v1/s/ai/video — 视频生成
|
|
14
|
+
* - POST /v1/s/ai/chat/completions — OpenAI 兼容端点
|
|
15
|
+
* - GET /v1/s/ai/models — 模型列表
|
|
15
16
|
*/
|
|
16
17
|
import { Service } from "../service.js";
|
|
17
|
-
import type {
|
|
18
|
+
import type { ActionFn } from "../action.js";
|
|
18
19
|
import type { ModelConfig, PublicModel } from "./types.js";
|
|
19
|
-
/**
|
|
20
|
-
* AI 模型服务。
|
|
21
|
-
*
|
|
22
|
-
* 继承 Service,构造时自动注册所有模态子路由和模型列表路由。
|
|
23
|
-
*
|
|
24
|
-
* 使用方式:
|
|
25
|
-
* ```ts
|
|
26
|
-
* const ai = new AIService();
|
|
27
|
-
* ai.use(provider.model({ id: "gpt-4o", name: "GPT-4o" }));
|
|
28
|
-
* base.use(ai);
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
20
|
export declare class AIService extends Service {
|
|
32
|
-
/**
|
|
33
|
-
* 模型注册表,key 为 model id。
|
|
34
|
-
*/
|
|
21
|
+
/** 模型注册表 */
|
|
35
22
|
private modelMap;
|
|
23
|
+
/** SDK 通路 action 映射(modality → action) */
|
|
24
|
+
private modalityActions;
|
|
36
25
|
constructor();
|
|
37
|
-
/**
|
|
38
|
-
* 注册一个或多个模型配置。
|
|
39
|
-
*
|
|
40
|
-
* 支持三种调用形式:
|
|
41
|
-
* - `use(modelConfig)` — 单个
|
|
42
|
-
* - `use([config1, config2])` — 数组
|
|
43
|
-
* - `use(config1, config2)` — 展开参数
|
|
44
|
-
*/
|
|
45
26
|
use(...inputs: (ModelConfig | ModelConfig[])[]): this;
|
|
46
|
-
/**
|
|
47
|
-
* 返回所有已注册的模型配置。
|
|
48
|
-
*/
|
|
49
27
|
listModels(): ModelConfig[];
|
|
50
|
-
|
|
51
|
-
* 是否有已注册的 handler。
|
|
52
|
-
*/
|
|
53
|
-
hasHandler(): boolean;
|
|
54
|
-
/**
|
|
55
|
-
* 根据查询参数匹配模型和对应的 handler。
|
|
56
|
-
*
|
|
57
|
-
* 匹配优先级:
|
|
58
|
-
* 1. 指定 model → 精确匹配 modelMap
|
|
59
|
-
* 2. 未指定 model → 该 mode 的默认模型
|
|
60
|
-
* 3. 都没有 → 第一个注册的模型(兜底)
|
|
61
|
-
*/
|
|
28
|
+
hasAction(): boolean;
|
|
62
29
|
resolve(query: {
|
|
63
30
|
model?: string;
|
|
64
31
|
mode?: string;
|
|
65
32
|
}): {
|
|
66
33
|
model?: ModelConfig;
|
|
67
|
-
|
|
34
|
+
action: ActionFn;
|
|
68
35
|
};
|
|
69
|
-
private
|
|
36
|
+
private getAction;
|
|
37
|
+
private resolveOpenAIAction;
|
|
38
|
+
private createAutoPassthroughAction;
|
|
70
39
|
private findDefaultForMode;
|
|
71
|
-
/**
|
|
72
|
-
* 处理单个模态的 HTTP 请求。
|
|
73
|
-
*/
|
|
74
40
|
private handleModality;
|
|
75
|
-
|
|
76
|
-
* 从 AIService 实例中聚合公开模型列表。
|
|
77
|
-
*/
|
|
41
|
+
private handleChatCompletions;
|
|
78
42
|
static listModels(aiService: AIService): PublicModel[];
|
|
79
43
|
}
|
|
80
44
|
//# sourceMappingURL=ai-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-service.d.ts","sourceRoot":"","sources":["../../../src/service/ai/ai-service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ai-service.d.ts","sourceRoot":"","sources":["../../../src/service/ai/ai-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAC;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EACZ,MAAM,YAAY,CAAC;AAcpB,qBAAa,SAAU,SAAQ,OAAO;IACpC,YAAY;IACZ,OAAO,CAAC,QAAQ,CAAkC;IAElD,0CAA0C;IAC1C,OAAO,CAAC,eAAe,CAA+B;;IAoBtD,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC,WAAW,GAAG,WAAW,EAAE,CAAC,EAAE,GAAG,IAAI;IAarD,UAAU,IAAI,WAAW,EAAE;IAI3B,SAAS,IAAI,OAAO;IAMpB,OAAO,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,KAAK,CAAC,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,QAAQ,CAAA;KAAE;IA4B5F,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,2BAA2B;IAmCnC,OAAO,CAAC,kBAAkB;YAWZ,cAAc;YAiBd,qBAAqB;IAmBnC,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,WAAW,EAAE;CAMvD"}
|
|
@@ -1,124 +1,135 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AI Service 模块。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 通过
|
|
4
|
+
* AIService 处理所有 AI 通路(SDK 通路 + OpenAI 兼容通路)。
|
|
5
|
+
* 通过 action() 注册 modality action,通过 resolve() 匹配模型和 action。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - POST /
|
|
11
|
-
* - POST /
|
|
12
|
-
* - POST /
|
|
13
|
-
* - POST /
|
|
14
|
-
* -
|
|
7
|
+
* 鉴权由 Base 在路由入口统一强制执行。
|
|
8
|
+
*
|
|
9
|
+
* 路由(Base 自动生成):
|
|
10
|
+
* - POST /v1/s/ai/text — 文本生成
|
|
11
|
+
* - POST /v1/s/ai/stream — 流式生成
|
|
12
|
+
* - POST /v1/s/ai/image — 图片生成
|
|
13
|
+
* - POST /v1/s/ai/video — 视频生成
|
|
14
|
+
* - POST /v1/s/ai/chat/completions — OpenAI 兼容端点
|
|
15
|
+
* - GET /v1/s/ai/models — 模型列表
|
|
15
16
|
*/
|
|
16
17
|
import { Service } from "../service.js";
|
|
17
18
|
import { httpError } from "../../utils/helpers.js";
|
|
18
|
-
/** AIService
|
|
19
|
+
/** AIService 支持的 SDK 通路模态列表 */
|
|
19
20
|
const MODALITIES = ["text", "stream", "image", "video", "tts", "asr"];
|
|
20
21
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* 继承 Service,构造时自动注册所有模态子路由和模型列表路由。
|
|
24
|
-
*
|
|
25
|
-
* 使用方式:
|
|
26
|
-
* ```ts
|
|
27
|
-
* const ai = new AIService();
|
|
28
|
-
* ai.use(provider.model({ id: "gpt-4o", name: "GPT-4o" }));
|
|
29
|
-
* base.use(ai);
|
|
30
|
-
* ```
|
|
22
|
+
* 判断一个值是否为 HTTP Response。
|
|
31
23
|
*/
|
|
24
|
+
function isResponse(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && "status" in value && "headers" in value;
|
|
26
|
+
}
|
|
32
27
|
export class AIService extends Service {
|
|
33
|
-
/**
|
|
34
|
-
* 模型注册表,key 为 model id。
|
|
35
|
-
*/
|
|
28
|
+
/** 模型注册表 */
|
|
36
29
|
modelMap = new Map();
|
|
30
|
+
/** SDK 通路 action 映射(modality → action) */
|
|
31
|
+
modalityActions = new Map();
|
|
37
32
|
constructor() {
|
|
38
33
|
super({ id: "ai", name: "AI" });
|
|
39
|
-
//
|
|
34
|
+
// 为每个 modality 注册 routing action
|
|
40
35
|
for (const modality of MODALITIES) {
|
|
41
|
-
this.
|
|
36
|
+
this.action(modality, async (ctx) => this.handleModality(modality, ctx));
|
|
42
37
|
}
|
|
43
|
-
//
|
|
44
|
-
this.
|
|
38
|
+
// OpenAI 兼容端点
|
|
39
|
+
this.action("chat/completions", async (ctx) => this.handleChatCompletions(ctx));
|
|
40
|
+
// 模型列表(GET 路由 — Base 自动处理,AIService 通过在 Base 层面注册 GET 路由)
|
|
41
|
+
// 暂时保持 models 通过 POST 也可以访问,后续优化
|
|
42
|
+
this.action("models", () => ({ items: AIService.listModels(this) }), { method: "GET", auth: "user" });
|
|
45
43
|
}
|
|
46
44
|
// ========== 模型注册 ==========
|
|
47
|
-
/**
|
|
48
|
-
* 注册一个或多个模型配置。
|
|
49
|
-
*
|
|
50
|
-
* 支持三种调用形式:
|
|
51
|
-
* - `use(modelConfig)` — 单个
|
|
52
|
-
* - `use([config1, config2])` — 数组
|
|
53
|
-
* - `use(config1, config2)` — 展开参数
|
|
54
|
-
*/
|
|
55
45
|
use(...inputs) {
|
|
56
46
|
const configs = [];
|
|
57
47
|
for (const input of inputs) {
|
|
58
|
-
if (Array.isArray(input))
|
|
48
|
+
if (Array.isArray(input))
|
|
59
49
|
configs.push(...input);
|
|
60
|
-
|
|
61
|
-
else {
|
|
50
|
+
else
|
|
62
51
|
configs.push(input);
|
|
63
|
-
}
|
|
64
52
|
}
|
|
65
53
|
for (const config of configs) {
|
|
66
|
-
if (this.modelMap.has(config.id))
|
|
54
|
+
if (this.modelMap.has(config.id))
|
|
67
55
|
throw new Error(`Duplicate model: ${config.id}`);
|
|
68
|
-
}
|
|
69
56
|
this.modelMap.set(config.id, config);
|
|
70
57
|
}
|
|
71
58
|
return this;
|
|
72
59
|
}
|
|
73
|
-
/**
|
|
74
|
-
* 返回所有已注册的模型配置。
|
|
75
|
-
*/
|
|
76
60
|
listModels() {
|
|
77
61
|
return [...this.modelMap.values()];
|
|
78
62
|
}
|
|
79
|
-
|
|
80
|
-
* 是否有已注册的 handler。
|
|
81
|
-
*/
|
|
82
|
-
hasHandler() {
|
|
63
|
+
hasAction() {
|
|
83
64
|
return this.modelMap.size > 0;
|
|
84
65
|
}
|
|
85
66
|
// ========== 模型匹配 ==========
|
|
86
|
-
/**
|
|
87
|
-
* 根据查询参数匹配模型和对应的 handler。
|
|
88
|
-
*
|
|
89
|
-
* 匹配优先级:
|
|
90
|
-
* 1. 指定 model → 精确匹配 modelMap
|
|
91
|
-
* 2. 未指定 model → 该 mode 的默认模型
|
|
92
|
-
* 3. 都没有 → 第一个注册的模型(兜底)
|
|
93
|
-
*/
|
|
94
67
|
resolve(query) {
|
|
95
68
|
const { model: modelId, mode } = query;
|
|
69
|
+
const isOpenAIMode = mode === "openai";
|
|
96
70
|
if (modelId) {
|
|
97
71
|
const model = this.modelMap.get(modelId);
|
|
98
72
|
if (!model)
|
|
99
73
|
throw httpError(422, `Unknown model: ${modelId}`);
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
74
|
+
const action = isOpenAIMode ? this.resolveOpenAIAction(model) : this.getAction(model, mode);
|
|
75
|
+
if (!action)
|
|
102
76
|
throw httpError(422, `Model ${modelId} does not support mode: ${mode ?? "text"}`);
|
|
103
|
-
return { model,
|
|
77
|
+
return { model, action };
|
|
104
78
|
}
|
|
105
79
|
const defaultModel = this.findDefaultForMode(mode);
|
|
106
80
|
if (defaultModel) {
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
return { model: defaultModel,
|
|
81
|
+
const action = isOpenAIMode ? this.resolveOpenAIAction(defaultModel) : this.getAction(defaultModel, mode);
|
|
82
|
+
if (action)
|
|
83
|
+
return { model: defaultModel, action };
|
|
110
84
|
}
|
|
111
85
|
const first = this.modelMap.values().next().value;
|
|
112
86
|
if (first) {
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
return { model: first,
|
|
116
|
-
throw httpError(422, `No
|
|
87
|
+
const action = isOpenAIMode ? this.resolveOpenAIAction(first) : this.getAction(first, mode);
|
|
88
|
+
if (action)
|
|
89
|
+
return { model: first, action };
|
|
90
|
+
throw httpError(422, `No action for mode: ${mode ?? "text"}`);
|
|
117
91
|
}
|
|
118
92
|
throw httpError(422, `No model registered`);
|
|
119
93
|
}
|
|
120
|
-
|
|
121
|
-
return model.
|
|
94
|
+
getAction(model, mode) {
|
|
95
|
+
return model.actions[(mode ?? "text")];
|
|
96
|
+
}
|
|
97
|
+
resolveOpenAIAction(model) {
|
|
98
|
+
if (model.actions.openai)
|
|
99
|
+
return model.actions.openai;
|
|
100
|
+
if (model.baseURL && model.envKey)
|
|
101
|
+
return this.createAutoPassthroughAction(model);
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
createAutoPassthroughAction(model) {
|
|
105
|
+
const baseURL = model.baseURL;
|
|
106
|
+
const envKey = model.envKey;
|
|
107
|
+
const passthroughModel = model.passthroughModel;
|
|
108
|
+
return async (ctx) => {
|
|
109
|
+
const apiKey = ctx.env(envKey);
|
|
110
|
+
if (!apiKey) {
|
|
111
|
+
return new Response(JSON.stringify({
|
|
112
|
+
error: { message: `${envKey} is required`, type: "authentication_error" },
|
|
113
|
+
}), { status: 401, headers: { "content-type": "application/json" } });
|
|
114
|
+
}
|
|
115
|
+
const body = { ...ctx.input };
|
|
116
|
+
if (passthroughModel) {
|
|
117
|
+
body.model = passthroughModel;
|
|
118
|
+
}
|
|
119
|
+
const response = await fetch(`${baseURL}/chat/completions`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: {
|
|
122
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify(body),
|
|
126
|
+
});
|
|
127
|
+
return new Response(response.body, {
|
|
128
|
+
status: response.status,
|
|
129
|
+
statusText: response.statusText,
|
|
130
|
+
headers: response.headers,
|
|
131
|
+
});
|
|
132
|
+
};
|
|
122
133
|
}
|
|
123
134
|
findDefaultForMode(mode) {
|
|
124
135
|
const m = mode ?? "text";
|
|
@@ -130,54 +141,45 @@ export class AIService extends Service {
|
|
|
130
141
|
}
|
|
131
142
|
return undefined;
|
|
132
143
|
}
|
|
133
|
-
// ==========
|
|
134
|
-
/**
|
|
135
|
-
* 处理单个模态的 HTTP 请求。
|
|
136
|
-
*/
|
|
144
|
+
// ========== SDK 通路 ==========
|
|
137
145
|
async handleModality(modality, ctx) {
|
|
138
|
-
const resolved = this.resolve({
|
|
139
|
-
|
|
140
|
-
mode: modality,
|
|
141
|
-
});
|
|
142
|
-
// 构建 model handler 的 Context(注入 model 信息)
|
|
143
|
-
const aiCtx = {
|
|
144
|
-
...ctx,
|
|
145
|
-
model: resolved.model ? { id: resolved.model.id, name: resolved.model.name } : undefined,
|
|
146
|
-
};
|
|
146
|
+
const resolved = this.resolve({ model: ctx.input.model, mode: modality });
|
|
147
|
+
const aiCtx = { ...ctx, variant: resolved.model ? { id: resolved.model.id, name: resolved.model.name, meta: resolved.model.meta } : undefined };
|
|
147
148
|
try {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
await this.hook.runAfter(beforeCtx);
|
|
151
|
-
if (output instanceof Response)
|
|
149
|
+
const output = await resolved.action(aiCtx);
|
|
150
|
+
if (isResponse(output))
|
|
152
151
|
return output;
|
|
153
152
|
return output;
|
|
154
153
|
}
|
|
155
154
|
catch (error) {
|
|
156
|
-
await this.hook.runOnError(aiCtx);
|
|
157
155
|
const message = error instanceof Error ? error.message : String(error);
|
|
158
156
|
const status = error.statusCode ?? 500;
|
|
159
|
-
return new Response(JSON.stringify({ error: message }), {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
return new Response(JSON.stringify({ error: message }), { status, headers: { "content-type": "application/json" } });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ========== OpenAI 兼容通路 ==========
|
|
161
|
+
async handleChatCompletions(ctx) {
|
|
162
|
+
const body = ctx.input;
|
|
163
|
+
const modelId = body.model;
|
|
164
|
+
const resolved = this.resolve({ model: modelId, mode: "openai" });
|
|
165
|
+
const aiCtx = { ...ctx, input: body, variant: resolved.model ? { id: resolved.model.id, name: resolved.model.name, meta: resolved.model.meta } : undefined };
|
|
166
|
+
try {
|
|
167
|
+
const output = await resolved.action(aiCtx);
|
|
168
|
+
if (isResponse(output))
|
|
169
|
+
return output;
|
|
170
|
+
return new Response(JSON.stringify(output), { status: 200, headers: { "content-type": "application/json" } });
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
174
|
+
const status = error.statusCode ?? 500;
|
|
175
|
+
return new Response(JSON.stringify({ error: { message, type: "server_error" } }), { status, headers: { "content-type": "application/json" } });
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
|
-
// ==========
|
|
166
|
-
/**
|
|
167
|
-
* 从 AIService 实例中聚合公开模型列表。
|
|
168
|
-
*/
|
|
178
|
+
// ========== 模型列表 ==========
|
|
169
179
|
static listModels(aiService) {
|
|
170
180
|
return [...aiService.modelMap.values()].map((config) => {
|
|
171
|
-
const modalities = Object.keys(config.
|
|
172
|
-
return {
|
|
173
|
-
id: config.id,
|
|
174
|
-
name: config.name,
|
|
175
|
-
description: config.description ?? "",
|
|
176
|
-
modalities,
|
|
177
|
-
tags: config.tags ?? [],
|
|
178
|
-
meta: config.meta ?? {},
|
|
179
|
-
env: config.env ?? {},
|
|
180
|
-
};
|
|
181
|
+
const modalities = Object.keys(config.actions).filter((k) => config.actions[k] !== undefined);
|
|
182
|
+
return { id: config.id, name: config.name, description: config.description ?? "", modalities, tags: config.tags ?? [], meta: config.meta ?? {} };
|
|
181
183
|
});
|
|
182
184
|
}
|
|
183
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-service.js","sourceRoot":"","sources":["../../../src/service/ai/ai-service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ai-service.js","sourceRoot":"","sources":["../../../src/service/ai/ai-service.ts"],"names":[],"mappings":"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"}
|