doomiaichat 4.9.0 → 5.1.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/dist/azureai.d.ts +1 -21
- package/dist/azureai.js +0 -95
- package/dist/declare.d.ts +3 -64
- package/dist/gptbase.d.ts +0 -47
- package/dist/gptbase.js +0 -47
- package/dist/gptprovider.js +3 -3
- package/dist/openai.d.ts +4 -75
- package/dist/openai.js +24 -588
- package/package.json +1 -1
- package/src/azureai.ts +1 -95
- package/src/declare.ts +3 -69
- package/src/gptbase.ts +1 -48
- package/src/gptprovider.ts +3 -3
- package/src/openai.ts +545 -561
package/src/openai.ts
CHANGED
|
@@ -1,81 +1,17 @@
|
|
|
1
1
|
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "azure-openai"
|
|
2
|
-
// import { EventEmitter } from "events";
|
|
3
2
|
import GptBase from "./gptbase"
|
|
4
|
-
import { OpenAIApiParameters, ChatReponse,
|
|
5
|
-
const SECTION_LENGTH = 1024; ///每2400个字符分成一组
|
|
6
|
-
const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
|
|
7
|
-
//请将答案放在最后,标记为答案:()
|
|
8
|
-
// const QUESTION_TEXT_MAPPING: any = {
|
|
9
|
-
// singlechoice: '你是一名专业的出题老师,根据以下内容,生成@ITEMCOUNT@道单选题,每道题目4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题一个正确答案,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出',
|
|
10
|
-
// multiplechoice: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道多选题,提供4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题的答案至少有两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出', //请将答案放在最后,标记为答案:()
|
|
11
|
-
// trueorfalse: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道判断题,每道题正确和错误两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":["A.正确","B.错误"],"answer":[]}]的结构输出', //标记为答案:(正确或错误)
|
|
12
|
-
// completion: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道填空题和对应答案,输出结果必须是JSON数组并按照[{"question":"","answer":["填空答案1","填空答案2"]}]的结构输出' //请将答案放在最后,标记为答案:()
|
|
13
|
-
// }
|
|
14
|
-
const FAQ_ROLE_DEFINE = `
|
|
15
|
-
角色扮演:你是一位精通各行业的培训专家,你擅长从资料里提取重点要点,并形成用于培训员工的问题及对应的答案和答案的关键词。请记住:
|
|
16
|
-
1、问题需要偏口语化,问题需要与所给的资料相关,绝不能问超出所给资料的范围;每个问题需要有主语,所提问题需要准确、完整、清晰,绝不能有歧义;意思相近的问题不要重复给出;
|
|
17
|
-
2、对应的答案必须要在资料中能找到,绝对不能给出在资料里没有的答案,答案的关键词必须完整在所给的答案中出现,绝不能给出不在答案里的关键词;
|
|
18
|
-
3、生成问题的时候,请出具有代表性的问题,对于一些无关紧要的问题可以忽略。特别注意资料中关于数字、参数、特点等关键信息的提取,在给出的问题中尽可能覆盖;
|
|
19
|
-
4、生成的结果严格按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的标准JSON数组结构输出。
|
|
20
|
-
`
|
|
21
|
-
|
|
22
|
-
const QUESTION_ROLE_DEFINE: any = {
|
|
23
|
-
singlechoice: `
|
|
24
|
-
角色扮演:你是一位精通各行业的培训专家,你擅长从资料里提取重点要点,并形成用于培训员工的单选题,每道题包括一个问题和四个选项,其中只有一个选项是正确的。请记住:
|
|
25
|
-
1、问题需要与所给的资料相关,绝不能问超出所给资料的范围;每个问题需要有主语,所提问题需要准确、完整、清晰,绝不能有歧义;意思相近的问题不要重复给出;
|
|
26
|
-
2、四个选项用大写字母ABCD开头,其中只有一个是正确的选项,而且这个正确的选项必须要在资料中能找到,绝对不能给出在资料里没有的正确选项;
|
|
27
|
-
3、生成问题的时候,请出具有代表性的问题,对于一些无关紧要的问题可以忽略。特别注意资料中关于数字、参数、特点等关键信息的提取,在给出的问题中尽可能覆盖;
|
|
28
|
-
4、生成的结果严格按照标准JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出`,
|
|
29
|
-
multiplechoice: `
|
|
30
|
-
角色扮演:你是一位精通各行业的培训专家,你擅长从资料里提取重点要点,并形成用于培训员工的多选题,每道题包括一个问题和四个选项,其中至少有两个选项是正确的。请记住:
|
|
31
|
-
1、问题需要与所给的资料相关,绝不能问超出所给资料的范围;每个问题需要有主语,所提问题需要准确、完整、清晰,绝不能有歧义;意思相近的问题不要重复给出;
|
|
32
|
-
2、四个选项用大写字母ABCD开头,其中至少有两个是正确的选项,而且正确的选项必须要在资料中能找到,绝对不能给出在资料里没有的正确选项;
|
|
33
|
-
3、生成问题的时候,请出具有代表性的问题,对于一些无关紧要的问题可以忽略。特别注意资料中关于数字、参数、特点等关键信息的提取,在给出的问题中尽可能覆盖;
|
|
34
|
-
4、生成的结果严格按照标准JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出
|
|
35
|
-
`,
|
|
36
|
-
trueorfalse: `
|
|
37
|
-
角色扮演:你是一位精通各行业的培训专家,你擅长从资料里提取重点要点,并形成用于培训员工的判断题,每道题包括一个问题和一个正确和一个错误的两个选项。请记住:
|
|
38
|
-
1、问题需要与所给的资料相关,绝不能问超出所给资料的范围;每个问题需要有主语,所提问题需要准确、完整、清晰,绝不能有歧义;意思相近的问题不要重复给出;
|
|
39
|
-
2、两个选项必须为“正确”和“错误”这两个,正确答案必须是其中一个;
|
|
40
|
-
3、生成问题的时候,请出具有代表性的问题,对于一些无关紧要的问题可以忽略。特别注意资料中关于数字、参数、特点等关键信息的提取,在给出的问题中尽可能覆盖;
|
|
41
|
-
5、生成的结果严格按照标准JSON数组并按照[{"question":"","choice":["A.正确","B.错误"],"answer":[]}]的结构输出'
|
|
42
|
-
`,
|
|
43
|
-
completion: `
|
|
44
|
-
角色扮演:你是一位精通各行业的培训专家,你擅长从资料里提取重点要点,并形成用于培训员工的填空题及对应的答案。请记住:
|
|
45
|
-
1、问题需要与所给的资料相关,绝不能问超出所给资料的范围;每个问题需要有主语,所提问题需要准确、完整、清晰,绝不能有歧义;意思相近的问题不要重复给出;
|
|
46
|
-
2、对应的答案必须要在资料中能找到,绝对不能给出在资料里没有的答案,答案尽量选择数字、词组等,字数不超过10个字,避免出现过长的答案;
|
|
47
|
-
3、生成问题的时候,请出具有代表性的问题,对于一些无关紧要的问题可以忽略。特别注意资料中关于数字、参数、特点等关键信息的提取,在给出的问题中尽可能覆盖;
|
|
48
|
-
4、生成的结果严格按照标准JSON数组并按照[{"question":"","answer":["填空答案1","填空答案2"]}]的结构输出'
|
|
49
|
-
`
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* 问题生成的Prompt
|
|
53
|
-
*/
|
|
54
|
-
const QUESTION_PROMPT: any ={
|
|
55
|
-
singlechoice:'根据以下内容,生成@ITEMCOUNT@道单选题,每道题目4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题一个正确答案,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组。',
|
|
56
|
-
multiplechoice: '根据以下内容,请生成@ITEMCOUNT@道多选题,提供4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题的答案至少有两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组。',
|
|
57
|
-
trueorfalse: '根据以下内容,请生成@ITEMCOUNT@道判断题,每道题正确和错误两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":["A.正确","B.错误"],"answer":[]}]的结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组。',
|
|
58
|
-
completion: '根据以下内容,请生成@ITEMCOUNT@道填空题和对应答案,输出结果必须是JSON数组并按照[{"question":"","answer":["填空答案1","填空答案2"]}]的结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组。'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 问题生成的Prompt
|
|
63
|
-
*/
|
|
64
|
-
const QUESTION_PROMPT_FIXED: any = {
|
|
65
|
-
singlechoice: '[{"question":"","choice":[],"answer":[]}]',
|
|
66
|
-
multiplechoice: '[{"question":"","choice":[],"answer":[]}]',
|
|
67
|
-
trueorfalse: '[{"question":"","choice":["A.正确","B.错误"],"answer":[]}]',
|
|
68
|
-
completion: '[{"question":"","answer":["填空答案1","填空答案2"]}]'
|
|
69
|
-
}
|
|
70
|
-
const QUESTION_TYPE: string[] = ['singlechoice', 'multiplechoice', 'trueorfalse', 'completion']
|
|
3
|
+
import { OpenAIApiParameters, ChatReponse, EmbeddingResult } from './declare'
|
|
71
4
|
|
|
72
5
|
export default class OpenAIGpt extends GptBase {
|
|
73
6
|
protected readonly apiKey: string;
|
|
74
7
|
protected aiApi: OpenAIApi | undefined;
|
|
75
8
|
protected readonly chatModel: string;
|
|
76
9
|
protected readonly maxtoken: number;
|
|
10
|
+
protected readonly top_p: number;
|
|
11
|
+
protected readonly presence_penalty:number;
|
|
12
|
+
protected readonly frequency_penalty: number;
|
|
77
13
|
protected readonly temperature: number;
|
|
78
|
-
protected readonly embeddingmodel:string;
|
|
14
|
+
protected readonly embeddingmodel: string;
|
|
79
15
|
/**
|
|
80
16
|
*
|
|
81
17
|
* @param apiKey 调用OpenAI 的key
|
|
@@ -87,7 +23,10 @@ export default class OpenAIGpt extends GptBase {
|
|
|
87
23
|
this.apiKey = apiKey;
|
|
88
24
|
this.chatModel = apiOption.model || 'gpt-3.5-turbo';
|
|
89
25
|
this.maxtoken = apiOption.maxtoken || 2048;
|
|
26
|
+
this.top_p = apiOption.top_p || 0.95;
|
|
90
27
|
this.temperature = apiOption.temperature || 0.9;
|
|
28
|
+
this.presence_penalty = apiOption.presence_penalty || 0;
|
|
29
|
+
this.frequency_penalty = apiOption.frequency_penalty || 0;
|
|
91
30
|
this.embeddingmodel = apiOption.embedding || 'text-embedding-ada-002';
|
|
92
31
|
}
|
|
93
32
|
/**
|
|
@@ -101,13 +40,13 @@ export default class OpenAIGpt extends GptBase {
|
|
|
101
40
|
* 获得文字的向量
|
|
102
41
|
* @param text
|
|
103
42
|
*/
|
|
104
|
-
override async getTextEmbedding(text: string, axiosOption: any): Promise<EmbeddingResult>{
|
|
43
|
+
override async getTextEmbedding(text: string, axiosOption: any): Promise<EmbeddingResult> {
|
|
105
44
|
if (!text) return { successed: false, error: { errcode: 2, errmsg: 'content required' } };
|
|
106
45
|
if (!this.aiApi) {
|
|
107
46
|
this.aiApi = this.createOpenAI(this.apiKey);
|
|
108
47
|
}
|
|
109
48
|
try {
|
|
110
|
-
const response:any = await this.aiApi.createEmbedding({
|
|
49
|
+
const response: any = await this.aiApi.createEmbedding({
|
|
111
50
|
model: this.embeddingmodel,
|
|
112
51
|
input: text,
|
|
113
52
|
}, axiosOption);
|
|
@@ -132,18 +71,21 @@ export default class OpenAIGpt extends GptBase {
|
|
|
132
71
|
[{ role: 'user', content: chatText }] : chatText;
|
|
133
72
|
// console.log('message', message)
|
|
134
73
|
try {
|
|
135
|
-
const response:any = await this.aiApi.createChatCompletion({
|
|
74
|
+
const response: any = await this.aiApi.createChatCompletion({
|
|
136
75
|
model: callChatOption?.model || this.chatModel,
|
|
137
76
|
messages: message,
|
|
138
77
|
temperature: Number(callChatOption?.temperature || this.temperature),
|
|
139
78
|
max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
|
|
79
|
+
top_p: Number(callChatOption?.top_p || this.top_p),
|
|
80
|
+
presence_penalty: Number(callChatOption?.presence_penalty || this.presence_penalty),
|
|
81
|
+
frequency_penalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty),
|
|
140
82
|
n: Number(callChatOption?.replyCounts || 1) || 1
|
|
141
83
|
}, axiosOption);
|
|
142
84
|
// console.log('finish_reason==>', response.data.choices)
|
|
143
85
|
////输出的内容不合规
|
|
144
|
-
if (response.data.choices[0].finish_reason ==='content_filter') {
|
|
86
|
+
if (response.data.choices[0].finish_reason === 'content_filter') {
|
|
145
87
|
console.log('content_filter')
|
|
146
|
-
return { successed: false, error:'content_filter'}
|
|
88
|
+
return { successed: false, error: 'content_filter' }
|
|
147
89
|
}
|
|
148
90
|
return { successed: true, message: response.data.choices, usage: response.data.usage };
|
|
149
91
|
} catch (error) {
|
|
@@ -158,55 +100,65 @@ export default class OpenAIGpt extends GptBase {
|
|
|
158
100
|
* @param _paramOption
|
|
159
101
|
* @param axiosOption
|
|
160
102
|
*/
|
|
161
|
-
override async chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, attach?: any, axiosOption?: any):Promise<any>{
|
|
162
|
-
if (!chatText) this.emit('chaterror', { successed: false, error:'no text in chat'});
|
|
103
|
+
override async chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, attach?: any, axiosOption?: any): Promise<any> {
|
|
104
|
+
if (!chatText) this.emit('chaterror', { successed: false, error: 'no text in chat' });
|
|
163
105
|
if (!this.aiApi) {
|
|
164
106
|
this.aiApi = this.createOpenAI(this.apiKey);
|
|
165
107
|
}
|
|
108
|
+
// const DATA_END_TAG = `"usage":null}`
|
|
166
109
|
let message: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
|
|
167
110
|
[{ role: 'user', content: chatText }] : chatText;
|
|
168
111
|
axiosOption = Object.assign({}, axiosOption || { timeout: 60000 }, { responseType: 'stream' })
|
|
169
112
|
let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000);
|
|
170
113
|
try {
|
|
171
|
-
let finishreason:any = null,usage:any = null;
|
|
114
|
+
let finishreason: any = null, usage: any = null,errtxt = '';
|
|
172
115
|
///便于知道返回的requestid
|
|
173
116
|
// console.log('model', callChatOption?.model || this.chatModel,)
|
|
174
117
|
const response: any = await this.aiApi.createChatCompletion({
|
|
175
118
|
model: callChatOption?.model || this.chatModel,
|
|
176
119
|
messages: message,
|
|
177
|
-
stream:true,
|
|
120
|
+
stream: true,
|
|
121
|
+
top_p: Number(callChatOption?.top_p || this.top_p),
|
|
122
|
+
presence_penalty: Number(callChatOption?.presence_penalty || this.presence_penalty),
|
|
123
|
+
frequency_penalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty),
|
|
178
124
|
temperature: Number(callChatOption?.temperature || this.temperature),
|
|
179
125
|
max_tokens: Number(callChatOption?.maxtoken || this.maxtoken)
|
|
180
126
|
}, axiosOption);
|
|
181
|
-
let replytext:string[] = [];
|
|
182
|
-
|
|
183
|
-
response.data.on('data', (data:any) => {
|
|
184
|
-
const lines = data.toString().split('\n').filter((line:string) => line.trim() !== '');
|
|
127
|
+
let replytext: string[] = [];
|
|
128
|
+
|
|
129
|
+
response.data.on('data', (data: any) => {
|
|
130
|
+
const lines = data.toString().split('\n').filter((line: string) => line.trim() !== '');
|
|
185
131
|
///已经返回了结束原因
|
|
186
132
|
if (finishreason) return;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
133
|
+
// console.log('before add', lines.join('').split('data:'));
|
|
134
|
+
let alltext = (errtxt +lines.join('')).split('data:');
|
|
135
|
+
// console.log('alltext',alltext)
|
|
136
|
+
errtxt = '';
|
|
137
|
+
for (const line of alltext) {
|
|
138
|
+
let txt = line.trim();
|
|
139
|
+
if (!txt) continue;
|
|
140
|
+
if (txt === '[DONE]') {
|
|
191
141
|
let output = { successed: true, requestid, text: replytext.join(''), finish_reason: 'stop', usage };
|
|
192
|
-
if (attach) output = Object.assign({},output, attach);
|
|
142
|
+
if (attach) output = Object.assign({}, output, attach);
|
|
193
143
|
this.emit('chatdone', output)
|
|
194
144
|
return; // Stream finished
|
|
195
145
|
}
|
|
196
146
|
try {
|
|
197
147
|
///{ delta: { content: '$\\' }, index: 0, finish_reason: null }
|
|
198
148
|
///发送出去
|
|
199
|
-
const parsed = JSON.parse(
|
|
149
|
+
const parsed = JSON.parse(txt);
|
|
150
|
+
///已经返回一个正确的了,可以重置这个变量了
|
|
200
151
|
finishreason = parsed.choices[0].finish_reason;
|
|
201
152
|
usage = parsed.usage;
|
|
202
153
|
let streamtext = parsed.choices[0].delta.content;
|
|
203
154
|
replytext.push(streamtext);
|
|
204
155
|
let output = { successed: true, requestid, text: replytext.join(''), finish_reason: finishreason, index: parsed.choices[0].index, usage };
|
|
205
|
-
if (attach) output = Object.assign({},output, attach);
|
|
206
|
-
this.emit(finishreason ? 'chatdone':'chattext', output
|
|
156
|
+
if (attach) output = Object.assign({}, output, attach);
|
|
157
|
+
this.emit(finishreason ? 'chatdone' : 'chattext', output)
|
|
207
158
|
if (finishreason) return;
|
|
208
159
|
} catch (error) {
|
|
209
|
-
|
|
160
|
+
errtxt+=txt; ///这一段json没有结束,作为下一次的流过来时使用
|
|
161
|
+
this.emit('chaterror', { successed: false, requestid, error: 'JSON parse stream message', errtxt });
|
|
210
162
|
}
|
|
211
163
|
}
|
|
212
164
|
});
|
|
@@ -217,489 +169,521 @@ export default class OpenAIGpt extends GptBase {
|
|
|
217
169
|
}
|
|
218
170
|
}
|
|
219
171
|
|
|
220
|
-
/**
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
override async commentQuestionAnswer(question: string, answer: string, axiosOption: any = { timeout: 30000 }): Promise<CommentResult>{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
override async getScentenceEmotional(s1: string, axiosOption: any = { timeout: 30000 }): Promise<EmotionResult> {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
172
|
+
// /**
|
|
173
|
+
// * 点评问题回答的评价
|
|
174
|
+
// * @param question
|
|
175
|
+
// * @param answer
|
|
176
|
+
// * @param axiosOption
|
|
177
|
+
// */
|
|
178
|
+
// override async commentQuestionAnswer(question: string, answer: string, axiosOption: any = { timeout: 30000 }): Promise<CommentResult> {
|
|
179
|
+
// if (!question || !answer) return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } }
|
|
180
|
+
// let message = [
|
|
181
|
+
// { role: 'system', content: '你是一名专业的知识点评师。' },
|
|
182
|
+
// { role: 'user', content: `问题题干:“${question}”` },
|
|
183
|
+
// { role: 'user', content: `回答内容:“${answer}”` },
|
|
184
|
+
// { role: 'user', content: `请根据以上的回答内容进行点评,给出一段不超过200字的评语,并给出0-100的评分。` },
|
|
185
|
+
// { role: 'user', content: `结果完整按照{"comment":"点评内容","score":"评分"}的JSON结构输出` }
|
|
186
|
+
// ]
|
|
187
|
+
// const result = await this.chatRequest(message, {}, axiosOption);
|
|
188
|
+
// if (result.successed && result.message) {
|
|
189
|
+
// let value = result.message[0].message.content.trim();
|
|
190
|
+
// let replyJson = this.fixedJsonString(value);
|
|
191
|
+
// ///能够提取到内容
|
|
192
|
+
// if (replyJson.length) return { successed: true, ...replyJson[0] }
|
|
193
|
+
// ///回答的内容非JSON格式,自己来提取算了
|
|
194
|
+
// console.log('自己组装')
|
|
195
|
+
// let matched = value.match(/\d+分/g), score = 0;
|
|
196
|
+
// if (matched && matched.length) {
|
|
197
|
+
// score = Number(matched[0].replace('分', ''));
|
|
198
|
+
// }
|
|
199
|
+
// return { successed: true, comment: value, score }
|
|
200
|
+
// }
|
|
201
|
+
// return { successed: false };
|
|
202
|
+
// }
|
|
203
|
+
// /**
|
|
204
|
+
// * 判断一句话的表达情绪
|
|
205
|
+
// * @param {*} s1
|
|
206
|
+
// * @param {*} axiosOption
|
|
207
|
+
// */
|
|
208
|
+
// override async getScentenceEmotional(s1: string, axiosOption: any = { timeout: 30000 }): Promise<EmotionResult> {
|
|
209
|
+
// if (!s1) return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } }
|
|
210
|
+
// const emotion = ['愤怒', '威胁', '讽刺', '愧疚', '兴奋', '友好', '消极', '生气', '正常'];
|
|
211
|
+
// const messages = [
|
|
212
|
+
// { role: 'system', content: `你是一名专业的语言大师` },
|
|
213
|
+
// { role: 'user', content: s1 },
|
|
214
|
+
// { role: 'user', content: `请分析上述内容的语言情绪,请从"${emotion.join(',')}"这些情绪中对应一个输出` },
|
|
215
|
+
// ]
|
|
216
|
+
// const result = await this.chatRequest(messages, {}, axiosOption);
|
|
217
|
+
// if (result.successed && result.message) {
|
|
218
|
+
// let value = result.message[0].message.content.trim();
|
|
219
|
+
// for (const word of emotion) {
|
|
220
|
+
// if (value.indexOf(word) >= 0) return { successed: true, emotion: word };
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
// return { successed: true, emotion: '未知' };
|
|
224
|
+
// }
|
|
273
225
|
|
|
274
|
-
/**
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
override async getScentenseSimilarity(s1: string, s2: string, axiosOption: any = { timeout: 30000 }): Promise<SimilarityResult> {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
226
|
+
// /**
|
|
227
|
+
// * 获取两句话的相似度取值
|
|
228
|
+
// * @param {*} s1
|
|
229
|
+
// * @param {*} s2
|
|
230
|
+
// */
|
|
231
|
+
// override async getScentenseSimilarity(s1: string, s2: string, axiosOption: any = { timeout: 30000 }): Promise<SimilarityResult> {
|
|
232
|
+
// if (!s1 || !s2) return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } }
|
|
233
|
+
// const messages = [
|
|
234
|
+
// { role: 'system', content: '你是一名专业的语言分析大师' },
|
|
235
|
+
// { role: 'user', content: s1 },
|
|
236
|
+
// { role: 'user', content: s2 },
|
|
237
|
+
// { role: 'user', content: '请从语义上对比以上两句话的相似度,请仅输出0至100之间的整数对比结果即可' },
|
|
238
|
+
// ]
|
|
239
|
+
// const result = await this.chatRequest(messages, { maxtoken: 32 }, axiosOption);
|
|
240
|
+
// if (result.successed && result.message) {
|
|
241
|
+
// let value = result.message[0].message.content.replace(/[^\d]/g, "")
|
|
242
|
+
// if (value > 100) value = Math.floor(value / 10);
|
|
243
|
+
// return { successed: true, value: Number(value) };
|
|
244
|
+
// }
|
|
245
|
+
// return { successed: false, error: result.error, value: 0 };
|
|
294
246
|
|
|
295
|
-
}
|
|
247
|
+
// }
|
|
296
248
|
|
|
297
249
|
|
|
298
|
-
/**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
override async getSimilarityContent(content: string, count: number = 1, axiosOption: any = {}): Promise<ChatReponse> {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
override async getSummaryOfContent(content: string | Array<any>, axiosOption: any = {}): Promise<SummaryReponse> {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
override async generateQuestionsFromContent(content: string, count: number = 1, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ChatReponse> {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
250
|
+
// /**
|
|
251
|
+
// * 获得一种内容的相似说法
|
|
252
|
+
// * 比如:
|
|
253
|
+
// * 你今年多大?
|
|
254
|
+
// * 相似问法:您是哪一年出生的
|
|
255
|
+
// * 您今年贵庚?
|
|
256
|
+
// * @param {*} content
|
|
257
|
+
// * @param {需要出来的数量} count
|
|
258
|
+
// */
|
|
259
|
+
// override async getSimilarityContent(content: string, count: number = 1, axiosOption: any = {}): Promise<ChatReponse> {
|
|
260
|
+
// let chnReg: boolean = /([\u4e00-\u9fa5]|[\ufe30-\uffa0])/.test(content) ///检查源话是否含有中文内容
|
|
261
|
+
// let engReg: boolean = /[a-zA-Z]/.test(content) ///检查源话是否含有英文内容
|
|
262
|
+
// ///如果源话是全中文,那么结果中不应该出来英文的相似说法,如果源话是全英文,则结果不能出现全中文的说法
|
|
263
|
+
// let prefix = (!chnReg && engReg) ? '请用完整的英文表达,' : ((chnReg && !engReg) ? '请用完整的中文表达,' : '')
|
|
264
|
+
// const text = `${prefix}生成与下面句子意思相同的内容"${content}"`
|
|
265
|
+
// let result = await this.chatRequest(text, { replyCounts: count }, axiosOption);
|
|
266
|
+
// if (!result.successed || !result.message) return result;
|
|
267
|
+
// let replys = result.message.map(item => { return item.message.content.trim(); })
|
|
268
|
+
// return { successed: true, message: replys }
|
|
269
|
+
// }
|
|
270
|
+
// /**
|
|
271
|
+
// * 提取内容的中心思想摘要
|
|
272
|
+
// * @param content
|
|
273
|
+
// * @param axiosOption
|
|
274
|
+
// */
|
|
275
|
+
// override async getSummaryOfContent(content: string | Array<any>, axiosOption: any = {}): Promise<SummaryReponse> {
|
|
276
|
+
// let arrContent: any[] = [];
|
|
277
|
+
// if (typeof (content) == 'string') {
|
|
278
|
+
// let splittext = this.splitLongText(content);
|
|
279
|
+
// for (const string of splittext) {
|
|
280
|
+
// arrContent.push({ role: 'user', content: string })
|
|
281
|
+
// }
|
|
282
|
+
// } else {
|
|
283
|
+
// arrContent = content;
|
|
284
|
+
// }
|
|
285
|
+
// let summary: Array<OutlineSummaryItem> = [];
|
|
286
|
+
// while (arrContent.length > 0) {
|
|
287
|
+
// let subarray = arrContent.slice(0, MESSAGE_LENGTH);
|
|
288
|
+
// subarray.push({ role: 'user', content: '根据上述内容精简,提炼内容提纲及摘要内容,每项摘要内容尽量精简数据化不超过100字,结果严格按照[{outline:"提纲标题","summary":["摘要内容1","摘要内容2","摘要内容3"]}]的JSON结构输出' })
|
|
289
|
+
// let result = await this.chatRequest(subarray, {}, axiosOption);
|
|
290
|
+
// if (result.successed && result.message) {
|
|
291
|
+
// try {
|
|
292
|
+
// // console.log('result.message[0].content', result.message[0].message.content)
|
|
293
|
+
// let jsonObjItems = JSON.parse(result.message[0].message.content)
|
|
294
|
+
// if (Array.isArray(jsonObjItems)) summary = summary.concat(jsonObjItems)
|
|
295
|
+
// } catch (error) {
|
|
296
|
+
// console.log('result.message[0].content', error)
|
|
297
|
+
// }
|
|
298
|
+
// }
|
|
299
|
+
// ////删除已经处理的文本
|
|
300
|
+
// arrContent.splice(0, MESSAGE_LENGTH);
|
|
301
|
+
// }
|
|
302
|
+
// return { successed: true, article: summary }
|
|
303
|
+
// }
|
|
304
|
+
// /**
|
|
305
|
+
// * 从指定的文本内容中生成相关的问答
|
|
306
|
+
// * @param {*} content
|
|
307
|
+
// * @param {*} count
|
|
308
|
+
// * @param {*} axiosOption
|
|
309
|
+
// * @returns
|
|
310
|
+
// *///并在答案末尾处必须给出答案内容中的关键词
|
|
311
|
+
// override async generateQuestionsFromContent(content: string, count: number = 1, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ChatReponse> {
|
|
312
|
+
// let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
313
|
+
// ///如果最后一段的文字内容过短,则把最后一段内容追加到前一段中,并删除最后一段
|
|
314
|
+
// let totalLen = arrContent.length;
|
|
315
|
+
// if (totalLen >= 2 && (arrContent[totalLen - 1]?.length || 0) < 100) {
|
|
316
|
+
// arrContent[totalLen - 2] += arrContent[totalLen - 1];
|
|
317
|
+
// arrContent.splice(totalLen - 1, 1);
|
|
318
|
+
// }
|
|
319
|
+
// ///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
320
|
+
// ///每一句话需要产生的题目
|
|
321
|
+
// let questions4EverySentense: number = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
322
|
+
// let faqs: FaqItem[] = [], gotted: number = 0;
|
|
323
|
+
// while (arrContent.length > 0 && gotted < count) {
|
|
324
|
+
// questions4EverySentense = (count - gotted) / arrContent.length
|
|
325
|
+
// ////每次最多送MESSAGE_LENGTH句话给openai
|
|
326
|
+
// let itemCount = Math.min(Math.ceil(questions4EverySentense), count - gotted);
|
|
327
|
+
// let subarray = [
|
|
328
|
+
// { role: 'system', content: FAQ_ROLE_DEFINE },
|
|
329
|
+
// { role: 'user', content: `从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组 []。` },
|
|
330
|
+
// { role: 'user', content: arrContent.slice(0, 1)[0] }
|
|
331
|
+
// ]
|
|
332
|
+
// console.log('Faq Question Pick Prompt:', subarray)
|
|
333
|
+
// let result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
334
|
+
// ///如果请求发生了网络错误(不是内容合规问题),则再重试一次,如果任然有错则放弃
|
|
335
|
+
// if (!result.successed && result.error != 'content_filter') {
|
|
336
|
+
// console.log('network error,retry onemore time')
|
|
337
|
+
// result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
338
|
+
// }
|
|
339
|
+
// if (result.successed && result.message) {
|
|
340
|
+
// let msgs = await this.pickUpFaqContent(result.message);
|
|
341
|
+
// if (msgs.length) {
|
|
342
|
+
// ///对外发送检出问答题的信号
|
|
343
|
+
// this.emit('parseout', { type: 'qa', items: msgs })
|
|
344
|
+
// gotted += msgs.length; //result.message.length;
|
|
345
|
+
// faqs = faqs.concat(msgs);
|
|
346
|
+
// }
|
|
347
|
+
// }
|
|
348
|
+
// ////删除已经处理的文本
|
|
349
|
+
// arrContent.splice(0, 1);
|
|
350
|
+
// }
|
|
351
|
+
// arrContent = []; /// 释放内存
|
|
352
|
+
// ///发出信号,解析完毕
|
|
353
|
+
// this.emit('parseover', { type: 'qa', items: faqs })
|
|
354
|
+
// return { successed: true, message: faqs.slice(0, count) };
|
|
355
|
+
// }
|
|
404
356
|
|
|
405
|
-
/**
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
protected async pickUpFaqContent(messages: Array<any>): Promise<Array<FaqItem>> {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
try {
|
|
432
|
-
//let jsonObj = JSON.parse(answerString);
|
|
433
|
-
//let jsonObj = eval(answerString);
|
|
434
|
-
jsonObj.map((item: FaqItem) => {
|
|
435
|
-
let realKeyword: string[] = [];
|
|
436
|
-
let keywords: string[] = (item.keywords + '').split(',');
|
|
437
|
-
let answer = item.answer || '';
|
|
438
|
-
for (const k of keywords) {
|
|
439
|
-
if (k && answer.indexOf(k) >= 0) realKeyword.push(k)
|
|
440
|
-
}
|
|
441
|
-
item.keywords = realKeyword;
|
|
442
|
-
return item;
|
|
443
|
-
})
|
|
444
|
-
return jsonObj;
|
|
445
|
-
} catch (err) {
|
|
446
|
-
console.log('JSON error', err)
|
|
447
|
-
return [];
|
|
448
|
-
}
|
|
449
|
-
}
|
|
357
|
+
// /**
|
|
358
|
+
// * 解析Faq返回的问题
|
|
359
|
+
// * @param {*} messages
|
|
360
|
+
// * @returns
|
|
361
|
+
// */
|
|
362
|
+
// protected async pickUpFaqContent(messages: Array<any>): Promise<Array<FaqItem>> {
|
|
363
|
+
// if (!messages[0]?.message?.content) return [];
|
|
364
|
+
// let answerString = messages[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
365
|
+
// if (answerString === '[]') return [];
|
|
366
|
+
// let jsonObj = this.fixedJsonString(answerString);
|
|
367
|
+
// if (!jsonObj.length) {
|
|
368
|
+
// let fixedAsk = [
|
|
369
|
+
// { role: 'system', content: '角色扮演:假设你是一位高级JSON数据分析师' },
|
|
370
|
+
// { role: 'user', content: `请分析以下内容,严格按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的标准JSON数组结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组,无需提供参考。` },
|
|
371
|
+
// { role: 'user', content: answerString },
|
|
372
|
+
// ]
|
|
373
|
+
// console.log('pickUpFaqContent fixedAsk', fixedAsk)
|
|
374
|
+
// let fixedJsonResult: any = await this.chatRequest(fixedAsk, { replyCounts: 1 }, {})
|
|
375
|
+
// if (fixedJsonResult.successed) {
|
|
376
|
+
// answerString = fixedJsonResult.message[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
377
|
+
// jsonObj = this.fixedJsonString(answerString);
|
|
378
|
+
// }
|
|
379
|
+
// if (!jsonObj.length) return []
|
|
380
|
+
// }
|
|
450
381
|
|
|
451
|
-
/**
|
|
452
|
-
* 从指定的文本内容中生成一张试卷
|
|
453
|
-
* @param {*} content
|
|
454
|
-
* @param {试卷的参数} paperOption
|
|
455
|
-
* totalscore: 试卷总分,默认100
|
|
456
|
-
* section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
457
|
-
* @param {*} axiosOption
|
|
458
|
-
* @returns
|
|
459
|
-
*///并在答案末尾处必须给出答案内容中的关键词
|
|
460
|
-
override async generateExaminationPaperFromContent(content: string, paperOption: any = {}, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ExaminationPaperResult> {
|
|
461
|
-
let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
462
|
-
///如果最后一段的文字内容过短,则把最后一段内容追加到前一段中,并删除最后一段
|
|
463
|
-
let totalLen = arrContent.length;
|
|
464
|
-
if (totalLen >= 2 && (arrContent[totalLen - 1]?.length || 0) < 100) {
|
|
465
|
-
arrContent[totalLen - 2] += arrContent[totalLen - 1];
|
|
466
|
-
arrContent.splice(totalLen - 1, 1);
|
|
467
|
-
}
|
|
468
|
-
let sectionCount: any = {
|
|
469
|
-
singlechoice: (paperOption.singlechoice?.count || 0) / arrContent.length,
|
|
470
|
-
multiplechoice: (paperOption.multiplechoice?.count || 0) / arrContent.length,
|
|
471
|
-
trueorfalse: (paperOption.trueorfalse?.count || 0) / arrContent.length,
|
|
472
|
-
completion: (paperOption.completion?.count || 0) / arrContent.length
|
|
473
|
-
};
|
|
474
|
-
///剩余待生成的题目数量
|
|
475
|
-
let remainCount: any = {
|
|
476
|
-
singlechoice: paperOption.singlechoice?.count || 0,
|
|
477
|
-
multiplechoice: paperOption.multiplechoice?.count || 0,
|
|
478
|
-
trueorfalse: paperOption.trueorfalse?.count || 0,
|
|
479
|
-
completion: paperOption.completion?.count || 0
|
|
480
|
-
};
|
|
481
|
-
///每种类型的题目的分数
|
|
482
|
-
let ITEM_SCORE: any = {
|
|
483
|
-
singlechoice: paperOption.singlechoice?.score || 0,
|
|
484
|
-
multiplechoice: paperOption.multiplechoice?.score || 0,
|
|
485
|
-
trueorfalse: paperOption.trueorfalse?.score || 0,
|
|
486
|
-
completion: paperOption.completion?.score || 0
|
|
487
|
-
};
|
|
488
|
-
///最后生成出来的结果
|
|
489
|
-
let paperReturned: any = {
|
|
490
|
-
singlechoice: [], multiplechoice: [], trueorfalse: [], completion: []
|
|
491
382
|
|
|
492
|
-
|
|
383
|
+
// try {
|
|
384
|
+
// //let jsonObj = JSON.parse(answerString);
|
|
385
|
+
// //let jsonObj = eval(answerString);
|
|
386
|
+
// jsonObj.map((item: FaqItem) => {
|
|
387
|
+
// let realKeyword: string[] = [];
|
|
388
|
+
// let keywords: string[] = (item.keywords + '').split(',');
|
|
389
|
+
// let answer = item.answer || '';
|
|
390
|
+
// for (const k of keywords) {
|
|
391
|
+
// if (k && answer.indexOf(k) >= 0) realKeyword.push(k)
|
|
392
|
+
// }
|
|
393
|
+
// item.keywords = realKeyword;
|
|
394
|
+
// return item;
|
|
395
|
+
// })
|
|
396
|
+
// return jsonObj;
|
|
397
|
+
// } catch (err) {
|
|
398
|
+
// console.log('JSON error', err)
|
|
399
|
+
// return [];
|
|
400
|
+
// }
|
|
401
|
+
// }
|
|
493
402
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
403
|
+
// /**
|
|
404
|
+
// * 从指定的文本内容中生成一张试卷
|
|
405
|
+
// * @param {*} content
|
|
406
|
+
// * @param {试卷的参数} paperOption
|
|
407
|
+
// * totalscore: 试卷总分,默认100
|
|
408
|
+
// * section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
409
|
+
// * @param {*} axiosOption
|
|
410
|
+
// * @returns
|
|
411
|
+
// *///并在答案末尾处必须给出答案内容中的关键词
|
|
412
|
+
// override async generateExaminationPaperFromContent(content: string, paperOption: any = {}, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ExaminationPaperResult> {
|
|
413
|
+
// let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
414
|
+
// ///如果最后一段的文字内容过短,则把最后一段内容追加到前一段中,并删除最后一段
|
|
415
|
+
// let totalLen = arrContent.length;
|
|
416
|
+
// if (totalLen >= 2 && (arrContent[totalLen - 1]?.length || 0) < 100) {
|
|
417
|
+
// arrContent[totalLen - 2] += arrContent[totalLen - 1];
|
|
418
|
+
// arrContent.splice(totalLen - 1, 1);
|
|
419
|
+
// }
|
|
420
|
+
// let sectionCount: any = {
|
|
421
|
+
// singlechoice: (paperOption.singlechoice?.count || 0) / arrContent.length,
|
|
422
|
+
// multiplechoice: (paperOption.multiplechoice?.count || 0) / arrContent.length,
|
|
423
|
+
// trueorfalse: (paperOption.trueorfalse?.count || 0) / arrContent.length,
|
|
424
|
+
// completion: (paperOption.completion?.count || 0) / arrContent.length
|
|
425
|
+
// };
|
|
426
|
+
// ///剩余待生成的题目数量
|
|
427
|
+
// let remainCount: any = {
|
|
428
|
+
// singlechoice: paperOption.singlechoice?.count || 0,
|
|
429
|
+
// multiplechoice: paperOption.multiplechoice?.count || 0,
|
|
430
|
+
// trueorfalse: paperOption.trueorfalse?.count || 0,
|
|
431
|
+
// completion: paperOption.completion?.count || 0
|
|
432
|
+
// };
|
|
433
|
+
// ///每种类型的题目的分数
|
|
434
|
+
// let ITEM_SCORE: any = {
|
|
435
|
+
// singlechoice: paperOption.singlechoice?.score || 0,
|
|
436
|
+
// multiplechoice: paperOption.multiplechoice?.score || 0,
|
|
437
|
+
// trueorfalse: paperOption.trueorfalse?.score || 0,
|
|
438
|
+
// completion: paperOption.completion?.score || 0
|
|
439
|
+
// };
|
|
440
|
+
// ///最后生成出来的结果
|
|
441
|
+
// let paperReturned: any = {
|
|
442
|
+
// singlechoice: [], multiplechoice: [], trueorfalse: [], completion: []
|
|
504
443
|
|
|
505
|
-
|
|
506
|
-
let itemCount = Math.min(remainCount[key], Math.ceil(sectionCount[key]));
|
|
507
|
-
let subarray:any[] = [
|
|
508
|
-
{ role: 'system', content: QUESTION_ROLE_DEFINE[key] },
|
|
509
|
-
{ role: 'user', content: QUESTION_PROMPT[key].replace('@ITEMCOUNT@', itemCount) },
|
|
510
|
-
{ role: 'user', content: arrContent.slice(0, 1)[0] }
|
|
511
|
-
]
|
|
512
|
-
// subarray.unshift()
|
|
513
|
-
console.log('subarray', subarray)
|
|
514
|
-
let result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
515
|
-
///如果请求发生了网络错误(不是内容合规问题),则再重试一次,如果任然有错则放弃
|
|
516
|
-
if (!result.successed && result.error != 'content_filter') {
|
|
517
|
-
console.log('network error,retry onemore time')
|
|
518
|
-
result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
519
|
-
}
|
|
520
|
-
console.log('subarray returned', result.successed)
|
|
521
|
-
if (result.successed && result.message) {
|
|
522
|
-
//console.log('paper result', key, result.message.length)
|
|
523
|
-
let pickedQuestions = await this.pickUpQuestions(result.message, itemCount, key, ITEM_SCORE[key]);
|
|
524
|
-
if (pickedQuestions.length) {
|
|
525
|
-
///对外发送检出题目的信号
|
|
526
|
-
this.emit('parseout', { type: 'question', name: key, items: pickedQuestions })
|
|
527
|
-
paperReturned[key] = paperReturned[key].concat(pickedQuestions);
|
|
528
|
-
remainCount[key] = remainCount[key] - pickedQuestions.length;
|
|
529
|
-
totalscore = totalscore + pickedQuestions.length * ITEM_SCORE[key];
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
//subarray.splice(0, 1); ///把第一个角色定位的问法删除
|
|
533
|
-
// subarray.splice(subarray.length - 1, 1); ///把第一个角色定位的问法删除
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
////删除已经处理的文本
|
|
538
|
-
arrContent.splice(0, MESSAGE_LENGTH);
|
|
539
|
-
}
|
|
540
|
-
console.log('parseover')
|
|
541
|
-
///发出信号,解析完毕
|
|
542
|
-
this.emit('parseover', { type: 'question', items: paperReturned })
|
|
543
|
-
return { successed: true, score: totalscore, paper: paperReturned }
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* 从答复中得到题目
|
|
547
|
-
* @param {*} result
|
|
548
|
-
*
|
|
549
|
-
*/
|
|
550
|
-
protected async pickUpQuestions(result: Array<any>, count: number, questiontype: string, score: number = 1): Promise<Array<QuestionItem>> {
|
|
551
|
-
if (!result[0]?.message?.content) return [];
|
|
552
|
-
let answerString = result[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
553
|
-
if (answerString === '[]') return [];
|
|
554
|
-
let jsonObj = this.fixedJsonString(answerString);
|
|
555
|
-
////修复的结果无法用程序修复,请求GPT来分析修复一下这个结果
|
|
556
|
-
if (!jsonObj.length){
|
|
557
|
-
let fixedAsk = [
|
|
558
|
-
{role:'system',content:'角色扮演:假设你是一位高级JSON数据分析师'},
|
|
559
|
-
{ role: 'user', content: `请分析以下内容,严格按照${QUESTION_PROMPT_FIXED[questiontype]}的标准JSON数组结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组,无需提供参考。` },
|
|
560
|
-
{ role: 'user', content: answerString },
|
|
561
|
-
]
|
|
562
|
-
console.log('fixedAsk', fixedAsk)
|
|
563
|
-
let fixedJsonResult:any =await this.chatRequest(fixedAsk,{replyCounts:1},{})
|
|
564
|
-
if (fixedJsonResult.successed){
|
|
565
|
-
answerString = fixedJsonResult.message[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
566
|
-
jsonObj = this.fixedJsonString(answerString);
|
|
567
|
-
}
|
|
568
|
-
if (!jsonObj.length) return []
|
|
569
|
-
}
|
|
570
|
-
let returnItems: QuestionItem[] = [];
|
|
571
|
-
try {
|
|
572
|
-
// let jsonObj = JSON.parse(answerString);
|
|
573
|
-
returnItems = jsonObj.map((questionitem: any) => {
|
|
574
|
-
console.log('answer item from jsonObj', questionitem);
|
|
575
|
-
if (questionitem.choice && Array.isArray(questionitem.choice) && questiontype != 'completion') {
|
|
576
|
-
questionitem.fullanswer = (questionitem.answer + '').replace(/,|[^ABCDE]/g, '');
|
|
577
|
-
questionitem.score = score;
|
|
578
|
-
if (questionitem.choice) {
|
|
579
|
-
questionitem.choice = questionitem.choice.map((item: string, index: number) => {
|
|
580
|
-
let seqNo = 'ABCDEFG'[index]; //String.fromCharCode(65 + index);
|
|
581
|
-
let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig')
|
|
582
|
-
// console.log('itemitemitem', item)
|
|
583
|
-
//let answer = jsonObj.fullanswer
|
|
584
|
-
return {
|
|
585
|
-
id: seqNo,
|
|
586
|
-
content: (item + '').replace(correctReg, '').trim(),
|
|
587
|
-
iscorrect: (questionitem.fullanswer || '').indexOf(seqNo) >= 0 ? 1 : 0
|
|
588
|
-
//|| jsonObj.fullanswer.indexOf(m))
|
|
589
|
-
}
|
|
590
|
-
})
|
|
591
|
-
}
|
|
592
|
-
///如果是非判断题,题目的选项数量小于2 ,则无效
|
|
593
|
-
///如果是判断题,题目的选项必须=2
|
|
594
|
-
if (!questionitem.choice || (questiontype != 'trueorfalse' && questionitem.choice.length < 3) || (questiontype == 'trueorfalse' && questionitem.choice.length != 2)) {
|
|
595
|
-
return null;
|
|
596
|
-
}
|
|
444
|
+
// }, noMoreQuestionRetrive: boolean = false, totalscore: number = 0;
|
|
597
445
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
questionitem.answer = [rightItem?.id || 'Z'] ; //[(questionitem.answer + '').indexOf('正确') >= 0 ? 'A' : 'B']
|
|
609
|
-
break;
|
|
610
|
-
}
|
|
611
|
-
///单选题验证
|
|
612
|
-
if (questiontype == 'singlechoice') {
|
|
613
|
-
let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
|
|
614
|
-
///单选题的正确选项大于了1个
|
|
615
|
-
if (rightAnswer.length != 1 || !questionitem.answer || questionitem.answer.length !== 1) return null;
|
|
616
|
-
///正确选项和答案不一致
|
|
617
|
-
if (rightAnswer[0].id.toUpperCase() != (questionitem.answer[0] || '').toUpperCase()) return null;
|
|
618
|
-
}
|
|
619
|
-
///多选题验证
|
|
620
|
-
if (questiontype == 'multiplechoice') {
|
|
621
|
-
let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
|
|
622
|
-
///单选题的正确选项大于了1个
|
|
623
|
-
if (rightAnswer.length === 0 || !questionitem.answer || questionitem.answer.length === 0) return null;
|
|
624
|
-
}
|
|
625
|
-
///判断题验证:防止没有答案的
|
|
626
|
-
if (questiontype == 'trueorfalse' && !questionitem.answer.length ) return null;
|
|
446
|
+
// while (arrContent.length > 0 && !noMoreQuestionRetrive) {
|
|
447
|
+
// ////每次最多送MESSAGE_LENGTH句话给openai
|
|
448
|
+
// /**
|
|
449
|
+
// * 每种类型的题目进行遍历
|
|
450
|
+
// */
|
|
451
|
+
// noMoreQuestionRetrive = true;
|
|
452
|
+
// for (const key of QUESTION_TYPE) {
|
|
453
|
+
// ///还需要抓取题目
|
|
454
|
+
// if (remainCount[key] > 0) {
|
|
455
|
+
// noMoreQuestionRetrive = false;
|
|
627
456
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
457
|
+
// //let itemCount = Math.min(remainCount[key], Math.ceil(subarray.length * sectionCount[key]));
|
|
458
|
+
// let itemCount = Math.min(remainCount[key], Math.ceil(sectionCount[key]));
|
|
459
|
+
// let subarray: any[] = [
|
|
460
|
+
// { role: 'system', content: QUESTION_ROLE_DEFINE[key] },
|
|
461
|
+
// { role: 'user', content: QUESTION_PROMPT[key].replace('@ITEMCOUNT@', itemCount).replace('@CONTENT@', arrContent.slice(0, 1)[0]) },
|
|
462
|
+
// // { role: 'user', content:`出题材料:${arrContent.slice(0, 1)[0]}`}
|
|
463
|
+
// ]
|
|
464
|
+
// // subarray.unshift()
|
|
465
|
+
// console.log('subarray', subarray)
|
|
466
|
+
// let result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
467
|
+
// ///如果请求发生了网络错误(不是内容合规问题),则再重试一次,如果任然有错则放弃
|
|
468
|
+
// if (!result.successed && result.error != 'content_filter') {
|
|
469
|
+
// console.log('network error,retry onemore time')
|
|
470
|
+
// result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
471
|
+
// }
|
|
472
|
+
// console.log('subarray returned', result.successed)
|
|
473
|
+
// if (result.successed && result.message) {
|
|
474
|
+
// ///以下再次验证好像没有什么效果,暂时取消
|
|
475
|
+
// // subarray.push(
|
|
476
|
+
// // {role: 'assistant', content: result.message[0].message.content},
|
|
477
|
+
// // {role: 'user', content:`请将上述结果,结合出题材料再次进行验证,结果必须满足问题对应的正确答案必须在出题材料中完整且一字不差连续出现,如出现不满足的情况,请再次修正直到问题对应的正确答案必须在出题材料中完整且一字不差连续出现为止,最终按照结果要求输出后输出`
|
|
478
|
+
// // })
|
|
479
|
+
// // console.log('subarray reask', subarray)
|
|
480
|
+
// // result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
481
|
+
// // if (result.successed && result.message){
|
|
482
|
+
// //console.log('paper result', key, result.message.length)
|
|
483
|
+
// let pickedQuestions = await this.pickUpQuestions(result.message, itemCount, key, ITEM_SCORE[key]);
|
|
484
|
+
// if (pickedQuestions.length) {
|
|
485
|
+
// ///对外发送检出题目的信号
|
|
486
|
+
// this.emit('parseout', { type: 'question', name: key, items: pickedQuestions })
|
|
487
|
+
// paperReturned[key] = paperReturned[key].concat(pickedQuestions);
|
|
488
|
+
// remainCount[key] = remainCount[key] - pickedQuestions.length;
|
|
489
|
+
// totalscore = totalscore + pickedQuestions.length * ITEM_SCORE[key];
|
|
654
490
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
491
|
+
// console.log('start sleep', new Date().getTime())
|
|
492
|
+
// await this.sleep(30);
|
|
493
|
+
// console.log('do check', new Date().getTime())
|
|
494
|
+
// let allItemInfo = pickedQuestions.map((q: QuestionItem, idx: number) => { return `\r\n(${idx + 1}).` + q.question + '\n选项\n' + q.choice?.map(c => { return `(${c.id}) ${c.content}`; }).join('\n'); }).join('\n');
|
|
495
|
+
// console.log('allItemInfo', allItemInfo)
|
|
496
|
+
// let prmopt = [{
|
|
497
|
+
// role: 'user',
|
|
498
|
+
// content: `请根据内容,完成以下题目作答,最终结果标准JSON数组并按照[{"seq":serialnumber,"answer":[正确答案]}]的结构输出。
|
|
499
|
+
// \n内容:"${arrContent.slice(0, 1)[0]}"
|
|
500
|
+
// \r\n${QUESTION_TYPE_TITLE[key]}\r\n${allItemInfo}`
|
|
501
|
+
// }];
|
|
502
|
+
// let checkResult = await this.chatRequest(prmopt, { replyCounts: 1 }, axiosOption);
|
|
503
|
+
// if (checkResult.successed && checkResult.message) {
|
|
504
|
+
// console.log("出题试卷答案:", pickedQuestions.map((oq, on) => {
|
|
505
|
+
// return `(${on + 1}).` + oq.question + ' 答案 : ' + oq.answer + ''
|
|
506
|
+
// }).join('\n'))
|
|
507
|
+
// console.log("复查后的答案:", checkResult.message[0].message.content.trim())
|
|
508
|
+
// }
|
|
509
|
+
// await this.sleep(30);
|
|
510
|
+
// }
|
|
511
|
+
// }
|
|
512
|
+
// //subarray.splice(0, 1); ///把第一个角色定位的问法删除
|
|
513
|
+
// // subarray.splice(subarray.length - 1, 1); ///把第一个角色定位的问法删除
|
|
514
|
+
// }
|
|
515
|
+
// }
|
|
681
516
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
517
|
+
// ////删除已经处理的文本
|
|
518
|
+
// arrContent.splice(0, MESSAGE_LENGTH);
|
|
519
|
+
// }
|
|
520
|
+
// console.log('parseover')
|
|
521
|
+
// ///发出信号,解析完毕
|
|
522
|
+
// this.emit('parseover', { type: 'question', items: paperReturned })
|
|
523
|
+
// return { successed: true, score: totalscore, paper: paperReturned }
|
|
524
|
+
// }
|
|
525
|
+
// /**
|
|
526
|
+
// * 从答复中得到题目
|
|
527
|
+
// * @param {*} result
|
|
528
|
+
// *
|
|
529
|
+
// */
|
|
530
|
+
// protected async pickUpQuestions(result: Array<any>, count: number, questiontype: string, score: number = 1): Promise<Array<QuestionItem>> {
|
|
531
|
+
// if (!result[0]?.message?.content) return [];
|
|
532
|
+
// let answerString = result[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
533
|
+
// if (answerString === '[]') return [];
|
|
534
|
+
// let jsonObj = this.fixedJsonString(answerString);
|
|
535
|
+
// ////修复的结果无法用程序修复,请求GPT来分析修复一下这个结果
|
|
536
|
+
// if (!jsonObj.length) {
|
|
537
|
+
// console.log('Json格式有误,再次进行GPT修复', answerString);
|
|
538
|
+
// let fixedAsk = [
|
|
539
|
+
// { role: 'system', content: '角色扮演:假设你是一位高级JSON数据分析师' },
|
|
540
|
+
// { role: 'user', content: `请分析以下内容,严格按照${QUESTION_PROMPT_FIXED[questiontype]}的标准JSON数组结构输出。如果内容不足以提取问题和答案,请直接输出JSON空数组,无需提供参考。` },
|
|
541
|
+
// { role: 'user', content: answerString },
|
|
542
|
+
// ]
|
|
543
|
+
// let fixedJsonResult: any = await this.chatRequest(fixedAsk, { replyCounts: 1 }, {})
|
|
544
|
+
// if (fixedJsonResult.successed) {
|
|
545
|
+
// answerString = fixedJsonResult.message[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
546
|
+
// jsonObj = this.fixedJsonString(answerString);
|
|
547
|
+
// }
|
|
548
|
+
// console.log('Json GPT修复 结果', fixedJsonResult.successed, answerString)
|
|
549
|
+
// if (!jsonObj.length) return []
|
|
550
|
+
// }
|
|
551
|
+
// let returnItems: QuestionItem[] = [];
|
|
552
|
+
// try {
|
|
553
|
+
// // let jsonObj = JSON.parse(answerString);
|
|
554
|
+
// returnItems = jsonObj.map((questionitem: any) => {
|
|
555
|
+
// console.log('answer item from jsonObj', questionitem);
|
|
556
|
+
// if (questionitem.choice && Array.isArray(questionitem.choice) && questiontype != 'completion') {
|
|
557
|
+
// questionitem.fullanswer = (questionitem.answer + '').replace(/,|[^ABCDE]/g, '');
|
|
558
|
+
// questionitem.score = score;
|
|
559
|
+
// if (questionitem.choice) {
|
|
560
|
+
// questionitem.choice = questionitem.choice.map((item: string, index: number) => {
|
|
561
|
+
// let seqNo = 'ABCDEFG'[index]; //String.fromCharCode(65 + index);
|
|
562
|
+
// let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig')
|
|
563
|
+
// return {
|
|
564
|
+
// id: seqNo,
|
|
565
|
+
// content: (item + '').replace(correctReg, '').trim(),
|
|
566
|
+
// iscorrect: (questionitem.fullanswer || '').indexOf(seqNo) >= 0 ? 1 : 0
|
|
567
|
+
// }
|
|
568
|
+
// })
|
|
569
|
+
// }
|
|
570
|
+
// ///如果是非判断题,题目的选项数量小于2 ,则无效
|
|
571
|
+
// ///如果是判断题,题目的选项必须=2
|
|
572
|
+
// if (!questionitem.choice || (questiontype != 'trueorfalse' && questionitem.choice.length < 3) || (questiontype == 'trueorfalse' && questionitem.choice.length != 2)) {
|
|
573
|
+
// return null;
|
|
574
|
+
// }
|
|
689
575
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
576
|
+
// }
|
|
577
|
+
// switch (questiontype) {
|
|
578
|
+
// case 'singlechoice':
|
|
579
|
+
// questionitem.answer = (questionitem.answer + '').replace(/,|[^ABCDEFG]/g, '').split('').slice(0, 1);
|
|
580
|
+
// break;
|
|
581
|
+
// case 'multiplechoice':
|
|
582
|
+
// questionitem.answer = Array.from(new Set((questionitem.answer + '').replace(/,|[^ABCDEFG]/g, '').split(''))).sort();
|
|
583
|
+
// break;
|
|
584
|
+
// case 'trueorfalse':
|
|
585
|
+
// let rightItem = questionitem.choice.find((x: any) => { return x.iscorrect == 1 });
|
|
586
|
+
// questionitem.answer = [rightItem?.id || 'Z']; //[(questionitem.answer + '').indexOf('正确') >= 0 ? 'A' : 'B']
|
|
587
|
+
// break;
|
|
588
|
+
// }
|
|
589
|
+
// ///单选题验证
|
|
590
|
+
// if (questiontype == 'singlechoice') {
|
|
591
|
+
// let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
|
|
592
|
+
// ///单选题的正确选项大于了1个
|
|
593
|
+
// if (rightAnswer.length != 1 || !questionitem.answer || questionitem.answer.length !== 1) return null;
|
|
594
|
+
// ///正确选项和答案不一致
|
|
595
|
+
// if (rightAnswer[0].id.toUpperCase() != (questionitem.answer[0] || '').toUpperCase()) return null;
|
|
596
|
+
// }
|
|
597
|
+
// ///多选题验证
|
|
598
|
+
// if (questiontype == 'multiplechoice') {
|
|
599
|
+
// let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
|
|
600
|
+
// ///单选题的正确选项大于了1个
|
|
601
|
+
// if (rightAnswer.length === 0 || !questionitem.answer || questionitem.answer.length === 0) return null;
|
|
602
|
+
// }
|
|
603
|
+
// ///判断题验证:防止没有答案的
|
|
604
|
+
// if (questiontype == 'trueorfalse' && !questionitem.answer.length) return null;
|
|
605
|
+
|
|
606
|
+
// return questionitem;
|
|
607
|
+
// })
|
|
608
|
+
// } catch (err) {
|
|
609
|
+
// console.log('error happened:', err);
|
|
610
|
+
// }
|
|
611
|
+
// return returnItems.filter(i => { return i != null; }).slice(0, count);
|
|
612
|
+
// }
|
|
613
|
+
// /**
|
|
614
|
+
// * 验证JSON字符串是否是真正可转换为JSON的合法格式
|
|
615
|
+
// * 这里只能做一个最简单的处理,就是用两端的符号
|
|
616
|
+
// * @param jsonstr
|
|
617
|
+
// */
|
|
618
|
+
// protected fixedJsonString(jsonstr: string): any[] {
|
|
619
|
+
// console.log('original json string:', jsonstr)
|
|
620
|
+
// ///检查返回的是不是一个数组对象(我们需要的是数组对象)
|
|
621
|
+
// let firstBracketSymbol = jsonstr.indexOf("["); ////必须过滤出来数组
|
|
622
|
+
// let lastBracketSymbol = jsonstr.lastIndexOf("]");
|
|
623
|
+
// ///第一个花括号出现的位置,如果花括号出现的位置早于 [ ,则默认返回的对象不是一个数组,仅仅是一个对象,
|
|
624
|
+
// ///则需要我们用中括号包住
|
|
625
|
+
// let firstBraceSymbol = jsonstr.indexOf("{");
|
|
626
|
+
// let lastBraceSymbol = jsonstr.lastIndexOf("}");
|
|
627
|
+
// ///返回的不是一个数组结构的,只是一个{},我们帮他完成数组拼接
|
|
628
|
+
// if (firstBraceSymbol >= 0 &&
|
|
629
|
+
// firstBraceSymbol < (firstBracketSymbol >= 0 ? firstBracketSymbol : 1000) &&
|
|
630
|
+
// lastBraceSymbol > firstBraceSymbol &&
|
|
631
|
+
// lastBraceSymbol >= 0 && lastBraceSymbol > lastBracketSymbol) {
|
|
632
|
+
|
|
633
|
+
// jsonstr = '[' + jsonstr.substr(firstBraceSymbol, lastBraceSymbol - firstBraceSymbol + 1); +']';
|
|
634
|
+
// firstBracketSymbol = 0;
|
|
635
|
+
// lastBracketSymbol = jsonstr.length - 1;
|
|
636
|
+
// }
|
|
637
|
+
// else if (firstBracketSymbol < 0 || lastBracketSymbol < 0 || lastBracketSymbol <= firstBracketSymbol) {
|
|
638
|
+
// return [];
|
|
639
|
+
// }
|
|
640
|
+
// jsonstr = jsonstr.substr(firstBracketSymbol, lastBracketSymbol - firstBracketSymbol + 1);
|
|
641
|
+
// ///尽量处理一些能够一眼识别出来的JSON错误
|
|
642
|
+
// jsonstr = jsonstr.replace(/}{/g, '},{');
|
|
643
|
+
// let mutilitems = jsonstr.split('][');
|
|
644
|
+
// ///确实存在多个数组拼接在一起,中间没有逗号隔开的了
|
|
645
|
+
// let retObject: any[] = [];
|
|
646
|
+
// for (let str of mutilitems) {
|
|
647
|
+
// if (!str.startsWith('[')) str = '[' + str;
|
|
648
|
+
// if (!str.endsWith(']')) str = str + ']';
|
|
649
|
+
// // console.log('json str', str)
|
|
650
|
+
// try {
|
|
651
|
+
// let jsonObj = eval(str);
|
|
652
|
+
// retObject = retObject.concat(jsonObj);
|
|
653
|
+
// } catch (err) {
|
|
654
|
+
// console.log('json error', str)
|
|
655
|
+
// }
|
|
656
|
+
// }
|
|
657
|
+
// return retObject;
|
|
658
|
+
// }
|
|
659
|
+
|
|
660
|
+
// /**
|
|
661
|
+
// * 将一段很长的文本,按1024长度来划分到多个中
|
|
662
|
+
// * @param {*} content
|
|
663
|
+
// */
|
|
664
|
+
// protected splitLongText(content: string, len = SECTION_LENGTH): string[] { //Array<ChatCompletionRequestMessage> {
|
|
665
|
+
// let start = 0, message: string[] = [], length = content.length;
|
|
666
|
+
// while (start < length) {
|
|
667
|
+
|
|
668
|
+
// let realLength: number = len;
|
|
669
|
+
// ////以句号或引号进行分段,不要随意截取
|
|
670
|
+
// for (let i = start + len; i >= start; i--) {
|
|
671
|
+
// if (/[。”"??]/.test(content[i] + '')) {
|
|
672
|
+
// realLength = i - start + 1;
|
|
673
|
+
// break;
|
|
674
|
+
// }
|
|
675
|
+
// }
|
|
676
|
+
// const subtext = content.substr(start, realLength).replace(/\s+/g, "").replace(/\t|\n|\v|\r|\f/g, ' ')
|
|
677
|
+
// if (subtext) message.push(subtext); //message.push({ role: 'user', content: subtext })
|
|
678
|
+
// start += realLength || len;
|
|
679
|
+
// }
|
|
680
|
+
// return message;
|
|
681
|
+
// }
|
|
682
|
+
|
|
683
|
+
// sleep(second: number) {
|
|
684
|
+
// return new Promise(resolve => {
|
|
685
|
+
// setTimeout(() => { resolve(true) }, second * 1000)
|
|
686
|
+
// })
|
|
687
|
+
// }
|
|
704
688
|
|
|
705
689
|
}
|