ctod 0.7.1 → 0.7.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.
Files changed (96) hide show
  1. package/examples/basic.ts +97 -0
  2. package/examples/llama.cpp.ts +56 -0
  3. package/examples/plugin.ts +118 -0
  4. package/lib/broker/chat.ts +435 -0
  5. package/lib/core/parser.ts +62 -0
  6. package/lib/core/plugin.ts +46 -0
  7. package/lib/core/translator.ts +115 -0
  8. package/lib/ctod.ts +71 -0
  9. package/lib/index.ts +41 -0
  10. package/lib/plugins/index.ts +38 -0
  11. package/lib/plugins/limiter.ts +103 -0
  12. package/lib/plugins/print-log.ts +35 -0
  13. package/lib/plugins/retry.ts +25 -0
  14. package/lib/plugins/role.ts +28 -0
  15. package/lib/service/llama3.cpp/completion.ts +313 -0
  16. package/lib/service/llama3.cpp/index.ts +53 -0
  17. package/lib/service/openai/chat.ts +244 -0
  18. package/lib/service/openai/images-generation.ts +64 -0
  19. package/lib/service/openai/index.ts +97 -0
  20. package/lib/service/openai/vision.ts +111 -0
  21. package/lib/shims.d.ts +4 -0
  22. package/lib/templates.ts +71 -0
  23. package/lib/types.ts +4 -0
  24. package/lib/utils/error.ts +14 -0
  25. package/lib/utils/validate.ts +64 -0
  26. package/package.json +1 -1
  27. package/types/examples/basic.d.ts +1 -0
  28. package/types/examples/chat-demo.d.ts +2 -0
  29. package/types/examples/chat-for-llama.cpp-demo.d.ts +2 -0
  30. package/types/examples/chat-with-json-schema-demo.d.ts +2 -0
  31. package/types/examples/llama.cpp.d.ts +2 -0
  32. package/types/examples/plugin-demo.d.ts +2 -0
  33. package/types/examples/plugin.d.ts +2 -0
  34. package/types/examples/stream-for-llama.cpp-demo.d.ts +2 -0
  35. package/types/examples/vision-demo.d.ts +2 -0
  36. package/types/lib/broker/chat.d.ts +150 -0
  37. package/types/lib/core/parser.d.ts +32 -0
  38. package/types/lib/core/plugin.d.ts +34 -0
  39. package/types/lib/core/translator.d.ts +67 -0
  40. package/types/lib/ctod.d.ts +32 -0
  41. package/types/lib/index.d.ts +34 -0
  42. package/types/lib/plugins/index.d.ts +47 -0
  43. package/types/lib/plugins/limiter.d.ts +36 -0
  44. package/types/lib/plugins/print-log.d.ts +5 -0
  45. package/types/lib/plugins/retry.d.ts +6 -0
  46. package/types/lib/plugins/role.d.ts +5 -0
  47. package/types/lib/service/llama3.cpp/completion.d.ts +61 -0
  48. package/types/lib/service/llama3.cpp/index.d.ts +19 -0
  49. package/types/lib/service/openai/chat.d.ts +110 -0
  50. package/types/lib/service/openai/completion.d.ts +59 -0
  51. package/types/lib/service/openai/images-generation.d.ts +35 -0
  52. package/types/lib/service/openai/index.d.ts +29 -0
  53. package/types/lib/service/openai/vision.d.ts +74 -0
  54. package/types/lib/templates.d.ts +20 -0
  55. package/types/lib/types.d.ts +1 -0
  56. package/types/lib/utils/error.d.ts +11 -0
  57. package/types/lib/utils/validate.d.ts +16 -0
  58. package/.api-key +0 -1
  59. package/.nyc_output/42919e68-b472-4a5d-b2d3-5d5153f28467.json +0 -1
  60. package/.nyc_output/processinfo/42919e68-b472-4a5d-b2d3-5d5153f28467.json +0 -1
  61. package/.nyc_output/processinfo/index.json +0 -1
  62. package/.output/.output/stores//344/270/200/345/240/264/346/234/237/345/276/205/345/267/262/344/271/205/347/232/204/345/222/214/350/247/243/cover-0.png +0 -1
  63. package/.output/.output/stores//344/270/200/345/240/264/346/234/237/345/276/205/345/267/262/344/271/205/347/232/204/345/222/214/350/247/243/cover-1.png +0 -1
  64. package/.output/.output/stores//344/270/200/345/240/264/346/234/237/345/276/205/345/267/262/344/271/205/347/232/204/345/222/214/350/247/243/story-config.json +0 -4
  65. package/.output/.output/stores//344/270/200/345/240/264/346/234/237/345/276/205/345/267/262/344/271/205/347/232/204/345/222/214/350/247/243/story.json +0 -22
  66. package/.output/.output/stores//345/276/236/351/273/221/346/232/227/350/265/260/345/220/221/345/205/211/346/230/216/cover-0.png +0 -1
  67. package/.output/.output/stores//345/276/236/351/273/221/346/232/227/350/265/260/345/220/221/345/205/211/346/230/216/cover-1.png +0 -1
  68. package/.output/.output/stores//345/276/236/351/273/221/346/232/227/350/265/260/345/220/221/345/205/211/346/230/216/story-config.json +0 -4
  69. package/.output/.output/stores//345/276/236/351/273/221/346/232/227/350/265/260/345/220/221/345/205/211/346/230/216/story.json +0 -24
  70. package/.output/.output/stores//347/240/264/347/242/216/347/232/204/345/271/273/350/261/241/cover-0.png +0 -1
  71. package/.output/.output/stores//347/240/264/347/242/216/347/232/204/345/271/273/350/261/241/cover-1.png +0 -1
  72. package/.output/.output/stores//347/240/264/347/242/216/347/232/204/345/271/273/350/261/241/story-config.json +0 -4
  73. package/.output/.output/stores//347/240/264/347/242/216/347/232/204/345/271/273/350/261/241/story.json +0 -24
  74. package/.output/.output/stores//350/227/235/350/241/223/345/256/266/347/232/204/351/235/210/346/204/237/cover-0.png +0 -1
  75. package/.output/.output/stores//350/227/235/350/241/223/345/256/266/347/232/204/351/235/210/346/204/237/cover-1.png +0 -1
  76. package/.output/.output/stores//350/227/235/350/241/223/345/256/266/347/232/204/351/235/210/346/204/237/story-config.json +0 -4
  77. package/.output/.output/stores//350/227/235/350/241/223/345/256/266/347/232/204/351/235/210/346/204/237/story.json +0 -28
  78. package/.output/.output/stores//350/250/230/346/206/266/345/225/206/344/272/272/cover-0.png +0 -1
  79. package/.output/.output/stores//350/250/230/346/206/266/345/225/206/344/272/272/cover-1.png +0 -1
  80. package/.output/.output/stores//350/250/230/346/206/266/345/225/206/344/272/272/story-config.json +0 -4
  81. package/.output/.output/stores//350/250/230/346/206/266/345/225/206/344/272/272/story.json +0 -18
  82. package/.output/.output/stores//350/250/255/350/250/210/350/210/207/351/226/213/347/231/274/347/232/204/346/214/221/346/210/260/content.json +0 -22
  83. package/.output/.output/talks//344/273/245/347/254/221/350/251/261/347/202/272/345/237/272/347/244/216/347/232/204/351/235/242/350/251/246/content.json +0 -30
  84. package/.output/.output/talks//344/273/245/347/254/221/350/251/261/347/202/272/345/237/272/347/244/216/347/232/204/351/235/242/350/251/246/cover-1684055229695.png +0 -0
  85. package/.output/.output/talks//345/234/250/346/224/277/346/262/273/345/200/231/351/201/270/344/272/272/350/276/257/350/253/226/344/270/255/347/232/204/350/252/252/346/234/215/346/200/247/346/272/235/351/200/232/content.json +0 -30
  86. package/.output/.output/talks//345/234/250/346/224/277/346/262/273/345/200/231/351/201/270/344/272/272/350/276/257/350/253/226/344/270/255/347/232/204/350/252/252/346/234/215/346/200/247/346/272/235/351/200/232/cover-1684056611678.png +0 -0
  87. package/.output/.output/talks//346/224/276/351/254/206/347/232/204/345/200/231/351/201/270/344/272/272/351/200/262/350/241/214/346/224/277/346/262/273/350/276/257/350/253/226/content.json +0 -36
  88. package/.output/.output/talks//346/224/276/351/254/206/347/232/204/345/200/231/351/201/270/344/272/272/351/200/262/350/241/214/346/224/277/346/262/273/350/276/257/350/253/226/cover-1684055140609.png +0 -0
  89. package/.output/.output/talks//346/224/277/346/262/273/347/254/221/350/251/261/content.json +0 -30
  90. package/.output/.output/talks//346/224/277/346/262/273/347/254/221/350/251/261/cover-1684056246465.png +0 -0
  91. package/.output/.output/talks//350/251/274/350/253/247/345/256/266/351/225/267/346/225/231/345/270/253/346/234/203/350/255/260/content.json +0 -26
  92. package/.output/.output/talks//350/251/274/350/253/247/345/256/266/351/225/267/346/225/231/345/270/253/346/234/203/350/255/260/cover-1685785935121.png +0 -0
  93. package/.output/.output/talks//350/262/241/345/213/231/351/241/247/345/225/217/350/253/256/350/251/242/content.json +0 -26
  94. package/.output/.output/talks//350/262/241/345/213/231/351/241/247/345/225/217/350/253/256/350/251/242/cover-1685785115833.png +0 -0
  95. package/.output/.output/talks//351/206/253/347/224/237/345/222/214/347/227/205/344/272/272/350/250/216/350/253/226/346/202/262/345/202/267/content.json +0 -32
  96. package/.output/.output/talks//351/206/253/347/224/237/345/222/214/347/227/205/344/272/272/350/250/216/350/253/226/346/202/262/345/202/267/cover-1684055075942.png +0 -0
