ctod 0.3.6 → 0.4.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/README.md +8 -1
- package/dist/index.js +1 -1
- package/examples/chat-demo.ts +2 -0
- package/examples/chat-for-llama.cpp-demo.ts +57 -0
- package/examples/chat-with-json-schema-demo.ts +61 -0
- package/examples/plugin-demo.ts +3 -0
- package/examples/stream-for-llama.cpp-demo.ts +33 -0
- package/examples/vision-demo.ts +3 -0
- package/lib/broker/chat.ts +201 -95
- package/lib/core/translator.ts +20 -3
- package/lib/index.ts +23 -30
- package/lib/service/llama3.cpp/completion.ts +313 -0
- package/lib/service/llama3.cpp/index.ts +63 -0
- package/lib/service/openai/chat.ts +72 -3
- package/lib/service/openai/index.ts +8 -9
- package/lib/shims.d.ts +4 -0
- package/lib/templates.ts +13 -0
- package/lib/utils/validate.ts +43 -0
- package/package.json +5 -3
- package/tsconfig.json +4 -3
- package/types/examples/chat-demo.d.ts +2 -0
- package/types/examples/chat-for-llama.cpp-demo.d.ts +2 -0
- package/types/examples/chat-with-json-schema-demo.d.ts +2 -0
- package/types/examples/plugin-demo.d.ts +2 -0
- package/types/examples/stream-for-llama.cpp-demo.d.ts +2 -0
- package/types/examples/vision-demo.d.ts +2 -0
- package/types/lib/broker/chat.d.ts +22 -2
- package/types/lib/core/plugin.d.ts +2 -2
- package/types/lib/core/translator.d.ts +16 -2
- package/types/lib/index.d.ts +27 -30
- package/types/lib/plugins/index.d.ts +6 -6
- package/types/lib/plugins/limiter.d.ts +2 -1
- package/types/lib/service/llama3.cpp/completion.d.ts +61 -0
- package/types/lib/service/llama3.cpp/index.d.ts +21 -0
- package/types/lib/service/openai/chat.d.ts +13 -2
- package/types/lib/service/openai/index.d.ts +1 -3
- package/types/lib/templates.d.ts +5 -0
- package/types/lib/utils/validate.d.ts +11 -0
- package/lib/service/openai/completion.ts +0 -90
package/lib/broker/chat.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TextParser } from '../core/parser'
|
|
2
2
|
import { ChatBrokerPlugin } from '../core/plugin'
|
|
3
|
-
import { flow, Hook, Log } from 'power-helper'
|
|
3
|
+
import { Event, flow, Hook, Log } from 'power-helper'
|
|
4
4
|
import { Translator, TranslatorParams } from '../core/translator'
|
|
5
5
|
import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
|
|
6
6
|
|
|
@@ -30,6 +30,10 @@ export type ChatBrokerHooks<
|
|
|
30
30
|
send: (data: PS[K]['__receiveData']) => void
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
schema: {
|
|
34
|
+
input: S
|
|
35
|
+
output: O
|
|
36
|
+
}
|
|
33
37
|
messages: Message[]
|
|
34
38
|
setPreMessages: (messages: Message[]) => void
|
|
35
39
|
changeMessages: (messages: Message[]) => void
|
|
@@ -102,6 +106,11 @@ export type ChatBrokerHooks<
|
|
|
102
106
|
type RequestContext = {
|
|
103
107
|
count: number
|
|
104
108
|
isRetry: boolean
|
|
109
|
+
onCancel: (cb: () => void) => void
|
|
110
|
+
schema: {
|
|
111
|
+
input: any
|
|
112
|
+
output: any
|
|
113
|
+
}
|
|
105
114
|
}
|
|
106
115
|
|
|
107
116
|
export type Params<
|
|
@@ -136,6 +145,12 @@ export class ChatBroker<
|
|
|
136
145
|
protected plugins = {} as PS
|
|
137
146
|
protected installed = false
|
|
138
147
|
protected translator: Translator<S, O>
|
|
148
|
+
protected event = new Event<{
|
|
149
|
+
cancel: {
|
|
150
|
+
requestId: string
|
|
151
|
+
}
|
|
152
|
+
cancelAll: any
|
|
153
|
+
}>()
|
|
139
154
|
|
|
140
155
|
constructor(params: Params<S, O, C, P, PS>) {
|
|
141
156
|
this.log = new Log(params.name ?? 'no name')
|
|
@@ -171,115 +186,206 @@ export class ChatBroker<
|
|
|
171
186
|
}
|
|
172
187
|
}
|
|
173
188
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
async cancel(requestId?: string) {
|
|
190
|
+
if (requestId) {
|
|
191
|
+
this.event.emit('cancel', {
|
|
192
|
+
requestId
|
|
193
|
+
})
|
|
194
|
+
} else {
|
|
195
|
+
this.event.emit('cancelAll', {})
|
|
196
|
+
}
|
|
197
|
+
}
|
|
178
198
|
|
|
179
|
-
|
|
199
|
+
requestWithId<T extends Translator<S, O>>(data: T['__schemeType']): {
|
|
200
|
+
id: string
|
|
201
|
+
request: Promise<T['__outputType']>
|
|
202
|
+
} {
|
|
180
203
|
this._install()
|
|
181
204
|
let id = flow.createUuid()
|
|
182
|
-
let
|
|
183
|
-
let
|
|
184
|
-
let
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
let waitCancel = null as (() => void) | null
|
|
206
|
+
let isCancel = false
|
|
207
|
+
let isSending = false
|
|
208
|
+
|
|
209
|
+
// =================
|
|
210
|
+
//
|
|
211
|
+
// event
|
|
212
|
+
//
|
|
213
|
+
|
|
214
|
+
let listeners = [
|
|
215
|
+
this.event.on('cancel', ({ requestId }) => {
|
|
216
|
+
if (requestId === id) {
|
|
217
|
+
cancelTrigger()
|
|
218
|
+
}
|
|
219
|
+
}),
|
|
220
|
+
this.event.on('cancelAll', () => {
|
|
221
|
+
cancelTrigger()
|
|
222
|
+
})
|
|
190
223
|
]
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
224
|
+
let eventOff = () => listeners.forEach(e => e.off())
|
|
225
|
+
let cancelTrigger = () => {
|
|
226
|
+
if (isCancel === false) {
|
|
227
|
+
if (isSending && waitCancel) {
|
|
228
|
+
waitCancel()
|
|
229
|
+
}
|
|
230
|
+
isCancel = true
|
|
231
|
+
eventOff()
|
|
197
232
|
}
|
|
198
233
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
234
|
+
let onCancel = (cb: () => void) => {
|
|
235
|
+
waitCancel = cb
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// =================
|
|
239
|
+
//
|
|
240
|
+
// main
|
|
241
|
+
//
|
|
242
|
+
|
|
243
|
+
let request = async() => {
|
|
244
|
+
let schema = this.translator.getValidate()
|
|
245
|
+
let output: any = null
|
|
246
|
+
let plugins = {} as any
|
|
247
|
+
let question = await this.translator.compile(data, {
|
|
248
|
+
schema
|
|
249
|
+
})
|
|
250
|
+
let messages: Message[] = [
|
|
251
|
+
{
|
|
252
|
+
role: 'user',
|
|
253
|
+
content: question.prompt
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
for (let key in this.plugins) {
|
|
257
|
+
plugins[key] = {
|
|
258
|
+
send: (data: any) => this.plugins[key].send({
|
|
259
|
+
id,
|
|
260
|
+
data
|
|
261
|
+
})
|
|
262
|
+
}
|
|
220
263
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
id,
|
|
251
|
-
output
|
|
252
|
-
})
|
|
253
|
-
await this.hook.notify('done', { id })
|
|
254
|
-
doBreak()
|
|
255
|
-
} catch (error: any) {
|
|
256
|
-
// 如果解析錯誤,可以選擇是否重新解讀
|
|
257
|
-
if (error.isParserError) {
|
|
258
|
-
await this.hook.notify('parseFailed', {
|
|
264
|
+
await this.hook.notify('start', {
|
|
265
|
+
id,
|
|
266
|
+
data,
|
|
267
|
+
schema,
|
|
268
|
+
plugins,
|
|
269
|
+
messages,
|
|
270
|
+
setPreMessages: ms => {
|
|
271
|
+
messages = [
|
|
272
|
+
...ms,
|
|
273
|
+
{
|
|
274
|
+
role: 'user',
|
|
275
|
+
content: question.prompt
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
changeMessages: ms => {
|
|
280
|
+
messages = ms
|
|
281
|
+
}
|
|
282
|
+
})
|
|
283
|
+
await flow.asyncWhile(async ({ count, doBreak }) => {
|
|
284
|
+
if (count >= 10) {
|
|
285
|
+
return doBreak()
|
|
286
|
+
}
|
|
287
|
+
let response = ''
|
|
288
|
+
let parseText = ''
|
|
289
|
+
let retryFlag = false
|
|
290
|
+
let lastUserMessage = messages.filter(e => e.role === 'user').slice(-1)[0]?.content || ''
|
|
291
|
+
try {
|
|
292
|
+
await this.hook.notify('talkBefore', {
|
|
259
293
|
id,
|
|
260
|
-
|
|
261
|
-
count,
|
|
262
|
-
response,
|
|
294
|
+
data,
|
|
263
295
|
messages,
|
|
264
|
-
lastUserMessage
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
296
|
+
lastUserMessage
|
|
297
|
+
})
|
|
298
|
+
const sender = this.params.request(messages, {
|
|
299
|
+
count,
|
|
300
|
+
schema,
|
|
301
|
+
onCancel,
|
|
302
|
+
isRetry: retryFlag
|
|
272
303
|
})
|
|
273
|
-
if (
|
|
304
|
+
if (isCancel) {
|
|
305
|
+
if (waitCancel) {
|
|
306
|
+
waitCancel()
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
try {
|
|
310
|
+
isSending = true
|
|
311
|
+
response = await sender
|
|
312
|
+
parseText = response
|
|
313
|
+
} finally {
|
|
314
|
+
isSending = false
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (isCancel === false) {
|
|
318
|
+
await this.hook.notify('talkAfter', {
|
|
319
|
+
id,
|
|
320
|
+
data,
|
|
321
|
+
response,
|
|
322
|
+
messages,
|
|
323
|
+
parseText,
|
|
324
|
+
lastUserMessage,
|
|
325
|
+
changeParseText: text => {
|
|
326
|
+
parseText = text
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
output = (await this.translator.parse(parseText)).output
|
|
330
|
+
await this.hook.notify('succeeded', {
|
|
331
|
+
id,
|
|
332
|
+
output
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
await this.hook.notify('done', { id })
|
|
336
|
+
doBreak()
|
|
337
|
+
} catch (error: any) {
|
|
338
|
+
// 如果解析錯誤,可以選擇是否重新解讀
|
|
339
|
+
if (error.isParserError) {
|
|
340
|
+
await this.hook.notify('parseFailed', {
|
|
341
|
+
id,
|
|
342
|
+
error: error.error,
|
|
343
|
+
count,
|
|
344
|
+
response,
|
|
345
|
+
messages,
|
|
346
|
+
lastUserMessage,
|
|
347
|
+
parserFails: error.parserFails,
|
|
348
|
+
retry: () => {
|
|
349
|
+
retryFlag = true
|
|
350
|
+
},
|
|
351
|
+
changeMessages: ms => {
|
|
352
|
+
messages = ms
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
if (retryFlag === false) {
|
|
356
|
+
await this.hook.notify('done', { id })
|
|
357
|
+
throw error
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
274
360
|
await this.hook.notify('done', { id })
|
|
275
361
|
throw error
|
|
276
362
|
}
|
|
277
|
-
} else {
|
|
278
|
-
await this.hook.notify('done', { id })
|
|
279
|
-
throw error
|
|
280
363
|
}
|
|
364
|
+
})
|
|
365
|
+
return output
|
|
366
|
+
}
|
|
367
|
+
const send = async() => {
|
|
368
|
+
try {
|
|
369
|
+
const result = await request()
|
|
370
|
+
return result
|
|
371
|
+
} finally {
|
|
372
|
+
eventOff()
|
|
281
373
|
}
|
|
282
|
-
}
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
id,
|
|
377
|
+
request: send()
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @zh 將請求發出至聊天機器人。
|
|
383
|
+
* @en Send request to chatbot.
|
|
384
|
+
*/
|
|
385
|
+
|
|
386
|
+
async request<T extends Translator<S, O>>(data: T['__schemeType']): Promise<T['__outputType']> {
|
|
387
|
+
const { request } = this.requestWithId(data)
|
|
388
|
+
const output = await request
|
|
283
389
|
return output
|
|
284
390
|
}
|
|
285
391
|
}
|
package/lib/core/translator.ts
CHANGED
|
@@ -24,7 +24,12 @@ export type TranslatorParams<
|
|
|
24
24
|
* @zh 組合輸入資料成為提示文字。
|
|
25
25
|
* @en Combine the input data into a prompt.
|
|
26
26
|
*/
|
|
27
|
-
question: (data: ValidateCallbackOutputs<S
|
|
27
|
+
question: (data: ValidateCallbackOutputs<S>, context: {
|
|
28
|
+
schema: {
|
|
29
|
+
input: S
|
|
30
|
+
output: O
|
|
31
|
+
}
|
|
32
|
+
}) => Promise<string>
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
export class Translator<
|
|
@@ -49,15 +54,27 @@ export class Translator<
|
|
|
49
54
|
* @en Combine the input data into a prompt.
|
|
50
55
|
*/
|
|
51
56
|
|
|
52
|
-
async compile(data: ValidateCallbackOutputs<S
|
|
57
|
+
async compile(data: ValidateCallbackOutputs<S>, context: {
|
|
58
|
+
schema: {
|
|
59
|
+
input: S
|
|
60
|
+
output: O
|
|
61
|
+
}
|
|
62
|
+
}) {
|
|
53
63
|
const scheme = validate(data, this.params.input)
|
|
54
|
-
const prompt = await this.params.question(scheme)
|
|
64
|
+
const prompt = await this.params.question(scheme, context)
|
|
55
65
|
return {
|
|
56
66
|
scheme,
|
|
57
67
|
prompt
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
|
|
71
|
+
getValidate() {
|
|
72
|
+
return {
|
|
73
|
+
input: this.params.input,
|
|
74
|
+
output: this.params.output
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
61
78
|
/**
|
|
62
79
|
* @zh 將文字轉換成序列化資料。
|
|
63
80
|
* @en Convert text to serialized data.
|
package/lib/index.ts
CHANGED
|
@@ -1,41 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export const OpenAI = _OpenAI
|
|
22
|
-
export const TextParser = _TextParser
|
|
23
|
-
export const Translator = _Translator.Translator
|
|
24
|
-
|
|
25
|
-
export const ChatBroker = _ChatBroker
|
|
26
|
-
export const ChatBrokerPlugin = _ChatBrokerPlugin
|
|
27
|
-
|
|
28
|
-
export const plugins = _plugins
|
|
29
|
-
export const templates = _templates
|
|
1
|
+
export * as plugins from './plugins'
|
|
2
|
+
export * as templates from './templates'
|
|
3
|
+
export { validateToJsonSchema, JsonSchemaInfo } from './utils/validate'
|
|
4
|
+
export { OpenAI } from './service/openai'
|
|
5
|
+
export { Llama3Cpp } from './service/llama3.cpp'
|
|
6
|
+
export { TextParser } from './core/parser'
|
|
7
|
+
export { ChatGPTMessage } from './service/openai/chat'
|
|
8
|
+
export { ChatBroker } from './broker/chat'
|
|
9
|
+
export { ChatBrokerPlugin } from './core/plugin'
|
|
10
|
+
export { Translator, TranslatorParams } from './core/translator'
|
|
11
|
+
|
|
12
|
+
import * as plugins from './plugins'
|
|
13
|
+
import * as templates from './templates'
|
|
14
|
+
import { OpenAI } from './service/openai'
|
|
15
|
+
import { Llama3Cpp } from './service/llama3.cpp'
|
|
16
|
+
import { Translator } from './core/translator'
|
|
17
|
+
import { TextParser } from './core/parser'
|
|
18
|
+
import { ChatBroker } from './broker/chat'
|
|
19
|
+
import { ChatBrokerPlugin } from './core/plugin'
|
|
20
|
+
import { validateToJsonSchema } from './utils/validate'
|
|
30
21
|
|
|
31
22
|
export const ctod = {
|
|
32
23
|
OpenAI,
|
|
24
|
+
Llama3Cpp,
|
|
33
25
|
plugins,
|
|
34
26
|
templates,
|
|
35
27
|
ChatBroker,
|
|
36
28
|
Translator,
|
|
37
29
|
TextParser,
|
|
38
|
-
ChatBrokerPlugin
|
|
30
|
+
ChatBrokerPlugin,
|
|
31
|
+
validateToJsonSchema
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
module.exports = ctod
|