@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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* eslint-disable eqeqeq */
|
|
2
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3
|
+
import {
|
|
4
|
+
createAsyncIterable,
|
|
5
|
+
TransformStream,
|
|
6
|
+
intoStandardStream,
|
|
7
|
+
isToolCallAssistantMessage,
|
|
8
|
+
toPolyfillReadable,
|
|
9
|
+
} from '../../utils'
|
|
10
|
+
import type { DSInput, DSGenerateOutput, DSStreamOutput } from './type'
|
|
11
|
+
import type {
|
|
12
|
+
ModelReq,
|
|
13
|
+
BaseChatModelInput,
|
|
14
|
+
DoGenerateOutput,
|
|
15
|
+
DoStreamOutput,
|
|
16
|
+
BaseDoStreamOutputChunk,
|
|
17
|
+
SimpleChatModel,
|
|
18
|
+
ReqOptions,
|
|
19
|
+
} from '../../type'
|
|
20
|
+
|
|
21
|
+
function processInput(input: BaseChatModelInput): DSInput {
|
|
22
|
+
const { messages, model, temperature, tools, top_p } = input
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...input,
|
|
26
|
+
messages,
|
|
27
|
+
model,
|
|
28
|
+
tools,
|
|
29
|
+
top_p,
|
|
30
|
+
temperature,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class DSSimpleModel implements SimpleChatModel {
|
|
35
|
+
public subUrl = 'dashscope/compatible-mode/v1/chat/completions'
|
|
36
|
+
|
|
37
|
+
constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
|
|
38
|
+
if (subUrl != null) {
|
|
39
|
+
this.subUrl = subUrl
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private get url() {
|
|
44
|
+
return `${this.baseUrl}/${this.subUrl}`
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
|
|
48
|
+
const res = (await this.req({
|
|
49
|
+
url: this.url,
|
|
50
|
+
data: {
|
|
51
|
+
...processInput(data),
|
|
52
|
+
stream: false,
|
|
53
|
+
},
|
|
54
|
+
stream: false,
|
|
55
|
+
timeout: options?.timeout,
|
|
56
|
+
})) as DSGenerateOutput
|
|
57
|
+
return { ...res, rawResponse: res }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
|
|
61
|
+
let isToolCall: null | boolean = null
|
|
62
|
+
const _stream = await this.req({
|
|
63
|
+
url: this.url,
|
|
64
|
+
data: {
|
|
65
|
+
...processInput(data),
|
|
66
|
+
stream: true,
|
|
67
|
+
},
|
|
68
|
+
stream: true,
|
|
69
|
+
timeout: options?.timeout,
|
|
70
|
+
})
|
|
71
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
72
|
+
|
|
73
|
+
const arkStream = intoStandardStream<DSStreamOutput>(stream)
|
|
74
|
+
const streamWithRaw = arkStream.pipeThrough(new TransformStream<DSStreamOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
|
|
75
|
+
transform(chunk, controller) {
|
|
76
|
+
const newChoices = chunk.choices.map((choice) => {
|
|
77
|
+
const message = Object.assign(choice.delta, { role: 'assistant' }) as typeof choice.delta & {
|
|
78
|
+
role: 'assistant'
|
|
79
|
+
}
|
|
80
|
+
if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
|
|
81
|
+
if (isToolCall) {
|
|
82
|
+
return {
|
|
83
|
+
...choice,
|
|
84
|
+
finish_reason: 'tool_calls' as const,
|
|
85
|
+
delta: message,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { ...choice, delta: message }
|
|
89
|
+
})
|
|
90
|
+
const newChunk = { ...chunk, choices: newChoices }
|
|
91
|
+
controller.enqueue({ ...newChunk, rawResponse: chunk })
|
|
92
|
+
},
|
|
93
|
+
}),)
|
|
94
|
+
|
|
95
|
+
return createAsyncIterable(streamWithRaw)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type DSInput = {
|
|
2
|
+
model: string
|
|
3
|
+
messages: Array<Message>
|
|
4
|
+
temperature?: number
|
|
5
|
+
top_p?: number
|
|
6
|
+
tools?: Array<{
|
|
7
|
+
type: string
|
|
8
|
+
function: { name: string; description: string; parameters: object }
|
|
9
|
+
}>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Message = SystemMessage | UserMessage | AssistantMessage | ToolMessage
|
|
13
|
+
|
|
14
|
+
type SystemMessage = {
|
|
15
|
+
content: string
|
|
16
|
+
role: 'system'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type UserMessage = {
|
|
20
|
+
content: string
|
|
21
|
+
role: 'user'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type ToolMessage = {
|
|
25
|
+
content: string
|
|
26
|
+
role: 'tool'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type AssistantMessage =
|
|
30
|
+
| {
|
|
31
|
+
role: 'assistant'
|
|
32
|
+
content: string
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
role: 'assistant'
|
|
36
|
+
tool_calls: Array<ToolCall>
|
|
37
|
+
content?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ToolCall = {
|
|
41
|
+
id: string
|
|
42
|
+
type: string
|
|
43
|
+
function: { name: string; arguments: string }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type DSGenerateOutput = {
|
|
47
|
+
choices: Array<{
|
|
48
|
+
finish_reason: string
|
|
49
|
+
message: {
|
|
50
|
+
content: string
|
|
51
|
+
role: 'assistant'
|
|
52
|
+
tool_calls?: Array<ToolCall>
|
|
53
|
+
}
|
|
54
|
+
}>
|
|
55
|
+
usage: {
|
|
56
|
+
prompt_tokens: number
|
|
57
|
+
completion_tokens: number
|
|
58
|
+
total_tokens: number
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type DSStreamOutput = {
|
|
63
|
+
choices: Array<{
|
|
64
|
+
delta: {
|
|
65
|
+
content: string
|
|
66
|
+
tool_calls?: Array<ToolCall>
|
|
67
|
+
role?: 'assistant'
|
|
68
|
+
}
|
|
69
|
+
finish_reason: string
|
|
70
|
+
}>
|
|
71
|
+
usage?: {
|
|
72
|
+
prompt_tokens: number
|
|
73
|
+
completion_tokens: number
|
|
74
|
+
total_tokens: number
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-disable eqeqeq */
|
|
2
|
+
import {
|
|
3
|
+
createAsyncIterable,
|
|
4
|
+
TransformStream,
|
|
5
|
+
toPolyfillReadable,
|
|
6
|
+
intoStandardStream,
|
|
7
|
+
isToolCallAssistantMessage,
|
|
8
|
+
} from '../../utils'
|
|
9
|
+
import type {
|
|
10
|
+
ModelReq,
|
|
11
|
+
BaseChatModelInput,
|
|
12
|
+
SimpleChatModel,
|
|
13
|
+
DoStreamOutput,
|
|
14
|
+
BaseDoStreamOutputChunk,
|
|
15
|
+
DoGenerateOutput,
|
|
16
|
+
ReqOptions,
|
|
17
|
+
} from '../../type'
|
|
18
|
+
|
|
19
|
+
export class DeepSeekSimpleModel implements SimpleChatModel {
|
|
20
|
+
public subUrl = 'deepseek/chat/completions'
|
|
21
|
+
constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
|
|
22
|
+
if (subUrl != null) {
|
|
23
|
+
this.subUrl = subUrl
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private get url() {
|
|
28
|
+
return `${this.baseUrl}/${this.subUrl}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
|
|
32
|
+
const res = (await this.req({
|
|
33
|
+
url: this.url,
|
|
34
|
+
data: {
|
|
35
|
+
...data,
|
|
36
|
+
stream: false,
|
|
37
|
+
},
|
|
38
|
+
stream: false,
|
|
39
|
+
timeout: options?.timeout,
|
|
40
|
+
})) as DoGenerateOutput
|
|
41
|
+
return { ...res, rawResponse: res }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
|
|
45
|
+
let isToolCall: null | boolean = null
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
47
|
+
const _stream = await this.req({
|
|
48
|
+
url: this.url,
|
|
49
|
+
data: {
|
|
50
|
+
...data,
|
|
51
|
+
stream: true,
|
|
52
|
+
},
|
|
53
|
+
stream: true,
|
|
54
|
+
timeout: options?.timeout,
|
|
55
|
+
})
|
|
56
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
57
|
+
|
|
58
|
+
const standardStream = intoStandardStream<BaseDoStreamOutputChunk>(stream)
|
|
59
|
+
const streamWithRaw = standardStream.pipeThrough(new TransformStream<BaseDoStreamOutputChunk, BaseDoStreamOutputChunk & { rawResponse?: any }>({
|
|
60
|
+
transform(chunk, controller) {
|
|
61
|
+
const newChoices = chunk.choices.map((choice) => {
|
|
62
|
+
const message = choice.delta
|
|
63
|
+
if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
|
|
64
|
+
if (isToolCall) {
|
|
65
|
+
return {
|
|
66
|
+
...choice,
|
|
67
|
+
finish_reason: 'tool_calls' as const,
|
|
68
|
+
delta: message,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return choice
|
|
72
|
+
})
|
|
73
|
+
const newChunk = { ...chunk, choices: newChoices }
|
|
74
|
+
controller.enqueue({ ...newChunk, rawResponse: chunk })
|
|
75
|
+
},
|
|
76
|
+
}),)
|
|
77
|
+
|
|
78
|
+
return createAsyncIterable(streamWithRaw)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAsyncIterable,
|
|
3
|
+
TransformStream,
|
|
4
|
+
toPolyfillReadable,
|
|
5
|
+
intoStandardStream,
|
|
6
|
+
isToolCallAssistantMessage,
|
|
7
|
+
} from '../../utils'
|
|
8
|
+
import type {
|
|
9
|
+
ModelReq,
|
|
10
|
+
BaseChatModelInput,
|
|
11
|
+
SimpleChatModel,
|
|
12
|
+
DoStreamOutput,
|
|
13
|
+
BaseDoStreamOutputChunk,
|
|
14
|
+
DoGenerateOutput,
|
|
15
|
+
} from '../../type'
|
|
16
|
+
|
|
17
|
+
export class DefaultSimpleModel implements SimpleChatModel {
|
|
18
|
+
constructor(private req: ModelReq, public baseUrl: string, public subUrl: string = '') {}
|
|
19
|
+
|
|
20
|
+
private get url() {
|
|
21
|
+
return `${this.baseUrl}/${this.subUrl}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async doGenerate(data: BaseChatModelInput): Promise<DoGenerateOutput> {
|
|
25
|
+
const res = await this.req({
|
|
26
|
+
url: this.url,
|
|
27
|
+
data: { ...data, stream: false },
|
|
28
|
+
stream: false,
|
|
29
|
+
})
|
|
30
|
+
return { ...res, rawResponse: res }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async doStream(data: BaseChatModelInput): Promise<DoStreamOutput> {
|
|
34
|
+
let isToolCall: null | boolean = null
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37
|
+
const _stream = await this.req({
|
|
38
|
+
url: this.url,
|
|
39
|
+
data: {
|
|
40
|
+
...data,
|
|
41
|
+
stream: true,
|
|
42
|
+
},
|
|
43
|
+
stream: true,
|
|
44
|
+
})
|
|
45
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
46
|
+
|
|
47
|
+
const standardStream = intoStandardStream<BaseDoStreamOutputChunk>(stream)
|
|
48
|
+
const streamWithRaw = standardStream.pipeThrough(new TransformStream<BaseDoStreamOutputChunk, BaseDoStreamOutputChunk & { rawResponse?: any }>({
|
|
49
|
+
transform(chunk, controller) {
|
|
50
|
+
const newChoices = chunk.choices.map((choice) => {
|
|
51
|
+
const message = choice.delta
|
|
52
|
+
// eslint-disable-next-line eqeqeq
|
|
53
|
+
if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
|
|
54
|
+
if (isToolCall) {
|
|
55
|
+
return {
|
|
56
|
+
...choice,
|
|
57
|
+
finish_reason: 'tool_calls',
|
|
58
|
+
delta: message,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return choice
|
|
62
|
+
})
|
|
63
|
+
const newChunk = { ...chunk, choices: newChoices }
|
|
64
|
+
controller.enqueue({ ...newChunk, rawResponse: chunk })
|
|
65
|
+
},
|
|
66
|
+
}),)
|
|
67
|
+
|
|
68
|
+
return createAsyncIterable(streamWithRaw)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable eqeqeq */
|
|
2
|
+
import {
|
|
3
|
+
createAsyncIterable,
|
|
4
|
+
TransformStream,
|
|
5
|
+
toPolyfillReadable,
|
|
6
|
+
intoStandardStream,
|
|
7
|
+
isToolCallAssistantMessage,
|
|
8
|
+
} from '../../utils'
|
|
9
|
+
import type {
|
|
10
|
+
ModelReq,
|
|
11
|
+
BaseChatModelInput,
|
|
12
|
+
BaseDoStreamOutputChunk,
|
|
13
|
+
DoStreamOutput,
|
|
14
|
+
SimpleChatModel,
|
|
15
|
+
DoGenerateOutput,
|
|
16
|
+
ReqOptions,
|
|
17
|
+
} from '../../type'
|
|
18
|
+
import { processInput, titleCaseToSnakeCase } from './util'
|
|
19
|
+
import { HunYuanGenerateTextOutput, HunYuanStreamTextOutput } from './type'
|
|
20
|
+
|
|
21
|
+
export class HunYuanSimpleModel implements SimpleChatModel {
|
|
22
|
+
public subUrl = 'hunyuan'
|
|
23
|
+
constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
|
|
24
|
+
if (subUrl != null) {
|
|
25
|
+
this.subUrl = subUrl
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private get url() {
|
|
30
|
+
return `${this.baseUrl}/${this.subUrl}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
|
|
34
|
+
const res = (await this.req({
|
|
35
|
+
url: this.url,
|
|
36
|
+
headers: {
|
|
37
|
+
'X-Tc-Action': 'ChatCompletions',
|
|
38
|
+
},
|
|
39
|
+
data: {
|
|
40
|
+
...processInput(data),
|
|
41
|
+
stream: false,
|
|
42
|
+
},
|
|
43
|
+
stream: false,
|
|
44
|
+
timeout: options?.timeout,
|
|
45
|
+
})) as { Response: any }
|
|
46
|
+
const output = titleCaseToSnakeCase(res.Response) as HunYuanGenerateTextOutput
|
|
47
|
+
return {
|
|
48
|
+
...output,
|
|
49
|
+
rawResponse: res,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
|
|
54
|
+
let isToolCall: null | boolean = null
|
|
55
|
+
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
57
|
+
const _stream = await this.req({
|
|
58
|
+
url: this.url,
|
|
59
|
+
headers: {
|
|
60
|
+
'X-Tc-Action': 'ChatCompletions',
|
|
61
|
+
},
|
|
62
|
+
data: {
|
|
63
|
+
...data,
|
|
64
|
+
stream: true,
|
|
65
|
+
},
|
|
66
|
+
stream: true,
|
|
67
|
+
timeout: options?.timeout,
|
|
68
|
+
})
|
|
69
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
70
|
+
|
|
71
|
+
const hunyuanStream = intoStandardStream(stream)
|
|
72
|
+
const streamWithRaw = hunyuanStream.pipeThrough(new TransformStream<unknown, BaseDoStreamOutputChunk & { rawResponse?: any }>({
|
|
73
|
+
transform(_chunk, controller) {
|
|
74
|
+
const chunk = titleCaseToSnakeCase(_chunk) as HunYuanStreamTextOutput
|
|
75
|
+
const newChoices = chunk.choices.map((choice) => {
|
|
76
|
+
const message = choice.delta
|
|
77
|
+
if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
|
|
78
|
+
if (isToolCall) {
|
|
79
|
+
return {
|
|
80
|
+
...choice,
|
|
81
|
+
finish_reason: 'tool_calls',
|
|
82
|
+
delta: message,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return choice
|
|
86
|
+
})
|
|
87
|
+
const newChunk = { ...chunk, choices: newChoices }
|
|
88
|
+
controller.enqueue({ ...newChunk, rawResponse: _chunk })
|
|
89
|
+
},
|
|
90
|
+
}),)
|
|
91
|
+
|
|
92
|
+
return createAsyncIterable(streamWithRaw)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
type HunYuanUserMessage = {
|
|
2
|
+
role: 'user'
|
|
3
|
+
content: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
type HunYuanSystemMessage = { role: 'system'; content: string }
|
|
7
|
+
|
|
8
|
+
type HunYuanToolMessage = { role: 'tool'; content: string; tool_call_id: string }
|
|
9
|
+
|
|
10
|
+
type HunYuanAssistantMessage =
|
|
11
|
+
| { role: 'assistant'; content: string }
|
|
12
|
+
| {
|
|
13
|
+
role: 'assistant'
|
|
14
|
+
tool_calls: Array<HunYuanToolCall>
|
|
15
|
+
content?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type HunYuanToolCall = {
|
|
19
|
+
id: string
|
|
20
|
+
type: 'function'
|
|
21
|
+
function: HunYuanToolCallFunction
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type HunYuanToolCallFunction = {
|
|
25
|
+
name: string
|
|
26
|
+
arguments: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type HunYuanMessage = HunYuanUserMessage | HunYuanSystemMessage | HunYuanToolMessage | HunYuanAssistantMessage
|
|
30
|
+
|
|
31
|
+
type HunYuanTool = {
|
|
32
|
+
// TODO: 混元文档说当前只支持 function
|
|
33
|
+
type: 'function'
|
|
34
|
+
function: HunYuanToolFunction
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type HunYuanToolFunction = {
|
|
38
|
+
name: string
|
|
39
|
+
parameters: object
|
|
40
|
+
description?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type HunYuanInputData = {
|
|
44
|
+
model:
|
|
45
|
+
| (string & {})
|
|
46
|
+
| 'hunyuan-lite'
|
|
47
|
+
| 'hunyuan-standard'
|
|
48
|
+
| 'hunyuan-standard-256K'
|
|
49
|
+
| 'hunyuan-pro'
|
|
50
|
+
| 'hunyuan-code'
|
|
51
|
+
| 'hunyuan-role'
|
|
52
|
+
| 'hunyuan-functioncall'
|
|
53
|
+
| 'hunyuan-vision'
|
|
54
|
+
messages: Array<HunYuanMessage>
|
|
55
|
+
stream_moderation?: boolean
|
|
56
|
+
top_p?: number
|
|
57
|
+
temperature?: number
|
|
58
|
+
enable_enhancement?: boolean
|
|
59
|
+
tools?: Array<HunYuanTool>
|
|
60
|
+
tool_choice?: 'none' | 'auto' | 'custom'
|
|
61
|
+
custom_tool?: HunYuanTool
|
|
62
|
+
search_info?: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type Usage = { prompt_tokens: number; completion_tokens: number; total_tokens: number }
|
|
66
|
+
|
|
67
|
+
export type HunYuanGenerateTextOutput = {
|
|
68
|
+
choices?: Array<GenerateChoice>
|
|
69
|
+
usage?: Usage
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type GenerateChoice = {
|
|
73
|
+
finish_reason?: string
|
|
74
|
+
message: HunYuanMessage
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type StreamChoice = {
|
|
78
|
+
finish_reason?: string
|
|
79
|
+
delta: HunYuanAssistantMessage
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type HunYuanStreamTextOutput = {
|
|
83
|
+
choices?: Array<StreamChoice>
|
|
84
|
+
usage?: Usage
|
|
85
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable eqeqeq */
|
|
2
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3
|
+
import { HunYuanInputData } from './type'
|
|
4
|
+
import { BaseChatModelInput } from '../../type'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 这里的 process 只是对不符合的 input 做 warning。
|
|
8
|
+
* 实际上还是会如实传递。
|
|
9
|
+
* 防止未来模型参数更新,SDK 没跟上而导致用户输入无法生效。
|
|
10
|
+
*/
|
|
11
|
+
export function processInput(input: BaseChatModelInput): HunYuanInputData {
|
|
12
|
+
const { messages, model, temperature, tool_choice, tools, top_p } = input
|
|
13
|
+
|
|
14
|
+
const handleTools = () => {
|
|
15
|
+
if (!tools) return undefined
|
|
16
|
+
tools.forEach((tool) => {
|
|
17
|
+
if (tool.type !== 'function') console.warn('`type` in tool is not \'function\'', tool)
|
|
18
|
+
})
|
|
19
|
+
return tools as HunYuanInputData['tools']
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const handleMessages = () => {
|
|
23
|
+
messages.forEach((message) => {
|
|
24
|
+
if ('tool_calls' in message) {
|
|
25
|
+
message.tool_calls
|
|
26
|
+
.filter(tool_call => tool_call.type !== 'function')
|
|
27
|
+
.forEach(tool_call => console.warn('`type` in tool_call is not \'function\'', tool_call, message))
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
return messages as HunYuanInputData['messages']
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
...input,
|
|
35
|
+
messages: handleMessages(),
|
|
36
|
+
model,
|
|
37
|
+
tools: handleTools(),
|
|
38
|
+
top_p,
|
|
39
|
+
tool_choice,
|
|
40
|
+
temperature,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function titleCaseToSnakeCase(obj: unknown) {
|
|
45
|
+
if (typeof obj !== 'object' || obj == null) return obj // 如果不是对象或者是null,则直接返回
|
|
46
|
+
|
|
47
|
+
if (Array.isArray(obj)) return obj.map(item => titleCaseToSnakeCase(item)) // 如果是数组,递归处理每个元素
|
|
48
|
+
|
|
49
|
+
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
50
|
+
const snakeCaseKey = toSnakeCase(key)
|
|
51
|
+
|
|
52
|
+
acc[snakeCaseKey] = typeof value === 'object' ? titleCaseToSnakeCase(value) : value
|
|
53
|
+
return acc
|
|
54
|
+
}, {})
|
|
55
|
+
|
|
56
|
+
function toSnakeCase(s: string) {
|
|
57
|
+
const ret = s.replace(/[A-Z]/g, match => `_${match.toLowerCase()}`)
|
|
58
|
+
return ret.charAt(0) === '_' ? ret.slice(1) : ret
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
+
/* eslint-disable eqeqeq */
|
|
3
|
+
import {
|
|
4
|
+
createAsyncIterable,
|
|
5
|
+
TransformStream,
|
|
6
|
+
toPolyfillReadable,
|
|
7
|
+
intoStandardStream,
|
|
8
|
+
isToolCallAssistantMessage,
|
|
9
|
+
} from '../../utils'
|
|
10
|
+
import type {
|
|
11
|
+
ModelReq,
|
|
12
|
+
BaseChatModelInput,
|
|
13
|
+
SimpleChatModel,
|
|
14
|
+
DoStreamOutput,
|
|
15
|
+
BaseDoStreamOutputChunk,
|
|
16
|
+
DoGenerateOutput,
|
|
17
|
+
ReqOptions,
|
|
18
|
+
} from '../../type'
|
|
19
|
+
import { processInput } from '../HunYuan/util'
|
|
20
|
+
import { HunYuanGenerateTextOutput, HunYuanStreamTextOutput } from '../HunYuan/type'
|
|
21
|
+
|
|
22
|
+
export class HunYuanBetaSimpleModel implements SimpleChatModel {
|
|
23
|
+
public subUrl = 'hunyuan-beta/openapi/v1/chat/completions'
|
|
24
|
+
constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
|
|
25
|
+
if (subUrl != null) {
|
|
26
|
+
this.subUrl = subUrl
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private get url() {
|
|
31
|
+
return `${this.baseUrl}/${this.subUrl}`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
|
|
35
|
+
const res = (await this.req({
|
|
36
|
+
url: this.url,
|
|
37
|
+
data: {
|
|
38
|
+
...processInput(data),
|
|
39
|
+
stream: false,
|
|
40
|
+
},
|
|
41
|
+
stream: false,
|
|
42
|
+
timeout: options?.timeout,
|
|
43
|
+
})) as HunYuanGenerateTextOutput
|
|
44
|
+
return { ...res, rawResponse: res }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
|
|
48
|
+
let isToolCall: null | boolean = null
|
|
49
|
+
|
|
50
|
+
const _stream = await this.req({
|
|
51
|
+
url: this.url,
|
|
52
|
+
data: {
|
|
53
|
+
...processInput(data),
|
|
54
|
+
stream: true,
|
|
55
|
+
},
|
|
56
|
+
stream: true,
|
|
57
|
+
timeout: options?.timeout,
|
|
58
|
+
})
|
|
59
|
+
const stream = toPolyfillReadable(_stream) as typeof _stream
|
|
60
|
+
|
|
61
|
+
const hunyuanBetaStream = intoStandardStream<HunYuanStreamTextOutput>(stream)
|
|
62
|
+
const streamWithRaw = hunyuanBetaStream.pipeThrough(new TransformStream<HunYuanStreamTextOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
|
|
63
|
+
transform(chunk, controller) {
|
|
64
|
+
const newChoices = chunk.choices.map((choice) => {
|
|
65
|
+
const message = choice.delta
|
|
66
|
+
if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
|
|
67
|
+
if (isToolCall) {
|
|
68
|
+
return {
|
|
69
|
+
...choice,
|
|
70
|
+
finish_reason: 'tool_calls',
|
|
71
|
+
delta: message,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return choice
|
|
75
|
+
})
|
|
76
|
+
const newChunk = { ...chunk, choices: newChoices }
|
|
77
|
+
controller.enqueue({ ...newChunk, rawResponse: chunk })
|
|
78
|
+
},
|
|
79
|
+
}),)
|
|
80
|
+
|
|
81
|
+
return createAsyncIterable(streamWithRaw)
|
|
82
|
+
}
|
|
83
|
+
}
|