@@ -0,0 +1,62 @@
1
+ import JSON5 from 'json5'
2
+
3
+ type TextParserParams = {
4
+ /**
5
+ * @zh 解讀器名字。
6
+ * @en The name of the parser.
7
+ */
8
+ name: string
9
+ /**
10
+ * @zh 解讀文本。
11
+ * @en Read the text.
12
+ */
13
+ handler: (text: string) => Promise<any>
14
+ }
15
+
16
+ export class TextParser {
17
+ private params: TextParserParams
18
+
19
+ /**
20
+ * @zh 盡可能將文字內的 json 解讀出來。
21
+ * @en Try to read the json in the text as much as possible.
22
+ */
23
+
24
+ static JsonMessage() {
25
+ return new TextParser({
26
+ name: 'JsonMessage',
27
+ handler: async (text) => {
28
+ try {
29
+ const result = JSON.parse(text)
30
+ return result
31
+ } catch (error) {
32
+ const jsonRegex = /{(?:[^{}]|(?:{[^{}]*}))*}/
33
+ const matchedText = text.match(jsonRegex)?.[0] || ''
34
+ return JSON5.parse(matchedText)
35
+ }
36
+ }
37
+ })
38
+ }
39
+
40
+ constructor(params: TextParserParams) {
41
+ this.params = params
42
+ }
43
+
44
+ /**
45
+ * @zh 解讀器名字。
46
+ * @en The name of the parser.
47
+ */
48
+
49
+ get name() {
50
+ return this.params.name
51
+ }
52
+
53
+ /**
54
+ * @zh 解讀文本。
55
+ * @en Read the text.
56
+ */
57
+
58
+ async read(text: string) {
59
+ const result = await this.params.handler(text)
60
+ return result
61
+ }
62
+ }
@@ -0,0 +1,46 @@
1
+ import { Translator } from './translator'
2
+ import { ChatBrokerHooks } from '../broker/chat'
3
+ import { Log, Hook, Event } from 'power-helper'
4
+ import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
5
+
6
+ type BrokerHooks = ChatBrokerHooks<any, any, any, any>
7
+ type BrokerPluginParams<
8
+ T extends ValidateCallback<any>,
9
+ R extends ValidateCallback<any>
10
+ > = {
11
+ name: string
12
+ params: T
13
+ receiveData: R
14
+ onInstall: (context: {
15
+ log: Log
16
+ params: ValidateCallbackOutputs<T>
17
+ attach: Hook<BrokerHooks>['attach']
18
+ attachAfter: Hook<BrokerHooks>['attachAfter']
19
+ translator: Translator<any, any>
20
+ receive: (callback: (params: {
21
+ id: string
22
+ data: ValidateCallbackOutputs<R>
23
+ }) => void) => void
24
+ }) => void
25
+ }
26
+
27
+ export class ChatBrokerPlugin<
28
+ T extends ValidateCallback<any>,
29
+ R extends ValidateCallback<any>
30
+ > {
31
+ _event = new Event()
32
+ _params: BrokerPluginParams<T, R>
33
+ constructor(params: BrokerPluginParams<T, R>) {
34
+ this._params = params
35
+ }
36
+
37
+ use(params: ValidateCallbackOutputs<T>) {
38
+ return {
39
+ instance: this as any,
40
+ params,
41
+ send: (data: ValidateCallbackOutputs<R>) => { this._event.emit('receive', data) },
42
+ receive: (callback: any) => { this._event.on('receive', callback) },
43
+ __receiveData: null as unknown as ValidateCallbackOutputs<R>
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,115 @@
1
+ import { TextParser } from './parser'
2
+ import { validate, ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
3
+ import { ParserError } from '../utils/error'
4
+
5
+ export type TranslatorParams<
6
+ S extends ValidateCallback<any>,
7
+ O extends ValidateCallback<any>
8
+ > = {
9
+ /**
10
+ * @zh 輸入的資料格式。
11
+ * @en The input data format.
12
+ */
13
+ input?: S
14
+ /**
15
+ * @zh 輸出的資料格式。
16
+ * @en The output data format.
17
+ */
18
+ output: O
19
+ /**
20
+ * @zh 註冊解讀文字的解析器。
21
+ * @en Register the parser to interpret the text.
22
+ */
23
+ parsers: TextParser[]
24
+ /**
25
+ * @zh 組合輸入資料成為提示文字。
26
+ * @en Combine the input data into a prompt.
27
+ */
28
+ question?: (data: ValidateCallbackOutputs<S>, context: {
29
+ schema: {
30
+ input?: S
31
+ output: O
32
+ }
33
+ }) => Promise<string | string[]>
34
+ }
35
+
36
+ export class Translator<
37
+ S extends ValidateCallback<any>,
38
+ O extends ValidateCallback<any>
39
+ > {
40
+ private params: TranslatorParams<S, O>
41
+
42
+ constructor(params: TranslatorParams<S, O>) {
43
+ this.params = params
44
+ }
45
+
46
+ get __schemeType(): ValidateCallbackOutputs<S> {
47
+ return null as any
48
+ }
49
+ get __outputType(): ValidateCallbackOutputs<O> {
50
+ return null as any
51
+ }
52
+
53
+ /**
54
+ * @zh 組合輸入資料成為提示文字。
55
+ * @en Combine the input data into a prompt.
56
+ */
57
+
58
+ async compile(data: ValidateCallbackOutputs<S>, context: {
59
+ schema: {
60
+ input?: S
61
+ output: O
62
+ }
63
+ }) {
64
+ const scheme = this.params.input ? validate(data, this.params.input) : data
65
+ const prompt = this.params.question ? await this.params.question(scheme, context) : ''
66
+ return {
67
+ scheme,
68
+ prompt: Array.isArray(prompt) ? prompt.join('\n') : prompt
69
+ }
70
+ }
71
+
72
+ getValidate() {
73
+ return {
74
+ input: this.params.input,
75
+ output: this.params.output
76
+ }
77
+ }
78
+
79
+ changeOutputSchema(schema: O) {
80
+ this.params.output = schema
81
+ }
82
+
83
+ /**
84
+ * @zh 將文字轉換成序列化資料。
85
+ * @en Convert text to serialized data.
86
+ */
87
+
88
+ async parse(text: string) {
89
+ let result: any = undefined
90
+ let parserName = ''
91
+ let parserFails: { name: string, error: any }[] = []
92
+ for (let parse of this.params.parsers) {
93
+ try {
94
+ result = await parse.read(text)
95
+ parserName = parse.name
96
+ } catch (error) {
97
+ result = undefined
98
+ parserFails.push({
99
+ name: parse.name,
100
+ error
101
+ })
102
+ }
103
+ }
104
+ try {
105
+ let output = validate(result, this.params.output)
106
+ return {
107
+ output,
108
+ parserName,
109
+ parserFails
110
+ }
111
+ } catch (error) {
112
+ throw new ParserError(error, parserFails)
113
+ }
114
+ }
115
+ }
package/lib/ctod.ts ADDED
@@ -0,0 +1,71 @@
1
+ import { ChatBroker, Message, Params as ChatBrokerParams, ChatBrokerHooks, RequestContext } from './broker/chat'
2
+ import { ChatBrokerPlugin } from './core/plugin'
3
+ import { Schema } from 'yup'
4
+ import * as Yup from 'yup'
5
+
6
+ type IO = any
7
+
8
+ export class CtoD<
9
+ P extends ChatBrokerPlugin<IO, IO>,
10
+ PS extends Record<string, ReturnType<P['use']>>
11
+ > {
12
+ params
13
+ constructor(params: {
14
+ request: (messages: Message[], context: RequestContext) => Promise<string>
15
+ plugins?: () => PS
16
+ }) {
17
+ this.params = params
18
+ }
19
+
20
+ createBrokerBuilder<I extends Record<string, any>>(params?: {
21
+ install?: ChatBrokerParams<() => I, IO, ChatBrokerHooks<() => I, IO, P, PS>, P, PS>['install']
22
+ }) {
23
+ return {
24
+ create: <O extends Record<string, Schema>>(install: (context: {
25
+ id: string
26
+ yup: typeof Yup
27
+ data: I
28
+ plugins: {
29
+ [K in keyof PS]: {
30
+ send: (data: PS[K]['__receiveData']) => void
31
+ }
32
+ }
33
+ setMessages: (messages: (Omit<Message, 'content'> & { content: string | string[] })[]) => void
34
+ metadata: Map<string, any>
35
+ }) => Promise<O>) => {
36
+ return new ChatBroker<
37
+ () => I,
38
+ () => O,
39
+ P,
40
+ PS,
41
+ ChatBrokerHooks<() => I, () => O, P, PS>
42
+ >({
43
+ output: () => ({} as any),
44
+ install: (context) => {
45
+ params?.install?.(context)
46
+ context.attach('start', async({ id, plugins, data, metadata, changeMessages, changeOutputSchema }) => {
47
+ const schema = await install({
48
+ id,
49
+ data: data as any,
50
+ plugins,
51
+ yup: Yup,
52
+ setMessages: (messages) => {
53
+ changeMessages(messages.map(e => {
54
+ return {
55
+ role: e.role,
56
+ content: Array.isArray(e.content) ? e.content.join('\n') : e.content
57
+ }
58
+ }))
59
+ },
60
+ metadata
61
+ })
62
+ changeOutputSchema(() => schema)
63
+ })
64
+ },
65
+ plugins: this.params.plugins ? (() => this.params.plugins!()) : undefined,
66
+ request: this.params.request
67
+ })
68
+ }
69
+ }
70
+ }
71
+ }
package/lib/index.ts ADDED
@@ -0,0 +1,41 @@
1
+ export * as plugins from './plugins'
2
+ export * as templates from './templates'
3
+ export { CtoD } from './ctod'
4
+ export { validateToJsonSchema, defineYupSchema, ValidateCallback } from './utils/validate'
5
+ export { OpenAI } from './service/openai'
6
+ export { Llama3Cpp } from './service/llama3.cpp'
7
+ export { TextParser } from './core/parser'
8
+ export { ChatGPTMessage } from './service/openai/chat'
9
+ export { ChatBroker } from './broker/chat'
10
+ export { ChatBrokerPlugin } from './core/plugin'
11
+ export { Translator, TranslatorParams } from './core/translator'
12
+
13
+ import * as plugins from './plugins'
14
+ import * as templates from './templates'
15
+ import { OpenAI } from './service/openai'
16
+ import { CtoD } from './ctod'
17
+ import { Llama3Cpp } from './service/llama3.cpp'
18
+ import { Translator } from './core/translator'
19
+ import { TextParser } from './core/parser'
20
+ import { ChatBroker } from './broker/chat'
21
+ import { ChatBrokerPlugin } from './core/plugin'
22
+ import { validateToJsonSchema, defineYupSchema } from './utils/validate'
23
+
24
+ export const ctod = {
25
+ CtoD,
26
+ OpenAI,
27
+ Llama3Cpp,
28
+ plugins,
29
+ templates,
30
+ ChatBroker,
31
+ Translator,
32
+ TextParser,
33
+ ChatBrokerPlugin,
34
+ defineYupSchema,
35
+ validateToJsonSchema
36
+ }
37
+
38
+ module.exports = ctod
39
+ module.exports.ctod = ctod
40
+
41
+ export default ctod
@@ -0,0 +1,38 @@
1
+ import Retry from './retry'
2
+ import PrintLog from './print-log'
3
+ import Limiter from './limiter'
4
+ import Role from './role'
5
+
6
+ /**
7
+ * @zh 一個基於印出 log 的 plugin。
8
+ * @en A plugin based on printing log.
9
+ */
10
+
11
+ export const PrintLogPlugin = PrintLog
12
+
13
+ /**
14
+ * @zh 當解析失敗時,會自動重試的對話。
15
+ * @en A conversation that will automatically retry when parsing fails.
16
+ */
17
+
18
+ export const RetryPlugin = Retry
19
+
20
+ /**
21
+ * @zh 限制使用流量,這個 plugin 可以有效讓所有對話不會再限制內同時發送,可用於在開發過程中遭遇伺服器因頻率過高而阻擋請求。
22
+ * @en Limit the use of traffic. This plugin can effectively prevent all conversations from being sent at the same time within the limit, and can be used when the server blocks requests due to high frequency during development.
23
+ */
24
+
25
+ export const LimiterPlugin = Limiter.plugin
26
+
27
+ /**
28
+ * @zh 排程系統將全域託管,有什麼必要設定可以來更動它的狀態,例如:關閉排程。
29
+ * @en The scheduling system will be globally hosted. What is necessary to set can come to change its status, for example: close the schedule.
30
+ */
31
+ export const LimiterPluginGlobState = Limiter
32
+
33
+ /**
34
+ * @zh 設定角色扮演。
35
+ * @en Set role play.
36
+ */
37
+
38
+ export const RolePlugin = Role
@@ -0,0 +1,103 @@
1
+ import { ChatBrokerPlugin } from '../core/plugin'
2
+ import { Event, flow, Schedule } from 'power-helper'
3
+
4
+ type Events = {
5
+ run: {
6
+ id: string
7
+ }
8
+ waitTimeChange: {
9
+ waitTime: number
10
+ }
11
+ }
12
+
13
+ const config = {
14
+ limit: 3,
15
+ interval: 60000,
16
+ }
17
+
18
+ const state = {
19
+ event: new Event<Events>(),
20
+ schedule: null as Schedule | null,
21
+ waitTimes: [] as number[],
22
+ waitQueue: [] as string[]
23
+ }
24
+
25
+ export default {
26
+ /**
27
+ * @zh 你可以監聽一些事件行為,例如還需要等待多少時間。
28
+ * @en You can listen for some event behaviors, such as how long you still need to wait.
29
+ */
30
+
31
+ event: state.event,
32
+
33
+ /**
34
+ * @zh 預設是每分鐘限制3次,你可以在設定中改變限制流量。
35
+ * @en By default, the limit is 3 times per minute, and you can change the limit flow in the settings.
36
+ */
37
+
38
+ config,
39
+
40
+ /**
41
+ * @zh 由於排程會在背景持續倒數,如果有關閉程式的需求,需要手動進行移除。
42
+ * @en Since the schedule will continue to count down in the background, if there is a need to close the program, you need to manually remove it.
43
+ */
44
+
45
+ closeSchedule: () => {
46
+ if (state.schedule) {
47
+ state.schedule.close()
48
+ state.schedule = null
49
+ }
50
+ },
51
+
52
+ /**
53
+ * @zh Plugin 的接口
54
+ * @en Plugin interface
55
+ */
56
+
57
+ plugin: new ChatBrokerPlugin({
58
+ name: 'limiter',
59
+ params: () => {
60
+ return {}
61
+ },
62
+ receiveData: () => {
63
+ return {}
64
+ },
65
+ onInstall({ attach }) {
66
+ if (state.schedule == null) {
67
+ state.schedule = new Schedule()
68
+ state.schedule.add('calc queue', 1000, async() => {
69
+ const now = Date.now()
70
+ state.waitTimes = state.waitTimes.filter(time => {
71
+ return now - time < config.interval
72
+ })
73
+ if (state.waitTimes.length !== config.limit) {
74
+ let nextId = state.waitQueue.shift()
75
+ if (nextId) {
76
+ state.waitTimes.push(Date.now())
77
+ state.event.emit('run', {
78
+ id: nextId
79
+ })
80
+ }
81
+ } else if (state.waitTimes[0]) {
82
+ state.event.emit('waitTimeChange', {
83
+ waitTime: Math.floor(60 - (now - state.waitTimes[0]) / 1000)
84
+ })
85
+ }
86
+ })
87
+ state.schedule.play()
88
+ }
89
+ attach('talkBefore', async() => {
90
+ const uid = flow.createUuid()
91
+ state.waitQueue.push(uid)
92
+ return new Promise(resolve => {
93
+ state.event.on('run', ({ id }, { off }) => {
94
+ if (id === uid) {
95
+ off()
96
+ resolve()
97
+ }
98
+ })
99
+ })
100
+ })
101
+ }
102
+ })
103
+ }
@@ -0,0 +1,35 @@
1
+ import { ChatBrokerPlugin } from '../core/plugin'
2
+
3
+ export default new ChatBrokerPlugin({
4
+ name: 'print-log',
5
+ params: yup => {
6
+ return {
7
+ detail: yup.boolean().default(false)
8
+ }
9
+ },
10
+ receiveData: () => {
11
+ return {}
12
+ },
13
+ onInstall({ params, log, attach }) {
14
+ attach('talkBefore', async({ lastUserMessage, messages }) => {
15
+ log.print('Send:', { color: 'green' })
16
+ if (params.detail) {
17
+ log.print('\n' + JSON.stringify(messages, null, 4))
18
+ } else {
19
+ log.print('\n' + lastUserMessage)
20
+ }
21
+ })
22
+ attach('talkAfter', async({ parseText }) => {
23
+ log.print('Receive:', { color: 'cyan' })
24
+ log.print('\n' + parseText)
25
+ })
26
+ attach('succeeded', async({ output }) => {
27
+ log.print('Output:', { color: 'yellow' })
28
+ try {
29
+ log.print('\n' + JSON.stringify(output, null, 4))
30
+ } catch (error) {
31
+ log.print('\n' + output)
32
+ }
33
+ })
34
+ }
35
+ })
@@ -0,0 +1,25 @@
1
+ import { ChatBrokerPlugin } from '../core/plugin'
2
+
3
+ export default new ChatBrokerPlugin({
4
+ name: 'retry',
5
+ params: yup => {
6
+ return {
7
+ retry: yup.number().required().default(1),
8
+ printWarn: yup.boolean().required().default(true)
9
+ }
10
+ },
11
+ receiveData: () => {
12
+ return {}
13
+ },
14
+ onInstall({ log, attach, params }) {
15
+ attach('parseFailed', async({ count, retry, messages, changeMessages }) => {
16
+ if (count <= params.retry) {
17
+ if (params.printWarn) {
18
+ log.print(`Is Failed, Retry ${count} times.`)
19
+ }
20
+ changeMessages(messages)
21
+ retry()
22
+ }
23
+ })
24
+ }
25
+ })
@@ -0,0 +1,28 @@
1
+ import { ChatBrokerPlugin } from '../core/plugin'
2
+
3
+ export default new ChatBrokerPlugin({
4
+ name: 'role',
5
+ params: yup => {
6
+ return {
7
+ role: yup.string().required()
8
+ }
9
+ },
10
+ receiveData: () => {
11
+ return {}
12
+ },
13
+ onInstall({ attach, params }) {
14
+ attach('start', async({ messages, changeMessages }) => {
15
+ changeMessages([
16
+ {
17
+ role: 'user',
18
+ content: `你現在是${params.role}。`
19
+ },
20
+ {
21
+ role: 'assistant',
22
+ content: `沒問題,我現在是${params.role},有什麼可以幫你的嗎?`
23
+ },
24
+ ...messages
25
+ ])
26
+ })
27
+ }
28
+ })