@cloudbase/ai 3.6.5-alpha.0 → 4.0.1-alpha.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/.eslintignore +2 -0
- package/.eslintrc.js +16 -0
- package/CHANGELOG.md +1164 -0
- package/package.json +4 -8
- package/src/AI.ts +191 -0
- package/src/bot/index.ts +278 -0
- package/src/bot/types.ts +165 -0
- package/src/errors.ts +23 -0
- package/src/eventsource_parser/index.ts +2 -0
- package/src/eventsource_parser/parse.ts +169 -0
- package/src/eventsource_parser/stream.ts +35 -0
- package/src/eventsource_parser/types.ts +90 -0
- package/src/index.ts +165 -0
- package/src/models/Ark/index.ts +94 -0
- package/src/models/Ark/type.ts +82 -0
- package/src/models/DashScope/index.ts +97 -0
- package/src/models/DashScope/type.ts +76 -0
- package/src/models/DeepSeek/index.ts +80 -0
- package/src/models/Default/index.ts +70 -0
- package/src/models/HunYuan/index.ts +94 -0
- package/src/models/HunYuan/type.ts +85 -0
- package/src/models/HunYuan/util.ts +60 -0
- package/src/models/HunYuanBeta/index.ts +83 -0
- package/src/models/HunYuanExp/index.ts +80 -0
- package/src/models/HunYuanOpen/index.ts +83 -0
- package/src/models/Moonshot/index.ts +95 -0
- package/src/models/Moonshot/type.ts +82 -0
- package/src/models/Yi/index.ts +100 -0
- package/src/models/Yi/type.ts +77 -0
- package/src/models/ZhiPu/index.ts +104 -0
- package/src/models/ZhiPu/type.ts +71 -0
- package/src/models/image-model.ts +100 -0
- package/src/models/index.ts +41 -0
- package/src/models/model.ts +425 -0
- package/src/type.ts +362 -0
- package/src/utils.ts +198 -0
- package/tsconfig.esm.json +16 -0
- package/tsconfig.json +16 -0
- package/webpack/web.prod.js +100 -0
- package/webpack/webpack.miniprogram.js +24 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/ai",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1-alpha.0",
|
|
4
4
|
"description": "cloudbase js sdk ai module",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"author": "",
|
|
31
31
|
"license": "Apache-2.0",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@cloudbase/types": "
|
|
34
|
-
"@cloudbase/utilities": "
|
|
33
|
+
"@cloudbase/types": "4.0.1-alpha.0",
|
|
34
|
+
"@cloudbase/utilities": "4.0.1-alpha.0",
|
|
35
35
|
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
|
36
36
|
"text-encoding-shim": "^1.0.5",
|
|
37
37
|
"web-streams-polyfill": "^4.0.0"
|
|
@@ -39,9 +39,5 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@cloudbase/adapter-interface": "^0.7.1"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
43
|
-
"types": "dist/cjs/index.d.ts",
|
|
44
|
-
"files": [
|
|
45
|
-
"dist/"
|
|
46
|
-
]
|
|
42
|
+
"gitHead": "f893174f5888080382b515a0a3ba1f4dd8999662"
|
|
47
43
|
}
|
package/src/AI.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* eslint-disable eqeqeq */
|
|
2
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3
|
+
import type { SDKRequestInterface } from '@cloudbase/adapter-interface'
|
|
4
|
+
import { Bot } from './bot'
|
|
5
|
+
import * as models from './models'
|
|
6
|
+
import * as types from './type'
|
|
7
|
+
import { readableStream2JsonObject } from './utils'
|
|
8
|
+
import { ICloudbaseConfig } from '@cloudbase/types'
|
|
9
|
+
import { langEvent } from '@cloudbase/utilities'
|
|
10
|
+
|
|
11
|
+
const { MODELS } = models
|
|
12
|
+
|
|
13
|
+
class AI {
|
|
14
|
+
public bot: Bot
|
|
15
|
+
public i18n: ICloudbaseConfig['i18n']
|
|
16
|
+
defaultHeaders: { [x: string]: any }
|
|
17
|
+
private _getBaseUrl?: () => string
|
|
18
|
+
|
|
19
|
+
/** 动态获取 aiBaseUrl,支持 registerEndPointWithKey 后端点变更生效 */
|
|
20
|
+
get aiBaseUrl(): string {
|
|
21
|
+
return `${this._getBaseUrl ? this._getBaseUrl() : this.baseUrl}/ai`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 动态获取 aiBotBaseUrl,支持 registerEndPointWithKey 后端点变更生效 */
|
|
25
|
+
get aiBotBaseUrl(): string {
|
|
26
|
+
return `${this._getBaseUrl ? this._getBaseUrl() : this.baseUrl}/aibot`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
private req: SDKRequestInterface,
|
|
31
|
+
public baseUrl: string,
|
|
32
|
+
i18n: ICloudbaseConfig['i18n'],
|
|
33
|
+
getBaseUrl?: () => string,
|
|
34
|
+
) {
|
|
35
|
+
this._getBaseUrl = getBaseUrl
|
|
36
|
+
this.bot = new Bot(this.botRequest, this.aiBotBaseUrl)
|
|
37
|
+
this.i18n = i18n
|
|
38
|
+
|
|
39
|
+
langEvent.bus.on(langEvent.LANG_CHANGE_EVENT, (params) => {
|
|
40
|
+
this.i18n = params.data?.i18n || this.i18n
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async handleResponseData(responseData: Promise<unknown> | ReadableStream<Uint8Array>, header?: Headers) {
|
|
45
|
+
const GO_TO_AI_TEXT = `${this.i18n.t('请检查调用方式,或前往云开发 AI+ 首页查看文档')}:https://tcb.cloud.tencent.com/dev#/ai`
|
|
46
|
+
|
|
47
|
+
const throwIfError = (json: unknown) => {
|
|
48
|
+
if (typeof json === 'object' && json && 'code' in json && (json as any).code !== 'NORMAL') {
|
|
49
|
+
throw new Error(`${this.i18n.t('AI+ 请求出错,错误码')}:${(json as any).code},${this.i18n.t('错误信息')}:${
|
|
50
|
+
(json as any).message
|
|
51
|
+
}\n${GO_TO_AI_TEXT}\n${JSON.stringify(json, null, 2)}`,)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 非流式请求:
|
|
56
|
+
// - 小程序/Web 适配器返回 Promise(has 'then')
|
|
57
|
+
// - Node 适配器已将 body 解析为普通对象(无 'then'、无 getReader)
|
|
58
|
+
// 两种情况都按 JSON 校验错误码后原样返回
|
|
59
|
+
if (typeof responseData === 'object' && responseData && typeof (responseData as any).getReader !== 'function') {
|
|
60
|
+
const json = 'then' in responseData ? await responseData : responseData
|
|
61
|
+
throwIfError(json)
|
|
62
|
+
return responseData
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 判断 responseData 是否是 ReadableStream 实例(兼容 Node.js 适配器非流式场景已解析为 JSON 对象的情况)
|
|
66
|
+
const isStream = typeof (responseData as any)?.getReader === 'function'
|
|
67
|
+
|
|
68
|
+
if (!isStream) {
|
|
69
|
+
// responseData 已经是解析后的 JSON 对象(如 Node.js 适配器非流式返回),直接检查错误码
|
|
70
|
+
const json = responseData as unknown as Record<string, unknown>
|
|
71
|
+
if (typeof json === 'object' && json && 'code' in json && json.code !== 'NORMAL') {
|
|
72
|
+
throw new Error(`${this.i18n.t('AI+ 请求出错,错误码')}:${json.code},${this.i18n.t('错误信息')}:${
|
|
73
|
+
json.message
|
|
74
|
+
}\n${GO_TO_AI_TEXT}\n${JSON.stringify(json, null, 2)}`,)
|
|
75
|
+
}
|
|
76
|
+
return responseData
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 流式请求,如果接口出错,会变成传 json 格式的响应,通过 header 判断格式
|
|
80
|
+
if (header?.get?.('content-type')?.includes('application/json')) {
|
|
81
|
+
const json = await readableStream2JsonObject(responseData as ReadableStream<Uint8Array>)
|
|
82
|
+
throwIfError(json)
|
|
83
|
+
}
|
|
84
|
+
return responseData
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
createModel(
|
|
88
|
+
model: string,
|
|
89
|
+
options?: {
|
|
90
|
+
defaultModelSubUrl?: string
|
|
91
|
+
},
|
|
92
|
+
) {
|
|
93
|
+
let simpleModel: types.SimpleChatModel
|
|
94
|
+
|
|
95
|
+
const SimpleModelConstructor = MODELS[model]
|
|
96
|
+
if (SimpleModelConstructor) {
|
|
97
|
+
simpleModel = new SimpleModelConstructor(this.modelRequest, this.aiBaseUrl)
|
|
98
|
+
} else {
|
|
99
|
+
const subUrl = typeof options?.defaultModelSubUrl === 'string' ? options.defaultModelSubUrl : '/chat/completions'
|
|
100
|
+
|
|
101
|
+
simpleModel = new models.DefaultSimpleModel(this.modelRequest, this.aiBaseUrl, `${model}${subUrl}`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const reactModel = new models.ReactModel(simpleModel)
|
|
105
|
+
return reactModel
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
registerModel(name: string, model: types.ChatModelConstructor) {
|
|
109
|
+
if (MODELS[name] != null) {
|
|
110
|
+
console.warn(`AI model ${name} already exists!`)
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
MODELS[name] = model
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
createImageModel<T extends 'hunyuan-image' | (string & {})>(provider: T) {
|
|
117
|
+
return new models.DefaultImageModel<T>(this.modelRequest, this.aiBaseUrl, provider)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
modelRequest: types.ModelReq = async ({ url, data, headers, stream, timeout }) => {
|
|
121
|
+
const fetchHeaders = {
|
|
122
|
+
'Content-Type': 'application/json',
|
|
123
|
+
}
|
|
124
|
+
// 带 Accept: text/event-stream 请求头显式指定是 SSE 绕过 60s 的限制
|
|
125
|
+
stream && Object.assign(fetchHeaders, { Accept: 'text/event-stream' })
|
|
126
|
+
|
|
127
|
+
const { data: responseData, header } = (await this.req.fetch({
|
|
128
|
+
method: 'post',
|
|
129
|
+
headers: { [this.i18n?.LANG_HEADER_KEY]: this.i18n?.lang, ...fetchHeaders, ...headers },
|
|
130
|
+
body: JSON.stringify(data),
|
|
131
|
+
url: this.resolveUrl(url),
|
|
132
|
+
stream,
|
|
133
|
+
timeout,
|
|
134
|
+
})) as { data: Promise<unknown> | ReadableStream<Uint8Array>; header?: Headers }
|
|
135
|
+
|
|
136
|
+
return this.handleResponseData(responseData, header) as any
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
botRequest: types.BotReq = async ({ method, url, data = {}, headers, stream, timeout }) => {
|
|
140
|
+
const resolvedUrl = this.resolveUrl(url)
|
|
141
|
+
if (method === 'get') {
|
|
142
|
+
return this.handleResponseData((await this.req.fetch({ url: `${resolvedUrl}?${objectToParam(data)}`, method, headers, stream, timeout })).data,)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const fetchHeaders = {
|
|
146
|
+
'Content-Type': 'application/json',
|
|
147
|
+
}
|
|
148
|
+
// 带 Accept: text/event-stream 请求头显式指定是 SSE 绕过 60s 的限制
|
|
149
|
+
stream && Object.assign(fetchHeaders, { Accept: 'text/event-stream' })
|
|
150
|
+
|
|
151
|
+
const { data: responseData, header } = (await this.req.fetch({
|
|
152
|
+
url: resolvedUrl,
|
|
153
|
+
body: JSON.stringify(data),
|
|
154
|
+
headers: {
|
|
155
|
+
[this.i18n?.LANG_HEADER_KEY]: this.i18n?.lang,
|
|
156
|
+
...fetchHeaders,
|
|
157
|
+
...headers,
|
|
158
|
+
},
|
|
159
|
+
stream,
|
|
160
|
+
method,
|
|
161
|
+
timeout,
|
|
162
|
+
})) as { data: Promise<unknown> | ReadableStream<Uint8Array>; header?: Headers }
|
|
163
|
+
|
|
164
|
+
return this.handleResponseData(responseData, header) as any
|
|
165
|
+
|
|
166
|
+
function objectToParam(obj: Object) {
|
|
167
|
+
return Object.entries(obj)
|
|
168
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
169
|
+
.join('&')
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
registerFunctionTool(functionTool: types.FunctionTool) {
|
|
174
|
+
if (models.toolMap.has(functionTool.name)) {
|
|
175
|
+
console.warn(`AI function tool ${functionTool.name} already exists and will be overwritten!`)
|
|
176
|
+
}
|
|
177
|
+
models.toolMap.set(functionTool.name, functionTool.fn)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** 动态替换 URL 中的 origin 部分,支持 registerEndPointWithKey 后生效 */
|
|
181
|
+
private resolveUrl(url: string): string {
|
|
182
|
+
if (!this._getBaseUrl) return url
|
|
183
|
+
const currentBase = this._getBaseUrl()
|
|
184
|
+
if (currentBase !== this.baseUrl && url.startsWith(this.baseUrl)) {
|
|
185
|
+
return url.replace(this.baseUrl, currentBase)
|
|
186
|
+
}
|
|
187
|
+
return url
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { AI }
|
package/src/bot/index.ts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { type ParsedEvent } from '../eventsource_parser'
|
|
2
|
+
import { BotReq, ReqOptions } from '../type'
|
|
3
|
+
import {
|
|
4
|
+
IBotCreateConversation,
|
|
5
|
+
IBotDeleteConversation,
|
|
6
|
+
IBotGetConversation,
|
|
7
|
+
IBotGetTextToSpeechResult,
|
|
8
|
+
IBotPreview,
|
|
9
|
+
IBotSendMessage,
|
|
10
|
+
IBotSpeechToText,
|
|
11
|
+
IBotTextToSpeech,
|
|
12
|
+
IBotUploadFiles,
|
|
13
|
+
ICreateBot,
|
|
14
|
+
IDeleteBot,
|
|
15
|
+
IGenerateBot,
|
|
16
|
+
IGenerateImage,
|
|
17
|
+
IGetBot,
|
|
18
|
+
IGetBotChatRecords,
|
|
19
|
+
IGetBotFeedback,
|
|
20
|
+
IGetBotList,
|
|
21
|
+
IGetBotRecommendQuestions,
|
|
22
|
+
ISendBotFeedback,
|
|
23
|
+
IUpdateBot,
|
|
24
|
+
} from './types'
|
|
25
|
+
import {
|
|
26
|
+
createAsyncIterable,
|
|
27
|
+
toPolyfillReadable,
|
|
28
|
+
createEventSourceParserTransformStream,
|
|
29
|
+
TextDecoderStream,
|
|
30
|
+
TransformStream,
|
|
31
|
+
} from '../utils'
|
|
32
|
+
|
|
33
|
+
export class Bot {
|
|
34
|
+
req: BotReq
|
|
35
|
+
|
|
36
|
+
constructor(req: BotReq, public baseUrl: string) {
|
|
37
|
+
// eslint-disable-next-line prefer-rest-params
|
|
38
|
+
const token = arguments[2]
|
|
39
|
+
if (typeof token === 'string') {
|
|
40
|
+
this.req = ({ headers = {}, ...rest }) => req({ ...rest, headers: { ...headers, Authorization: `Bearer ${token}` } })
|
|
41
|
+
} else {
|
|
42
|
+
this.req = req
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
list(props: IGetBotList, options?: ReqOptions) {
|
|
47
|
+
return this.req({
|
|
48
|
+
method: 'get',
|
|
49
|
+
url: this.join('bots'),
|
|
50
|
+
data: props,
|
|
51
|
+
timeout: options?.timeout,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
create({ botInfo }: ICreateBot, options?: ReqOptions) {
|
|
56
|
+
return this.req({
|
|
57
|
+
method: 'post',
|
|
58
|
+
url: this.join('bots'),
|
|
59
|
+
data: botInfo,
|
|
60
|
+
timeout: options?.timeout,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get({ botId }: IGetBot, options?: ReqOptions) {
|
|
65
|
+
return this.req({
|
|
66
|
+
method: 'get',
|
|
67
|
+
url: this.join(`bots/${botId}`),
|
|
68
|
+
timeout: options?.timeout,
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
update({ botId, botInfo }: IUpdateBot, options?: ReqOptions) {
|
|
73
|
+
return this.req({
|
|
74
|
+
method: 'PATCH',
|
|
75
|
+
url: this.join(`bots/${botId}`),
|
|
76
|
+
data: botInfo,
|
|
77
|
+
timeout: options?.timeout,
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
delete({ botId }: IDeleteBot, options?: ReqOptions) {
|
|
82
|
+
return this.req({ method: 'delete', url: this.join(`bots/${botId}`), timeout: options?.timeout })
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getChatRecords(props: IGetBotChatRecords, options?: ReqOptions) {
|
|
86
|
+
return this.req({
|
|
87
|
+
method: 'get',
|
|
88
|
+
url: this.join(`bots/${props.botId}/records`),
|
|
89
|
+
data: props,
|
|
90
|
+
timeout: options?.timeout,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
sendFeedback({ userFeedback }: ISendBotFeedback, options?: ReqOptions) {
|
|
95
|
+
return this.req({
|
|
96
|
+
method: 'post',
|
|
97
|
+
url: this.join(`bots/${userFeedback.botId}/feedback`),
|
|
98
|
+
data: userFeedback,
|
|
99
|
+
timeout: options?.timeout,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getFeedback(props: IGetBotFeedback, options?: ReqOptions) {
|
|
104
|
+
return this.req({
|
|
105
|
+
method: 'get',
|
|
106
|
+
url: this.join(`bots/${props.botId}/feedback`),
|
|
107
|
+
data: props,
|
|
108
|
+
timeout: options?.timeout,
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async uploadFiles(props: IBotUploadFiles, options?: ReqOptions) {
|
|
113
|
+
return this.req({
|
|
114
|
+
method: 'post',
|
|
115
|
+
url: this.join(`bots/${props.botId}/files`),
|
|
116
|
+
data: props,
|
|
117
|
+
timeout: options?.timeout,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async createConversation({ botId, ...rest }: IBotCreateConversation, options?: ReqOptions) {
|
|
122
|
+
return this.req({
|
|
123
|
+
method: 'post',
|
|
124
|
+
url: this.join(`bots/${botId}/conversation`),
|
|
125
|
+
data: rest,
|
|
126
|
+
timeout: options?.timeout,
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async getConversation({ pageSize = 10, pageNumber = 1, botId, ...rest }: IBotGetConversation, options?: ReqOptions) {
|
|
131
|
+
if (pageNumber < 1) throw new Error('pageNumber must be greater than 0')
|
|
132
|
+
const offset = pageSize * (pageNumber - 1)
|
|
133
|
+
const limit = pageSize
|
|
134
|
+
return this.req({
|
|
135
|
+
method: 'get',
|
|
136
|
+
url: this.join(`bots/${botId}/conversation`),
|
|
137
|
+
data: { ...rest, offset, limit },
|
|
138
|
+
timeout: options?.timeout,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async deleteConversation({ botId, conversationId, ...rest }: IBotDeleteConversation, options?: ReqOptions) {
|
|
143
|
+
return this.req({
|
|
144
|
+
method: 'delete',
|
|
145
|
+
url: this.join(`bots/${botId}/conversation/${conversationId}`),
|
|
146
|
+
data: rest,
|
|
147
|
+
timeout: options?.timeout,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async speechToText(props: IBotSpeechToText, options?: ReqOptions) {
|
|
152
|
+
return this.req({
|
|
153
|
+
method: 'post',
|
|
154
|
+
url: this.join(`bots/${props.botId}/speech-to-text`),
|
|
155
|
+
data: props,
|
|
156
|
+
timeout: options?.timeout,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async textToSpeech(props: IBotTextToSpeech, options?: ReqOptions) {
|
|
161
|
+
return this.req({
|
|
162
|
+
method: 'post',
|
|
163
|
+
url: this.join(`bots/${props.botId}/text-to-speech`),
|
|
164
|
+
data: props,
|
|
165
|
+
timeout: options?.timeout,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getTextToSpeechResult(props: IBotGetTextToSpeechResult, options?: ReqOptions) {
|
|
170
|
+
return this.req({
|
|
171
|
+
method: 'get',
|
|
172
|
+
url: this.join(`bots/${props.botId}/text-to-speech`),
|
|
173
|
+
data: props,
|
|
174
|
+
timeout: options?.timeout,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async getRecommendQuestions(props: IGetBotRecommendQuestions, options?: ReqOptions) {
|
|
179
|
+
const res = await this.req({
|
|
180
|
+
method: 'post',
|
|
181
|
+
url: this.join(`bots/${props.botId}/recommend-questions`),
|
|
182
|
+
data: props,
|
|
183
|
+
stream: true,
|
|
184
|
+
timeout: options?.timeout,
|
|
185
|
+
})
|
|
186
|
+
return new StreamResult(res)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async generateBot(props: IGenerateBot, options?: ReqOptions) {
|
|
190
|
+
const res = await this.req({
|
|
191
|
+
method: 'post',
|
|
192
|
+
url: this.join('generate-bot'),
|
|
193
|
+
data: props,
|
|
194
|
+
stream: true,
|
|
195
|
+
timeout: options?.timeout,
|
|
196
|
+
})
|
|
197
|
+
return new StreamResult(res)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async getPreview(props: IBotPreview, options?: ReqOptions) {
|
|
201
|
+
const res = await this.req({
|
|
202
|
+
method: 'post',
|
|
203
|
+
url: this.join('preview'),
|
|
204
|
+
data: props,
|
|
205
|
+
stream: true,
|
|
206
|
+
timeout: options?.timeout,
|
|
207
|
+
})
|
|
208
|
+
return new StreamResult(res)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
generateImage(props: IGenerateImage, options?: ReqOptions) {
|
|
212
|
+
return this.req({ method: 'post', url: this.join('generate-image'), data: props, timeout: options?.timeout })
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async sendMessage(props: IBotSendMessage, options?: ReqOptions) {
|
|
216
|
+
const res = await this.req({
|
|
217
|
+
method: 'post',
|
|
218
|
+
url: this.join(`bots/${props.botId}/send-message`),
|
|
219
|
+
data: props,
|
|
220
|
+
stream: true,
|
|
221
|
+
timeout: options?.timeout,
|
|
222
|
+
})
|
|
223
|
+
return new StreamResult(res)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private join(url: string) {
|
|
227
|
+
return `${this.baseUrl}/${url}`
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
type BotEventStreamData = { content: string }
|
|
232
|
+
|
|
233
|
+
class StreamResult {
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
235
|
+
private _eventSourceStream: ReadableStream<ParsedEvent>
|
|
236
|
+
|
|
237
|
+
constructor(_stream: ReadableStream<Uint8Array>) {
|
|
238
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
239
|
+
this._eventSourceStream = stream
|
|
240
|
+
.pipeThrough(new TextDecoderStream())
|
|
241
|
+
.pipeThrough(createEventSourceParserTransformStream())
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private get teeedStream() {
|
|
245
|
+
const [s1, s2] = this._eventSourceStream.tee()
|
|
246
|
+
this._eventSourceStream = s2
|
|
247
|
+
return s1
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
get eventSourceStream() {
|
|
251
|
+
return createAsyncIterable(this.teeedStream)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
get dataStream() {
|
|
255
|
+
return createAsyncIterable(this.eventSourceStream.pipeThrough(new TransformStream<ParsedEvent, BotEventStreamData>({
|
|
256
|
+
transform(chunk, controller) {
|
|
257
|
+
try {
|
|
258
|
+
const data = JSON.parse(chunk.data)
|
|
259
|
+
controller.enqueue(data)
|
|
260
|
+
} catch (e) {
|
|
261
|
+
if (chunk.data !== '[DONE]') {
|
|
262
|
+
console.warn('Error when transforming event source data to json', e, chunk)
|
|
263
|
+
} else {
|
|
264
|
+
controller.terminate()
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
}),),)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
get textStream() {
|
|
272
|
+
return createAsyncIterable(this.dataStream.pipeThrough(new TransformStream<BotEventStreamData, string>({
|
|
273
|
+
transform(chunk, controller) {
|
|
274
|
+
controller.enqueue(chunk?.content ?? '')
|
|
275
|
+
},
|
|
276
|
+
}),),)
|
|
277
|
+
}
|
|
278
|
+
}
|
package/src/bot/types.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
export interface IGetBotList {
|
|
2
|
+
name: string
|
|
3
|
+
introduction: string
|
|
4
|
+
information: string
|
|
5
|
+
enable: boolean
|
|
6
|
+
pageSize: number
|
|
7
|
+
pageNumber: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ICreateBot {
|
|
11
|
+
botInfo: BotInfo
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IGetBot {
|
|
15
|
+
botId: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface IUpdateBot {
|
|
19
|
+
botId: string
|
|
20
|
+
botInfo: BotInfo
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IDeleteBot {
|
|
24
|
+
botId: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface IGetBotChatRecords {
|
|
28
|
+
botId: string
|
|
29
|
+
sort: 'asc' | 'desc' | string
|
|
30
|
+
pageSize: number
|
|
31
|
+
pageNumber: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ISendBotFeedback {
|
|
35
|
+
userFeedback: IUserFeedback
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface IGetBotFeedback {
|
|
39
|
+
botId: string
|
|
40
|
+
type: 'upvote' | 'downvote' | string
|
|
41
|
+
sender: string
|
|
42
|
+
senderFilter: 'include' | 'exclude' | 'equal' | 'unequal' | 'prefix' | string
|
|
43
|
+
minRating: number
|
|
44
|
+
maxRating: number
|
|
45
|
+
from: number
|
|
46
|
+
to: number
|
|
47
|
+
pageSize: number
|
|
48
|
+
pageNumber: number
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface IGetBotRecommendQuestions {
|
|
52
|
+
botId: string
|
|
53
|
+
name: string
|
|
54
|
+
introduction: string
|
|
55
|
+
agentSetting: string
|
|
56
|
+
msg: string
|
|
57
|
+
history: Array<{
|
|
58
|
+
role: string
|
|
59
|
+
content: string
|
|
60
|
+
}>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface IGenerateBot {
|
|
64
|
+
simple: boolean
|
|
65
|
+
prompt: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface IBotPreview {
|
|
69
|
+
name: string
|
|
70
|
+
introduction: string
|
|
71
|
+
agentSetting: string
|
|
72
|
+
msg: string
|
|
73
|
+
history: Array<{
|
|
74
|
+
role: string
|
|
75
|
+
content: string
|
|
76
|
+
}>
|
|
77
|
+
knowledgeBase: Array<string>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface IGenerateImage {
|
|
81
|
+
prompt: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface IBotSendMessage {
|
|
85
|
+
botId: string
|
|
86
|
+
msg: string
|
|
87
|
+
history: Array<{
|
|
88
|
+
role: string
|
|
89
|
+
content: string
|
|
90
|
+
}>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface IBotUploadFiles {
|
|
94
|
+
botId: string
|
|
95
|
+
fileList: Array<{
|
|
96
|
+
fileName: string
|
|
97
|
+
fileId: string
|
|
98
|
+
type: string
|
|
99
|
+
}>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface IBotCreateConversation {
|
|
103
|
+
botId: string
|
|
104
|
+
title?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface IBotGetConversation {
|
|
108
|
+
botId: string
|
|
109
|
+
pageSize?: number
|
|
110
|
+
pageNumber?: number
|
|
111
|
+
isDefault?: boolean
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface IBotDeleteConversation {
|
|
115
|
+
botId: string
|
|
116
|
+
conversationId: string
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface IBotSpeechToText {
|
|
120
|
+
botId: string
|
|
121
|
+
engSerViceType: string
|
|
122
|
+
voiceFormat: string
|
|
123
|
+
url: string
|
|
124
|
+
isPreview?: boolean
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface IBotTextToSpeech {
|
|
128
|
+
botId: string
|
|
129
|
+
voiceType: number
|
|
130
|
+
text: string
|
|
131
|
+
isPreview?: boolean
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface IBotGetTextToSpeechResult {
|
|
135
|
+
botId: string
|
|
136
|
+
taskId: string
|
|
137
|
+
isPreview?: boolean
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface IUserFeedback {
|
|
141
|
+
recordId: string
|
|
142
|
+
type: string
|
|
143
|
+
botId: string
|
|
144
|
+
comment: string
|
|
145
|
+
rating: number
|
|
146
|
+
tags: Array<string>
|
|
147
|
+
input: string
|
|
148
|
+
aiAnswer: string
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface BotInfo {
|
|
152
|
+
botId: string
|
|
153
|
+
name: string
|
|
154
|
+
introduction: string
|
|
155
|
+
agentSetting: string
|
|
156
|
+
welcomeMessage: string
|
|
157
|
+
avatar: string
|
|
158
|
+
background: string
|
|
159
|
+
tags: Array<string>
|
|
160
|
+
isNeedRecommend: boolean
|
|
161
|
+
knowledgeBase: Array<string>
|
|
162
|
+
type: string
|
|
163
|
+
initQuestions: Array<string>
|
|
164
|
+
enable: true
|
|
165
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 参数校验错误类
|
|
3
|
+
* 用于统一参数校验错误的格式
|
|
4
|
+
*/
|
|
5
|
+
export class InvalidParamsError extends Error {
|
|
6
|
+
public code: string
|
|
7
|
+
public field?: string
|
|
8
|
+
|
|
9
|
+
constructor(message: string, field?: string) {
|
|
10
|
+
super(message)
|
|
11
|
+
this.name = 'InvalidParamsError'
|
|
12
|
+
this.code = 'INVALID_PARAMS'
|
|
13
|
+
this.field = field
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toJSON() {
|
|
17
|
+
return {
|
|
18
|
+
code: this.code,
|
|
19
|
+
message: this.message,
|
|
20
|
+
field: this.field,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|