ctod 0.0.5 → 0.0.7
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-TW.md +61 -3
- package/README.md +62 -3
- package/dist/index.js +1 -1
- package/examples/applications/bbc-news-reader.ts +218 -0
- package/examples/applications/story-generations.ts +129 -0
- package/examples/applications/talk-generations.ts +255 -0
- package/examples/chatgpt3.5-broker.ts +1 -0
- package/examples/utils/index.ts +56 -0
- package/lib/broker/3.ts +49 -0
- package/lib/broker/35.ts +61 -2
- package/lib/core/parser.ts +10 -5
- package/lib/core/translator.ts +26 -0
- package/lib/index.ts +5 -1
- package/lib/plugins.ts +21 -0
- package/lib/service/chatgpt3.ts +8 -4
- package/lib/service/chatgpt35.ts +5 -0
- package/lib/service/images-generations.ts +78 -0
- package/lib/templates.ts +1 -1
- package/logo.ai +1142 -1
- package/logo.png +0 -0
- package/package.json +4 -3
- package/types/lib/broker/3.d.ts +31 -0
- package/types/lib/broker/35.d.ts +36 -0
- package/types/lib/core/parser.d.ts +10 -5
- package/types/lib/core/translator.d.ts +24 -0
- package/types/lib/index.d.ts +4 -0
- package/types/lib/plugins.d.ts +9 -0
- package/types/lib/service/chatgpt3.d.ts +8 -4
- package/types/lib/service/chatgpt35.d.ts +5 -0
- package/types/lib/service/images-generations.d.ts +45 -0
- package/types/lib/templates.d.ts +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { flow, array } from 'power-helper'
|
|
2
|
+
import { ImagesGenerations } from '../../lib/service/images-generations'
|
|
3
|
+
import { definedOutputDir, getKey } from '../utils'
|
|
4
|
+
import { ChatGPT35Broker, plugins, templates } from '../../lib/index'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @invoke npx ts-node ./examples/applications/story-generations.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const styles = ['Adventure', 'Romance', 'Horror', 'Science Fiction', 'Suspense', 'Comedy', 'Inspirational', 'Epic', 'Philosophical', 'Historical', 'Supernatural', 'Crime', 'Family', 'Classic', 'Fairy Tale', 'Animal', 'Science', 'War', 'Fantasy', 'Social', 'Romantic', 'Short Story', 'Novel', 'Narrative Poem', 'Lyric Poem', 'Epic Poem', 'Variations', 'Memoir', 'Autobiography', 'Fantasy Fiction', 'Political', 'Romantic Comedy', 'Science Fiction Adventure', 'Crime Thriller', 'Pure Love', 'Mythology', 'Supernatural Fiction', 'Horror Comedy', 'Epic Fantasy', 'Surrealism', 'Satire', 'Dystopian Fiction', 'Humorous Poetry', 'Philosophical Fiction', 'Suspense Thriller', 'Historical Epic', 'Romantic Suspense', 'Humor', 'Science Fiction Romance', 'Historical Romance']
|
|
11
|
+
const ends = ['Happy ending', 'Tragic ending', 'Open ending', 'Bittersweet ending', 'Ambiguous ending', 'Surprise ending', 'Cathartic ending', 'Redemptive ending', 'Moral ending', 'Ironic ending', 'Deus ex machina', 'Twist ending', 'Epiphany ending', 'Mystery ending', 'Hopeful ending', 'Pessimistic ending', 'Revenge ending', 'Enigmatic ending', 'Metaphorical ending', 'Reflective ending', 'Satisfying ending', 'Unresolved ending', 'Transformation ending', 'Resolution ending', 'Sacrificial ending', 'Indeterminate ending', 'Existential ending', 'Nihilistic ending', 'Tragicomedy ending', 'Inconclusive ending', 'Climactic ending', 'Peripeteia ending', 'Prophetic ending', 'Heartwarming ending', 'Disillusioned ending', 'Sardonic ending', 'Revelatory ending', 'Comedic ending', 'Dramatic ending', 'Fateful ending', 'Introspective ending', 'Reconciling ending', 'Uplifting ending', 'Chaotic ending', 'Fatalistic ending', 'Epilogue ending', 'Foreboding ending', 'Satirical ending', 'Surreal ending']
|
|
12
|
+
|
|
13
|
+
const genImage = async (params: {
|
|
14
|
+
style: string
|
|
15
|
+
title: string
|
|
16
|
+
apiKey: string
|
|
17
|
+
outline: string
|
|
18
|
+
}) => {
|
|
19
|
+
const bot = new ImagesGenerations()
|
|
20
|
+
bot.setConfiguration(params.apiKey)
|
|
21
|
+
bot.setConfig({
|
|
22
|
+
n: 1,
|
|
23
|
+
size: '512x512'
|
|
24
|
+
})
|
|
25
|
+
const result = await bot.create(`is a ${params.style} style story, subject is ${params.title}, ${params.outline}`)
|
|
26
|
+
return result.data.map(e => e.b64_json)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const genStory = async (params: {
|
|
30
|
+
apiKey: string
|
|
31
|
+
style: string
|
|
32
|
+
ending: string
|
|
33
|
+
}) => {
|
|
34
|
+
const broker = new ChatGPT35Broker({
|
|
35
|
+
input: yup => {
|
|
36
|
+
return {
|
|
37
|
+
ending: yup.string().required(),
|
|
38
|
+
style: yup.string().required()
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
output: yup => {
|
|
42
|
+
return {
|
|
43
|
+
enUsOutline: yup.string().required(),
|
|
44
|
+
zhTwOutline: yup.string().required(),
|
|
45
|
+
enUsTitle: yup.string().required(),
|
|
46
|
+
zhTwTitle: yup.string().required(),
|
|
47
|
+
enUsContent: yup.array(yup.string()).required(),
|
|
48
|
+
zhTwContent: yup.array(yup.string()).required()
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
plugins: [
|
|
52
|
+
plugins.PrintLogPlugin.ver35.use({})
|
|
53
|
+
],
|
|
54
|
+
install: ({ bot, attach }) => {
|
|
55
|
+
bot.setConfiguration(params.apiKey)
|
|
56
|
+
attach('parseFailed', async({ count, retry, response, changeMessages }) => {
|
|
57
|
+
if (count <= 5) {
|
|
58
|
+
console.log(`回傳錯誤,正在重試: ${count} 次`)
|
|
59
|
+
changeMessages([response.newMessages[0]])
|
|
60
|
+
retry()
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
},
|
|
64
|
+
assembly: async ({ style, ending }) => {
|
|
65
|
+
return templates.requireJsonResponse([
|
|
66
|
+
`生成一個 ${style} 風格的故事,必須是 ${ending} 結局`,
|
|
67
|
+
'內容請豐富精彩有深度,而且有起承轉合,符合電影的三段結構,必須1000字以上',
|
|
68
|
+
'有中英兩種版本,中文是繁體中文'
|
|
69
|
+
], {
|
|
70
|
+
enUsOutline: {
|
|
71
|
+
desc: '故事簡述,請用英文呈現',
|
|
72
|
+
example: 'string'
|
|
73
|
+
},
|
|
74
|
+
zhTwOutline: {
|
|
75
|
+
desc: '故事簡述,請用中文呈現',
|
|
76
|
+
example: 'string'
|
|
77
|
+
},
|
|
78
|
+
enUsTitle: {
|
|
79
|
+
desc: '英文標題',
|
|
80
|
+
example: 'string'
|
|
81
|
+
},
|
|
82
|
+
zhTwTitle: {
|
|
83
|
+
desc: '中文標題',
|
|
84
|
+
example: 'string'
|
|
85
|
+
},
|
|
86
|
+
enUsContent: {
|
|
87
|
+
desc: '英文內容,每一段為一個元素',
|
|
88
|
+
example: 'string[]'
|
|
89
|
+
},
|
|
90
|
+
zhTwContent: {
|
|
91
|
+
desc: '中文內容,每一段為一個元素',
|
|
92
|
+
example: 'string[]'
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
const result = await broker.request(params)
|
|
98
|
+
return result
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
flow.run(async () => {
|
|
102
|
+
const apiKey = await getKey()
|
|
103
|
+
const style = array.randomPick(styles)
|
|
104
|
+
const ending = array.randomPick(ends)
|
|
105
|
+
try {
|
|
106
|
+
const result = await genStory({
|
|
107
|
+
style,
|
|
108
|
+
ending,
|
|
109
|
+
apiKey
|
|
110
|
+
})
|
|
111
|
+
const dir = definedOutputDir(`.output/stores/${result.zhTwTitle}`)
|
|
112
|
+
dir.write('story.json', result)
|
|
113
|
+
dir.write('story-config.json', {
|
|
114
|
+
style,
|
|
115
|
+
ending
|
|
116
|
+
})
|
|
117
|
+
for (let i = 0; i < 2; i++) {
|
|
118
|
+
const images = await genImage({
|
|
119
|
+
style,
|
|
120
|
+
apiKey,
|
|
121
|
+
title: result.enUsTitle,
|
|
122
|
+
outline: result.enUsOutline
|
|
123
|
+
})
|
|
124
|
+
dir.write(`cover-${i}.png`, images[0])
|
|
125
|
+
}
|
|
126
|
+
} catch (error: any) {
|
|
127
|
+
console.error('Error:', error?.response?.data?.error?.message ?? error)
|
|
128
|
+
}
|
|
129
|
+
})
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { flow, array } from 'power-helper'
|
|
2
|
+
import { ImagesGenerations } from '../../lib/service/images-generations'
|
|
3
|
+
import { definedOutputDir, getKey } from '../utils'
|
|
4
|
+
import { ChatGPT35Broker, plugins, templates } from '../../lib/index'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @invoke npx ts-node ./examples/applications/talk-generations.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const situations = [
|
|
11
|
+
{
|
|
12
|
+
'en-US': 'Brainstorming session between marketing team',
|
|
13
|
+
'zh-TW': '行銷團隊頭腦風暴會議'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
'en-US': 'Customer service representative handling a complaint',
|
|
17
|
+
'zh-TW': '客服代表處理客訴'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
'en-US': 'Job interview for a software engineer position',
|
|
21
|
+
'zh-TW': '軟體工程師職位面試'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
'en-US': 'Negotiation between a vendor and a client',
|
|
25
|
+
'zh-TW': '供應商與客戶的談判'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
'en-US': 'Meeting between a designer and a developer',
|
|
29
|
+
'zh-TW': '設計師與開發人員的會議'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
'en-US': 'Team huddle before a sports game',
|
|
33
|
+
'zh-TW': '比賽前的團隊集合'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
'en-US': 'Consultation with a financial advisor',
|
|
37
|
+
'zh-TW': '財務顧問諮詢'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
'en-US': 'Parent-teacher conference',
|
|
41
|
+
'zh-TW': '家長教師會議'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
'en-US': 'Discussion between a doctor and a patient',
|
|
45
|
+
'zh-TW': '醫生與病人的討論'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
'en-US': 'Debate between political candidates',
|
|
49
|
+
'zh-TW': '政治候選人辯論'
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
const tones = [
|
|
54
|
+
{
|
|
55
|
+
'en-US': 'Angry',
|
|
56
|
+
'zh-TW': '憤怒'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
'en-US': 'Excited',
|
|
60
|
+
'zh-TW': '興奮'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
'en-US': 'Bored',
|
|
64
|
+
'zh-TW': '無聊'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
'en-US': 'Sad',
|
|
68
|
+
'zh-TW': '悲傷'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
'en-US': 'Happy',
|
|
72
|
+
'zh-TW': '快樂'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
'en-US': 'Confused',
|
|
76
|
+
'zh-TW': '困惑'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
'en-US': 'Frustrated',
|
|
80
|
+
'zh-TW': '挫敗'
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
'en-US': 'Curious',
|
|
84
|
+
'zh-TW': '好奇'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
'en-US': 'Nervous',
|
|
88
|
+
'zh-TW': '緊張'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
'en-US': 'Relaxed',
|
|
92
|
+
'zh-TW': '輕鬆'
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
const styles = [
|
|
97
|
+
{
|
|
98
|
+
'en-US': 'Humorous',
|
|
99
|
+
'zh-TW': '幽默'
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
'en-US': 'Formal',
|
|
103
|
+
'zh-TW': '正式'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
'en-US': 'Casual',
|
|
107
|
+
'zh-TW': '隨意'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
'en-US': 'Professional',
|
|
111
|
+
'zh-TW': '專業'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
'en-US': 'Friendly',
|
|
115
|
+
'zh-TW': '友善'
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
'en-US': 'Serious',
|
|
119
|
+
'zh-TW': '嚴肅'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
'en-US': 'Sarcastic',
|
|
123
|
+
'zh-TW': '諷刺'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
'en-US': 'Inquisitive',
|
|
127
|
+
'zh-TW': '探究'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
'en-US': 'Persuasive',
|
|
131
|
+
'zh-TW': '說服'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
'en-US': 'Encouraging',
|
|
135
|
+
'zh-TW': '鼓勵'
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
const genImage = async (params: {
|
|
140
|
+
tone: string
|
|
141
|
+
apiKey: string,
|
|
142
|
+
style: string
|
|
143
|
+
situation: string
|
|
144
|
+
}) => {
|
|
145
|
+
const bot = new ImagesGenerations()
|
|
146
|
+
bot.setConfiguration(params.apiKey)
|
|
147
|
+
bot.setConfig({
|
|
148
|
+
n: 1,
|
|
149
|
+
size: '512x512'
|
|
150
|
+
})
|
|
151
|
+
const result = await bot.create(`two people ${params.tone} ${params.situation}, ${params.style}`)
|
|
152
|
+
return result.data.map(e => e.b64_json)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const genTalk = async (params: {
|
|
156
|
+
apiKey: string
|
|
157
|
+
tone: string
|
|
158
|
+
style: string
|
|
159
|
+
situation: string
|
|
160
|
+
}) => {
|
|
161
|
+
const broker = new ChatGPT35Broker({
|
|
162
|
+
input: yup => {
|
|
163
|
+
return {
|
|
164
|
+
tone: yup.string().required(),
|
|
165
|
+
style: yup.string().required(),
|
|
166
|
+
situation: yup.string().required()
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
output: yup => {
|
|
170
|
+
return {
|
|
171
|
+
enUsOutline: yup.string().required(),
|
|
172
|
+
zhTwOutline: yup.string().required(),
|
|
173
|
+
enUsTitle: yup.string().required(),
|
|
174
|
+
zhTwTitle: yup.string().required(),
|
|
175
|
+
enUsContent: yup.array(yup.string()).required(),
|
|
176
|
+
zhTwContent: yup.array(yup.string()).required()
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
plugins: [
|
|
180
|
+
plugins.PrintLogPlugin.ver35.use({})
|
|
181
|
+
],
|
|
182
|
+
install: ({ bot, attach }) => {
|
|
183
|
+
bot.setConfiguration(params.apiKey)
|
|
184
|
+
attach('parseFailed', async ({ count, retry, response, changeMessages }) => {
|
|
185
|
+
if (count <= 5) {
|
|
186
|
+
console.log(`回傳錯誤,正在重試: ${count} 次`)
|
|
187
|
+
changeMessages([response.newMessages[0]])
|
|
188
|
+
retry()
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
},
|
|
192
|
+
assembly: async ({ situation, style, tone }) => {
|
|
193
|
+
return templates.requireJsonResponse([
|
|
194
|
+
`幫我生成一組以${style}為出發點的對話`,
|
|
195
|
+
`是兩個 ${tone} 的人進行,${situation}`,
|
|
196
|
+
'有中英兩種版本,中文是繁體中文'
|
|
197
|
+
], {
|
|
198
|
+
enUsOutline: {
|
|
199
|
+
desc: '故事簡述,請用英文呈現',
|
|
200
|
+
example: 'string'
|
|
201
|
+
},
|
|
202
|
+
zhTwOutline: {
|
|
203
|
+
desc: '故事簡述,請用中文呈現',
|
|
204
|
+
example: 'string'
|
|
205
|
+
},
|
|
206
|
+
enUsTitle: {
|
|
207
|
+
desc: '英文標題',
|
|
208
|
+
example: 'string'
|
|
209
|
+
},
|
|
210
|
+
zhTwTitle: {
|
|
211
|
+
desc: '中文標題',
|
|
212
|
+
example: 'string'
|
|
213
|
+
},
|
|
214
|
+
enUsContent: {
|
|
215
|
+
desc: '英文內容,每一段為一個元素',
|
|
216
|
+
example: 'string[]'
|
|
217
|
+
},
|
|
218
|
+
zhTwContent: {
|
|
219
|
+
desc: '中文內容,每一段為一個元素',
|
|
220
|
+
example: 'string[]'
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
const result = await broker.request(params)
|
|
226
|
+
return result
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
flow.run(async () => {
|
|
230
|
+
const apiKey = await getKey()
|
|
231
|
+
const tone = array.randomPick(tones)
|
|
232
|
+
const style = array.randomPick(styles)
|
|
233
|
+
const situation = array.randomPick(situations)
|
|
234
|
+
try {
|
|
235
|
+
const result = await genTalk({
|
|
236
|
+
tone: tone['en-US'],
|
|
237
|
+
situation: situation['en-US'],
|
|
238
|
+
style: style['en-US'],
|
|
239
|
+
apiKey
|
|
240
|
+
})
|
|
241
|
+
const images = await genImage({
|
|
242
|
+
tone: tone['en-US'],
|
|
243
|
+
situation: situation['en-US'],
|
|
244
|
+
style: style['en-US'],
|
|
245
|
+
apiKey
|
|
246
|
+
})
|
|
247
|
+
const dir = definedOutputDir(`.output/talks/${result.zhTwTitle}`)
|
|
248
|
+
dir.write('content.json', result)
|
|
249
|
+
for (let image of images) {
|
|
250
|
+
dir.write(`cover-${Date.now()}.png`, image, 'base64')
|
|
251
|
+
}
|
|
252
|
+
} catch (error: any) {
|
|
253
|
+
console.error('Error:', error?.response?.data?.error?.message ?? error)
|
|
254
|
+
}
|
|
255
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { Buffer } from 'buffer'
|
|
3
|
+
import { prompt } from 'inquirer'
|
|
4
|
+
|
|
5
|
+
type BufferEncoding = 'ascii' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'latin1' | 'binary' | 'hex'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @zh 你可以透過在根目錄中加入 .key 檔案,來自動讀取 API key
|
|
9
|
+
* @en You can automatically read the API key by adding the .key file in the root directory.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const getKey = async() => {
|
|
13
|
+
let apiKey = ''
|
|
14
|
+
let keyFile = './.key'
|
|
15
|
+
if (fs.existsSync(keyFile)) {
|
|
16
|
+
apiKey = fs.readFileSync('./.key').toString()
|
|
17
|
+
}
|
|
18
|
+
if (!apiKey) {
|
|
19
|
+
const { inputApiKey } = await prompt([
|
|
20
|
+
{
|
|
21
|
+
type: 'input',
|
|
22
|
+
name: 'inputApiKey',
|
|
23
|
+
message: 'Please enter API key.',
|
|
24
|
+
default: ''
|
|
25
|
+
}
|
|
26
|
+
])
|
|
27
|
+
apiKey = inputApiKey
|
|
28
|
+
}
|
|
29
|
+
if (!apiKey) {
|
|
30
|
+
throw new Error('Unable to find API key.')
|
|
31
|
+
}
|
|
32
|
+
return apiKey
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @zh 定義輸出資料夾位置
|
|
37
|
+
* @en Define the output folder location
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
export const definedOutputDir = (dirName: string) => {
|
|
41
|
+
let dir = `.output/${dirName}`
|
|
42
|
+
if (fs.existsSync(dir) === false) {
|
|
43
|
+
fs.mkdirSync(dir, {
|
|
44
|
+
recursive: true
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
write(fileName: string, content: Buffer | string | Record<any, any>, encode: BufferEncoding = 'utf-8') {
|
|
49
|
+
let data = content
|
|
50
|
+
if (Buffer.isBuffer(content) === false && typeof content !== 'string') {
|
|
51
|
+
data = JSON.stringify(content, null, 4)
|
|
52
|
+
}
|
|
53
|
+
fs.writeFileSync(`${dir}/${fileName}`, data, encode)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
package/lib/broker/3.ts
CHANGED
|
@@ -9,21 +9,49 @@ export class ChatGPT3Broker<
|
|
|
9
9
|
S extends ValidateCallback<any>,
|
|
10
10
|
O extends ValidateCallback<any>,
|
|
11
11
|
> extends BaseBroker<S, O, Broker3Plugin<any>, {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @zh 發送聊天訊息給機器人前觸發
|
|
15
|
+
* @en Triggered before sending chat message to bot
|
|
16
|
+
*/
|
|
17
|
+
|
|
12
18
|
talkBefore: {
|
|
19
|
+
id: string
|
|
13
20
|
data: ValidateCallbackOutputs<S>
|
|
14
21
|
prompt: string
|
|
15
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @zh 當聊天機器人回傳資料的時候觸發
|
|
26
|
+
* @en Triggered when the chatbot returns data
|
|
27
|
+
*/
|
|
28
|
+
|
|
16
29
|
talkAfter: {
|
|
30
|
+
id: string
|
|
17
31
|
data: ValidateCallbackOutputs<S>
|
|
18
32
|
prompt: string
|
|
19
33
|
response: ChatGPT3TalkResponse
|
|
20
34
|
parseText: string
|
|
21
35
|
changeParseText: (text: string) => void
|
|
22
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @zh 當回傳資料符合規格時觸發
|
|
40
|
+
* @en Triggered when the returned data meets the specifications
|
|
41
|
+
*/
|
|
42
|
+
|
|
23
43
|
succeeded: {
|
|
44
|
+
id: string
|
|
24
45
|
output: ValidateCallbackOutputs<O>
|
|
25
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @zh 當回傳資料不符合規格,或是解析錯誤時觸發
|
|
50
|
+
* @en Triggered when the returned data does not meet the specifications or parsing errors
|
|
51
|
+
*/
|
|
52
|
+
|
|
26
53
|
parseFailed: {
|
|
54
|
+
id: string
|
|
27
55
|
error: any
|
|
28
56
|
count: number
|
|
29
57
|
retry: () => void
|
|
@@ -31,12 +59,27 @@ export class ChatGPT3Broker<
|
|
|
31
59
|
parserFails: { name: string, error: any }[]
|
|
32
60
|
changePrompt: (text: string) => void
|
|
33
61
|
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @zh 不論成功失敗,執行結束的時候會執行。
|
|
65
|
+
* @en It will be executed when the execution is completed, regardless of success or failure.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
done: {
|
|
69
|
+
id: string
|
|
70
|
+
}
|
|
34
71
|
}> {
|
|
35
72
|
|
|
36
73
|
bot: ChatGPT3 = new ChatGPT3()
|
|
37
74
|
|
|
75
|
+
/**
|
|
76
|
+
* @zh 將請求發出至聊天機器人。
|
|
77
|
+
* @en Send request to chatbot.
|
|
78
|
+
*/
|
|
79
|
+
|
|
38
80
|
async request<T extends Translator<S, O>>(data: T['__schemeType']): Promise<T['__outputType']> {
|
|
39
81
|
this._install()
|
|
82
|
+
let id = flow.createUuid()
|
|
40
83
|
let output: any = null
|
|
41
84
|
let question = await this.translator.compile(data)
|
|
42
85
|
await flow.asyncWhile(async ({ count, doBreak }) => {
|
|
@@ -48,12 +91,14 @@ export class ChatGPT3Broker<
|
|
|
48
91
|
let retryFlag = false
|
|
49
92
|
try {
|
|
50
93
|
await this.hook.notify('talkBefore', {
|
|
94
|
+
id,
|
|
51
95
|
data,
|
|
52
96
|
prompt: question.prompt
|
|
53
97
|
})
|
|
54
98
|
response = await this.bot.talk(question.prompt)
|
|
55
99
|
parseText = response.text
|
|
56
100
|
await this.hook.notify('talkAfter', {
|
|
101
|
+
id,
|
|
57
102
|
data,
|
|
58
103
|
prompt: question.prompt,
|
|
59
104
|
response,
|
|
@@ -64,13 +109,16 @@ export class ChatGPT3Broker<
|
|
|
64
109
|
})
|
|
65
110
|
output = (await this.translator.parse(parseText)).output
|
|
66
111
|
await this.hook.notify('succeeded', {
|
|
112
|
+
id,
|
|
67
113
|
output
|
|
68
114
|
})
|
|
115
|
+
await this.hook.notify('done', { id })
|
|
69
116
|
doBreak()
|
|
70
117
|
} catch (error: any) {
|
|
71
118
|
// 如果解析錯誤,可以選擇是否重新解讀
|
|
72
119
|
if (error.isParserError) {
|
|
73
120
|
await this.hook.notify('parseFailed', {
|
|
121
|
+
id,
|
|
74
122
|
error: error.error,
|
|
75
123
|
count,
|
|
76
124
|
response,
|
|
@@ -86,6 +134,7 @@ export class ChatGPT3Broker<
|
|
|
86
134
|
return doBreak()
|
|
87
135
|
}
|
|
88
136
|
}
|
|
137
|
+
await this.hook.notify('done', { id })
|
|
89
138
|
throw error
|
|
90
139
|
}
|
|
91
140
|
})
|