ctod 0.0.4 → 0.0.6

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/lib/broker/35.ts CHANGED
@@ -1,43 +1,100 @@
1
1
  import { flow } from 'power-helper'
2
2
  import { BaseBroker } from './index'
3
3
  import { Translator } from '../core/translator'
4
+ import { Broker35Plugin } from '../core/plugin'
4
5
  import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
5
6
  import { ChatGPT35, ChatGPT35Message, ChatGPT35TalkResponse } from '../service/chatgpt35'
6
7
 
7
8
  export class ChatGPT35Broker<
8
9
  S extends ValidateCallback<any>,
9
10
  O extends ValidateCallback<any>
10
- > extends BaseBroker<S, O, {
11
+ > extends BaseBroker<S, O, Broker35Plugin<any>, {
12
+
13
+ /**
14
+ * @zh 第一次聊天的時候觸發
15
+ * @en Triggered when chatting for the first time
16
+ */
17
+
11
18
  talkFirst: {
19
+ id: string
12
20
  data: ValidateCallbackOutputs<S>
13
21
  messages: ChatGPT35Message[]
14
22
  changeMessages: (messages: ChatGPT35Message[]) => void
15
23
  }
24
+
25
+ /**
26
+ * @zh 發送聊天訊息給機器人前觸發
27
+ * @en Triggered before sending chat message to bot
28
+ */
29
+
16
30
  talkBefore: {
31
+ id: string
17
32
  data: ValidateCallbackOutputs<S>
18
33
  messages: ChatGPT35Message[]
34
+ lastUserMessage: string
19
35
  }
36
+
37
+ /**
38
+ * @zh 當聊天機器人回傳資料的時候觸發
39
+ * @en Triggered when the chatbot returns data
40
+ */
41
+
20
42
  talkAfter: {
43
+ id: string
21
44
  data: ValidateCallbackOutputs<S>
22
45
  response: ChatGPT35TalkResponse
23
46
  messages: ChatGPT35Message[]
24
47
  parseText: string
48
+ lastUserMessage: string
25
49
  changeParseText: (text: string) => void
26
50
  }
51
+
52
+ /**
53
+ * @zh 當回傳資料符合規格時觸發
54
+ * @en Triggered when the returned data meets the specifications
55
+ */
56
+
57
+ succeeded: {
58
+ id: string
59
+ output: ValidateCallbackOutputs<O>
60
+ }
61
+
62
+ /**
63
+ * @zh 當回傳資料不符合規格,或是解析錯誤時觸發
64
+ * @en Triggered when the returned data does not meet the specifications or parsing errors
65
+ */
66
+
27
67
  parseFailed: {
68
+ id: string
28
69
  error: any
29
70
  retry: () => void
30
71
  count: number
31
72
  response: ChatGPT35TalkResponse
32
73
  parserFails: { name: string, error: any }[]
33
74
  messages: ChatGPT35Message[]
75
+ lastUserMessage: string
34
76
  changeMessages: (messages: ChatGPT35Message[]) => void
35
77
  }
78
+
79
+ /**
80
+ * @zh 不論成功失敗,執行結束的時候會執行。
81
+ * @en It will be executed when the execution is completed, regardless of success or failure.
82
+ */
83
+
84
+ done: {
85
+ id: string
86
+ }
36
87
  }> {
37
88
  bot: ChatGPT35 = new ChatGPT35()
38
89
 
90
+ /**
91
+ * @zh 將請求發出至聊天機器人。
92
+ * @en Send request to chatbot.
93
+ */
94
+
39
95
  async request<T extends Translator<S, O>>(data: T['__schemeType']): Promise<T['__outputType']> {
40
96
  this._install()
97
+ let id = flow.createUuid()
41
98
  let output: any = null
42
99
  let question = await this.translator.compile(data)
43
100
  let messages: ChatGPT35Message[] = [
@@ -46,7 +103,8 @@ export class ChatGPT35Broker<
46
103
  content: question.prompt
47
104
  }
48
105
  ]
49
- await this.notify('talkFirst', {
106
+ await this.hook.notify('talkFirst', {
107
+ id,
50
108
  data,
51
109
  messages,
52
110
  changeMessages: ms => {
@@ -60,33 +118,45 @@ export class ChatGPT35Broker<
60
118
  let response: ChatGPT35TalkResponse = null as any
61
119
  let parseText = ''
62
120
  let retryFlag = false
121
+ let lastUserMessage = messages.filter(e => e.role === 'user').slice(-1)[0]?.content || ''
63
122
  try {
64
- await this.notify('talkBefore', {
123
+ await this.hook.notify('talkBefore', {
124
+ id,
65
125
  data,
66
- messages
126
+ messages,
127
+ lastUserMessage
67
128
  })
68
129
  response = await this.bot.talk(messages)
69
130
  parseText = response.text
70
- await this.notify('talkAfter', {
131
+ await this.hook.notify('talkAfter', {
132
+ id,
71
133
  data,
72
134
  response,
73
135
  parseText,
74
136
  messages: response.newMessages,
137
+ lastUserMessage,
75
138
  changeParseText: text => {
76
139
  parseText = text
77
140
  }
78
141
  })
79
142
  messages = response.newMessages
80
143
  output = (await this.translator.parse(response.text)).output
144
+ await this.hook.notify('succeeded', {
145
+ id,
146
+ output
147
+ })
148
+ await this.hook.notify('done', { id })
81
149
  doBreak()
82
150
  } catch (error: any) {
83
151
  // 如果解析錯誤,可以選擇是否重新解讀
84
152
  if (error.isParserError) {
85
- await this.notify('parseFailed', {
153
+ await this.hook.notify('parseFailed', {
154
+ id,
86
155
  error: error.error,
87
156
  count,
88
157
  response,
89
158
  messages,
159
+ lastUserMessage,
90
160
  parserFails: error.parserFails,
91
161
  retry: () => {
92
162
  retryFlag = true
@@ -99,6 +169,7 @@ export class ChatGPT35Broker<
99
169
  return doBreak()
100
170
  }
101
171
  }
172
+ await this.hook.notify('done', { id })
102
173
  throw error
103
174
  }
104
175
  })
@@ -4,15 +4,19 @@ import { ChatGPT35 } from '../service/chatgpt35'
4
4
  import { TextParser } from '../core/parser'
5
5
  import { ValidateCallback } from '../utils/validate'
6
6
  import { Translator, TranslatorParams } from '../core/translator'
7
+ import { Broker3Plugin, Broker35Plugin } from '../core/plugin'
7
8
 
8
9
  export type Params<
9
10
  S extends ValidateCallback<any>,
10
11
  O extends ValidateCallback<any>,
11
- C extends Record<string, any>
12
+ C extends Record<string, any>,
13
+ P extends Broker3Plugin<any> | Broker35Plugin<any>
12
14
  > = Omit<TranslatorParams<S, O>, 'parsers'> & {
15
+ plugins?: ReturnType<P['use']>[]
13
16
  install: (context: {
14
17
  bot: ChatGPT3 | ChatGPT35
15
18
  attach: Hook<C>['attach']
19
+ attachAfter: Hook<C>['attachAfter']
16
20
  translator: Translator<S, O>
17
21
  }) => void
18
22
  }
@@ -20,15 +24,17 @@ export type Params<
20
24
  export class BaseBroker<
21
25
  S extends ValidateCallback<any>,
22
26
  O extends ValidateCallback<any>,
27
+ P extends Broker3Plugin<any> | Broker35Plugin<any>,
23
28
  C extends Record<string, any>
24
- > extends Hook<C> {
29
+ > {
30
+ protected hook = new Hook<C>()
25
31
  protected bot!: ChatGPT3 | ChatGPT35
26
- protected params: Params<S, O, C>
32
+ protected params: Params<S, O, C, P>
27
33
  protected installed = false
28
34
  protected translator: Translator<S, O>
35
+ protected __hookType!: C
29
36
 
30
- constructor(params: Params<S, O, C>) {
31
- super()
37
+ constructor(params: Params<S, O, C, P>) {
32
38
  this.params = params
33
39
  this.translator = new Translator({
34
40
  ...params,
@@ -42,11 +48,21 @@ export class BaseBroker<
42
48
  if (this.installed === false) {
43
49
  this.installed = true
44
50
  if (this.bot) {
45
- this.params.install({
51
+ const context = {
46
52
  bot: this.bot,
47
- attach: this.attach.bind(this),
53
+ attach: this.hook.attach.bind(this.hook),
54
+ attachAfter: this.hook.attachAfter.bind(this.hook),
48
55
  translator: this.translator
49
- })
56
+ }
57
+ if (this.params.plugins) {
58
+ for (let plugin of this.params.plugins) {
59
+ plugin.instance._params.onInstall({
60
+ ...context as any,
61
+ params: plugin.params
62
+ })
63
+ }
64
+ }
65
+ this.params.install(context)
50
66
  }
51
67
  }
52
68
  }
@@ -2,11 +2,13 @@ import JSON5 from 'json5'
2
2
 
3
3
  type TextParserParams = {
4
4
  /**
5
- * 解讀器名字
5
+ * @zh 解讀器名字。
6
+ * @en The name of the parser.
6
7
  */
7
8
  name: string
8
9
  /**
9
- * 解讀文本
10
+ * @zh 解讀文本。
11
+ * @en Read the text.
10
12
  */
11
13
  handler: (text: string) => Promise<any>
12
14
  }
@@ -15,7 +17,8 @@ export class TextParser {
15
17
  private params: TextParserParams
16
18
 
17
19
  /**
18
- * 盡可能將文字內的 json 解讀出來
20
+ * @zh 盡可能將文字內的 json 解讀出來。
21
+ * @en Try to read the json in the text as much as possible.
19
22
  */
20
23
 
21
24
  static JsonMessage() {
@@ -34,7 +37,8 @@ export class TextParser {
34
37
  }
35
38
 
36
39
  /**
37
- * 解讀器名字
40
+ * @zh 解讀器名字。
41
+ * @en The name of the parser.
38
42
  */
39
43
 
40
44
  get name() {
@@ -42,7 +46,8 @@ export class TextParser {
42
46
  }
43
47
 
44
48
  /**
45
- * 解讀文本
49
+ * @zh 解讀文本。
50
+ * @en Read the text.
46
51
  */
47
52
 
48
53
  async read(text: string) {
@@ -0,0 +1,64 @@
1
+ import { Hook } from 'power-helper'
2
+ import { ChatGPT3 } from '../service/chatgpt3'
3
+ import { ChatGPT35 } from '../service/chatgpt35'
4
+ import { ChatGPT3Broker } from '../broker/3'
5
+ import { ChatGPT35Broker } from '../broker/35'
6
+ import { Translator } from './translator'
7
+ import { ValidateCallback, ValidateCallbackOutputs } from '../utils/validate'
8
+
9
+ // 3
10
+
11
+ type Broker3Hooks = ChatGPT3Broker<any, any>['__hookType']
12
+ type Broker3PluginParams<T extends ValidateCallback<any>> = {
13
+ name: string
14
+ params: T
15
+ onInstall: (context: {
16
+ bot: ChatGPT3
17
+ params: ValidateCallbackOutputs<T>
18
+ attach: Hook<Broker3Hooks>['attach']
19
+ attachAfter: Hook<Broker3Hooks>['attachAfter']
20
+ translator: Translator<any, any>
21
+ }) => void
22
+ }
23
+
24
+ export class Broker3Plugin<T extends ValidateCallback<any>> {
25
+ _params: Broker3PluginParams<T>
26
+ constructor(params: Broker3PluginParams<T>) {
27
+ this._params = params
28
+ }
29
+ use(params: ValidateCallbackOutputs<T>) {
30
+ return {
31
+ instance: this as any,
32
+ params
33
+ }
34
+ }
35
+ }
36
+
37
+ // 3.5
38
+
39
+ type Broker35Hooks = ChatGPT35Broker<any, any>['__hookType']
40
+ type Broker35PluginParams<T extends ValidateCallback<any>> = {
41
+ name: string
42
+ params: T
43
+ onInstall: (context: {
44
+ bot: ChatGPT35
45
+ params: ValidateCallbackOutputs<T>
46
+ attach: Hook<Broker35Hooks>['attach']
47
+ attachAfter: Hook<Broker35Hooks>['attachAfter']
48
+ translator: Translator<any, any>
49
+ }) => void
50
+ }
51
+
52
+ export class Broker35Plugin<T extends ValidateCallback<any>> {
53
+ _params: Broker35PluginParams<T>
54
+ constructor(params: Broker35PluginParams<T>) {
55
+ this._params = params
56
+ }
57
+
58
+ use(params: ValidateCallbackOutputs<T>) {
59
+ return {
60
+ instance: this as any,
61
+ params
62
+ }
63
+ }
64
+ }
@@ -5,9 +5,25 @@ export type TranslatorParams<
5
5
  S extends ValidateCallback<any>,
6
6
  O extends ValidateCallback<any>
7
7
  > = {
8
- scheme: S
8
+ /**
9
+ * @zh 輸入的資料格式。
10
+ * @en The input data format.
11
+ */
12
+ input: S
13
+ /**
14
+ * @zh 輸出的資料格式。
15
+ * @en The output data format.
16
+ */
9
17
  output: O
18
+ /**
19
+ * @zh 註冊解讀文字的解析器。
20
+ * @en Register the parser to interpret the text.
21
+ */
10
22
  parsers: TextParser[]
23
+ /**
24
+ * @zh 組合輸入資料成為提示文字。
25
+ * @en Combine the input data into a prompt.
26
+ */
11
27
  assembly: (data: ValidateCallbackOutputs<S>) => Promise<string>
12
28
  }
13
29
 
@@ -28,8 +44,13 @@ export class Translator<
28
44
  return null as any
29
45
  }
30
46
 
47
+ /**
48
+ * @zh 組合輸入資料成為提示文字。
49
+ * @en Combine the input data into a prompt.
50
+ */
51
+
31
52
  async compile(data: ValidateCallbackOutputs<S>) {
32
- const scheme = validate(data, this.params.scheme)
53
+ const scheme = validate(data, this.params.input)
33
54
  const prompt = await this.params.assembly(scheme)
34
55
  return {
35
56
  scheme,
@@ -37,6 +58,11 @@ export class Translator<
37
58
  }
38
59
  }
39
60
 
61
+ /**
62
+ * @zh 將文字轉換成序列化資量。
63
+ * @en Convert text to serialized data.
64
+ */
65
+
40
66
  async parse(text: string) {
41
67
  let result: any = undefined
42
68
  let parserName = ''
package/lib/index.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /* eslint-disable no-redeclare */
2
2
 
3
+ import * as _Plugins from './core/plugin'
4
+ import * as _plugins from './plugins'
3
5
  import * as _templates from './templates'
4
6
  import * as _Translator from './core/translator'
5
7
  import { ValidateCallback } from './utils/validate'
@@ -14,6 +16,8 @@ export type Translator<S extends ValidateCallback<any>, O extends ValidateCallba
14
16
  export type TranslatorParams<S extends ValidateCallback<any>, O extends ValidateCallback<any>> = _Translator.TranslatorParams<S, O>
15
17
  export type ChatGPT3Broker<S extends ValidateCallback<any>, O extends ValidateCallback<any>> = _ChatGPT3Broker<S, O>
16
18
  export type ChatGPT35Broker<S extends ValidateCallback<any>, O extends ValidateCallback<any>> = _ChatGPT35Broker<S, O>
19
+ export type Broker3Plugin<T extends ValidateCallback<any>> = _Plugins.Broker3Plugin<T>
20
+ export type Broker35Plugin<T extends ValidateCallback<any>> = _Plugins.Broker35Plugin<T>
17
21
 
18
22
  export const TextParser = _TextParser
19
23
  export const Translator = _Translator.Translator
@@ -21,14 +25,21 @@ export const ChatGPT3 = _ChatGPT3
21
25
  export const ChatGPT35 = _ChatGPT35
22
26
  export const ChatGPT3Broker = _ChatGPT3Broker
23
27
  export const ChatGPT35Broker = _ChatGPT35Broker
28
+ export const Broker3Plugin = _Plugins.Broker3Plugin
29
+ export const Broker35Plugin = _Plugins.Broker35Plugin
30
+
31
+ export const plugins = _plugins
24
32
  export const templates = _templates
25
33
 
26
34
  export const ctod = {
35
+ plugins,
27
36
  templates,
28
37
  ChatGPT3,
29
38
  ChatGPT35,
30
39
  Translator,
31
40
  TextParser,
41
+ Broker3Plugin,
42
+ Broker35Plugin,
32
43
  ChatGPT3Broker,
33
44
  ChatGPT35Broker
34
45
  }
package/lib/plugins.ts ADDED
@@ -0,0 +1,72 @@
1
+ import { Log } from 'power-helper'
2
+ import { Broker35Plugin, Broker3Plugin } from './core/plugin'
3
+
4
+ /**
5
+ * @zh 一個基於印出 log 的 plugin。
6
+ * @en A plugin based on printing log.
7
+ */
8
+
9
+ export const PrintLogPlugin = {
10
+
11
+ /**
12
+ * @zh 用於 Broker3 的版本。
13
+ * @en The version for Broker3.
14
+ */
15
+
16
+ ver3: new Broker3Plugin({
17
+ name: 'print-log',
18
+ params: () => {
19
+ return {}
20
+ },
21
+ onInstall({ attach }) {
22
+ const log = new Log('print-log-plugin')
23
+ attach('talkBefore', async({ prompt }) => {
24
+ log.print('Send:', { color: 'green' })
25
+ log.print(prompt)
26
+ })
27
+ attach('talkAfter', async({ parseText }) => {
28
+ log.print('Receive:', { color: 'red' })
29
+ log.print(parseText)
30
+ })
31
+ attach('succeeded', async({ output }) => {
32
+ log.print('Output:', { color: 'yellow' })
33
+ try {
34
+ log.print('\n' + JSON.stringify(output, null, 4))
35
+ } catch (error) {
36
+ log.print('\n' + output)
37
+ }
38
+ })
39
+ }
40
+ }),
41
+
42
+ /**
43
+ * @zh 用於 Broker35 的版本。
44
+ * @en The version for Broker35.
45
+ */
46
+
47
+ ver35: new Broker35Plugin({
48
+ name: 'print-log',
49
+ params: () => {
50
+ return {}
51
+ },
52
+ onInstall({ attach }) {
53
+ const log = new Log('print-log-plugin')
54
+ attach('talkBefore', async({ lastUserMessage }) => {
55
+ log.print('Send:', { color: 'green' })
56
+ log.print('\n' + lastUserMessage)
57
+ })
58
+ attach('talkAfter', async({ parseText }) => {
59
+ log.print('Receive:', { color: 'cyan' })
60
+ log.print('\n' + parseText)
61
+ })
62
+ attach('succeeded', async({ output }) => {
63
+ log.print('Output:', { color: 'yellow' })
64
+ try {
65
+ log.print('\n' + JSON.stringify(output, null, 4))
66
+ } catch (error) {
67
+ log.print('\n' + output)
68
+ }
69
+ })
70
+ }
71
+ })
72
+ }
@@ -1,4 +1,4 @@
1
- import axios from 'axios'
1
+ import axios, { AxiosInstance } from 'axios'
2
2
  import { PromiseResponseType } from '../types'
3
3
 
4
4
  type Config = {
@@ -6,7 +6,7 @@ type Config = {
6
6
  * @zh 一次回應數量
7
7
  * @en How many chat completion choices to generate for each input message.
8
8
  */
9
- n: 1
9
+ n: number
10
10
  /**
11
11
  * @zh 最長回應長度,最大值為 4096。
12
12
  * @en The token count of your prompt plus max_tokens cannot exceed the model's context length. Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
@@ -39,6 +39,7 @@ type ApiResponse = {
39
39
  }
40
40
 
41
41
  export class ChatGPT3 {
42
+ private axios = axios.create()
42
43
  private apiKey = ''
43
44
  private config: Config = {
44
45
  n: 1,
@@ -46,16 +47,40 @@ export class ChatGPT3 {
46
47
  temperature: 1
47
48
  }
48
49
 
50
+ /**
51
+ * @zh 如果你有需要特別設定 axios,請使用這方法。
52
+ * @en If you need to set axios, please use this method.
53
+ */
54
+
55
+ setAxios(axios: AxiosInstance) {
56
+ this.axios = axios
57
+ }
58
+
59
+ /**
60
+ * @zh 設定 api key。
61
+ * @en Set api key.
62
+ */
63
+
49
64
  setConfiguration(apiKey: string) {
50
65
  this.apiKey = apiKey
51
66
  }
52
67
 
68
+ /**
69
+ * @zh 改變對話的一些設定。
70
+ * @en Change some settings of the chat.
71
+ */
72
+
53
73
  setConfig(options: Partial<Config>) {
54
74
  Object.assign(this.config, options)
55
75
  }
56
76
 
77
+ /**
78
+ * @zh 進行對話。
79
+ * @en Talk to the chatbot.
80
+ */
81
+
57
82
  async talk(prompt: string | string[]) {
58
- const result = await axios.post<ApiResponse>('https://api.openai.com/v1/completions', {
83
+ const result = await this.axios.post<ApiResponse>('https://api.openai.com/v1/completions', {
59
84
  model: 'text-davinci-003',
60
85
  n: this.config.n,
61
86
  prompt: Array.isArray(prompt) ? prompt.join('\n') : prompt,
@@ -1,4 +1,4 @@
1
- import axios from 'axios'
1
+ import axios, { AxiosInstance } from 'axios'
2
2
  import { json } from 'power-helper'
3
3
  import { PromiseResponseType } from '../types'
4
4
 
@@ -31,7 +31,7 @@ type Config = {
31
31
  * @zh 一次回應數量
32
32
  * @en How many chat completion choices to generate for each input message.
33
33
  */
34
- n: 1
34
+ n: number
35
35
  /**
36
36
  * @zh 最長回應長度,最大值為 4096。
37
37
  * @en The token count of your prompt plus max_tokens cannot exceed the model's context length. Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
@@ -46,6 +46,7 @@ type Config = {
46
46
  }
47
47
 
48
48
  export class ChatGPT35 {
49
+ private axios = axios.create()
49
50
  private apiKey = ''
50
51
  private config: Config = {
51
52
  n: 1,
@@ -55,6 +56,7 @@ export class ChatGPT35 {
55
56
 
56
57
  /**
57
58
  * @zh 獲取 DAN 指令啟用的 message
59
+ * @en Get the message that enables the DAN command
58
60
  */
59
61
 
60
62
  static getJailbrokenMessages(): Array<ChatGPT35Message> {
@@ -83,8 +85,18 @@ export class ChatGPT35 {
83
85
  ]
84
86
  }
85
87
 
88
+ /**
89
+ * @zh 如果你有需要特別設定 axios,請使用這方法
90
+ * @en If you need to set axios, use this method
91
+ */
92
+
93
+ setAxios(axios: AxiosInstance) {
94
+ this.axios = axios
95
+ }
96
+
86
97
  /**
87
98
  * @zh 設定 api key
99
+ * @en Set api key
88
100
  */
89
101
 
90
102
  setConfiguration(apiKey: string) {
@@ -92,7 +104,8 @@ export class ChatGPT35 {
92
104
  }
93
105
 
94
106
  /**
95
- * @zh 設定 api key
107
+ * @zh 改變對話的一些設定
108
+ * @en Change some settings of the conversation
96
109
  */
97
110
 
98
111
  setConfig(options: Partial<Config>) {
@@ -101,11 +114,12 @@ export class ChatGPT35 {
101
114
 
102
115
  /**
103
116
  * @zh 進行對話
117
+ * @en Talk to the AI
104
118
  */
105
119
 
106
120
  async talk(messages: ChatGPT35Message[] = []) {
107
121
  const newMessages = json.jpjs(messages)
108
- const result = await axios.post<ApiResponse>('https://api.openai.com/v1/chat/completions', {
122
+ const result = await this.axios.post<ApiResponse>('https://api.openai.com/v1/chat/completions', {
109
123
  model: 'gpt-3.5-turbo',
110
124
  n: this.config.n,
111
125
  messages: newMessages,
package/lib/templates.ts CHANGED
@@ -3,7 +3,7 @@ type JsonResponseFormat = {
3
3
  example: any
4
4
  }
5
5
  /**
6
- * @zh 協助使用者將格式需求轉成論敘語句
6
+ * @zh 協助使用者將格式需求轉成論敘語句。
7
7
  * @en Assist the user in converting the formatting requirements into declarative sentences.
8
8
  */
9
9