doomiaichat 2.2.0 → 2.3.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/baiduai.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EmotionResult, SimilarityResult, ChatReponse, SummaryReponse, ExaminationPaperResult, ApiResult, CacheProvider } from "./declare";
1
+ import { EmotionResult, SimilarityResult, ChatReponse, SummaryReponse, ExaminationPaperResult, ApiResult, CacheProvider, CommentResult } from "./declare";
2
2
  import GptBase from "./gptbase";
3
3
  export default class BaiduWenXinAI extends GptBase {
4
4
  protected credential: ApiCredential;
@@ -18,6 +18,7 @@ export default class BaiduWenXinAI extends GptBase {
18
18
  * 请求GPT接口
19
19
  */
20
20
  chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption?: any): Promise<ApiResult>;
21
+ commentQuestionAnswer(_question: string, _answer: string, _axiosOption: any): Promise<CommentResult>;
21
22
  getScentenceEmotional(_s1: string, _axiosOption: any): Promise<EmotionResult>;
22
23
  getScentenseSimilarity(_s1: string, _s2: string, _axiosOption: any): Promise<SimilarityResult>;
23
24
  getSimilarityContent(_content: string, _count: number, _axiosOption: any): Promise<ChatReponse>;
package/dist/baiduai.js CHANGED
@@ -88,6 +88,9 @@ class BaiduWenXinAI extends gptbase_1.default {
88
88
  }
89
89
  });
90
90
  }
91
+ commentQuestionAnswer(_question, _answer, _axiosOption) {
92
+ throw new Error("Method not implemented.");
93
+ }
91
94
  getScentenceEmotional(_s1, _axiosOption) {
92
95
  throw new Error("Method not implemented.");
93
96
  }
package/dist/declare.d.ts CHANGED
@@ -90,6 +90,13 @@ export interface QuestionItem {
90
90
  export interface SimilarityResult extends ApiResult {
91
91
  'value'?: number;
92
92
  }
93
+ /**
94
+ * 调用OpenAI Api的参数约定
95
+ */
96
+ export interface CommentResult extends ApiResult {
97
+ 'score'?: number;
98
+ 'comment'?: string;
99
+ }
93
100
  /**
94
101
  * 调用OpenAI Api的参数约定
95
102
  */
package/dist/gptbase.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from "events";
3
- import { ChatReponse, SummaryReponse, ExaminationPaperResult, EmotionResult, SimilarityResult, ApiResult } from './declare';
3
+ import { ChatReponse, SummaryReponse, ExaminationPaperResult, EmotionResult, SimilarityResult, ApiResult, CommentResult } from './declare';
4
4
  export default abstract class GptBase extends EventEmitter {
5
5
  /**
6
6
  * 构造函数
@@ -13,6 +13,13 @@ export default abstract class GptBase extends EventEmitter {
13
13
  * @param axiosOption
14
14
  */
15
15
  abstract chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption: any): Promise<ApiResult>;
16
+ /**
17
+ * 点评问题回答的评价
18
+ * @param question 问题题干
19
+ * @param answer 回答内容
20
+ * @param axiosOption
21
+ */
22
+ abstract commentQuestionAnswer(question: string, answer: string, axiosOption: any): Promise<CommentResult>;
16
23
  /**
17
24
  * 获取句子的情感
18
25
  * @param s1
package/dist/openai.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { OpenAIApi, ChatCompletionRequestMessage } from "openai";
2
2
  import GptBase from "./gptbase";
3
- import { OpenAIApiParameters, ChatReponse, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem } from './declare';
3
+ import { OpenAIApiParameters, ChatReponse, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem, CommentResult } from './declare';
4
4
  export default class OpenAIGpt extends GptBase {
5
5
  protected readonly apiKey: string;
6
6
  private aiApi;
@@ -22,6 +22,13 @@ export default class OpenAIGpt extends GptBase {
22
22
  * @param {*} chatText
23
23
  */
24
24
  chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption?: any): Promise<ChatReponse>;
25
+ /**
26
+ * 点评问题回答的评价
27
+ * @param question
28
+ * @param answer
29
+ * @param axiosOption
30
+ */
31
+ commentQuestionAnswer(question: string, answer: string, axiosOption?: any): Promise<CommentResult>;
25
32
  /**
26
33
  * 判断一句话的表达情绪
27
34
  * @param {*} s1
@@ -85,6 +92,12 @@ export default class OpenAIGpt extends GptBase {
85
92
  *
86
93
  */
87
94
  protected pickUpQuestions(result: Array<any>, count: number, questiontype: string, score?: number): Array<QuestionItem>;
95
+ /**
96
+ * 验证JSON字符串是否是真正可转换为JSON的合法格式
97
+ * 这里只能做一个最简单的处理,就是用两端的符号
98
+ * @param jsonstr
99
+ */
100
+ protected fixedJsonString(jsonstr: string): any[];
88
101
  /**
89
102
  * 将一段很长的文本,按1024长度来划分到多个中
90
103
  * @param {*} content
package/dist/openai.js CHANGED
@@ -75,6 +75,40 @@ class OpenAIGpt extends gptbase_1.default {
75
75
  }
76
76
  });
77
77
  }
78
+ /**
79
+ * 点评问题回答的评价
80
+ * @param question
81
+ * @param answer
82
+ * @param axiosOption
83
+ */
84
+ commentQuestionAnswer(question, answer, axiosOption = { timeout: 30000 }) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ if (!question || !answer)
87
+ return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } };
88
+ let message = [
89
+ { role: 'system', content: '你是一名专业的培训师。' },
90
+ { role: 'user', content: `问题题干:“${question}”` },
91
+ { role: 'user', content: `回答内容:“${answer}”` },
92
+ { role: 'user', content: `请根据以上的回答内容进行点评,给出一段不超过200字的评语,以及0-100的得分。最终结果按照{"comment":"评语","score":80}的JSON结构输出` }
93
+ ];
94
+ const result = yield this.chatRequest(message, {}, axiosOption);
95
+ if (result.successed && result.message) {
96
+ let value = result.message[0].message.content.trim();
97
+ let replyJson = this.fixedJsonString(value);
98
+ ///能够提取到内容
99
+ if (replyJson.length)
100
+ return Object.assign({ successed: true }, replyJson[0]);
101
+ ///回答的内容非JSON格式,自己来提取算了
102
+ console.log('自己组装');
103
+ let matched = value.match(/\d+分/g), score = 0;
104
+ if (matched && matched.length) {
105
+ score = Number(matched[0].replace('分', ''));
106
+ }
107
+ return { successed: true, comment: value, score };
108
+ }
109
+ return { successed: false };
110
+ });
111
+ }
78
112
  /**
79
113
  * 判断一句话的表达情绪
80
114
  * @param {*} s1
@@ -259,16 +293,18 @@ class OpenAIGpt extends gptbase_1.default {
259
293
  */
260
294
  pickUpFaqContent(messages) {
261
295
  let answerString = messages[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
262
- const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
263
- const lastsybmol = answerString.lastIndexOf("]");
264
- console.log('answerString', answerString);
265
- if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol)
296
+ // const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
297
+ // const lastsybmol = answerString.lastIndexOf("]");
298
+ // console.log('answerString', answerString)
299
+ // if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
300
+ // answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
301
+ // console.log('answerString', answerString)
302
+ let jsonObj = this.fixedJsonString(answerString);
303
+ if (!jsonObj.length)
266
304
  return [];
267
- answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
268
- console.log('answerString', answerString);
269
305
  try {
270
306
  //let jsonObj = JSON.parse(answerString);
271
- let jsonObj = eval(answerString);
307
+ //let jsonObj = eval(answerString);
272
308
  jsonObj.map((item) => {
273
309
  let realKeyword = [];
274
310
  let keywords = (item.keywords + '').split(',');
@@ -368,29 +404,32 @@ class OpenAIGpt extends gptbase_1.default {
368
404
  */
369
405
  pickUpQuestions(result, count, questiontype, score = 1) {
370
406
  let answerString = result[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
371
- const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
372
- const lastsybmol = answerString.lastIndexOf("]");
373
- console.log('answerString', answerString);
374
- if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol)
407
+ // const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
408
+ // const lastsybmol = answerString.lastIndexOf("]");
409
+ // console.log('answerString', answerString)
410
+ // if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
411
+ // answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
412
+ // console.log('answerString', answerString)
413
+ let jsonObj = this.fixedJsonString(answerString);
414
+ if (!jsonObj.length)
375
415
  return [];
376
- answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
377
- console.log('answerString', answerString);
378
416
  let returnItems = [];
379
417
  try {
380
- let jsonObj = JSON.parse(answerString);
418
+ // let jsonObj = JSON.parse(answerString);
381
419
  returnItems = jsonObj.map((questionitem) => {
382
- console.log('answer item', questionitem);
420
+ console.log('answer item from jsonObj', questionitem);
383
421
  if (questionitem.choice && Array.isArray(questionitem.choice) && questiontype != 'completion') {
384
422
  questionitem.fullanswer = (questionitem.answer + '').replace(/,|[^ABCDE]/g, '');
385
423
  questionitem.score = score;
386
424
  if (questionitem.choice) {
387
425
  questionitem.choice = questionitem.choice.map((item, index) => {
388
- let seqNo = String.fromCharCode(65 + index);
426
+ let seqNo = 'ABCDEFG'[index]; //String.fromCharCode(65 + index);
389
427
  let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig');
428
+ // console.log('itemitemitem', item)
390
429
  //let answer = jsonObj.fullanswer
391
430
  return {
392
431
  id: seqNo,
393
- content: item.replace(correctReg, '').trim(),
432
+ content: (item + '').replace(correctReg, '').trim(),
394
433
  iscorrect: (questionitem.fullanswer || '').indexOf(seqNo) >= 0 ? 1 : 0
395
434
  //|| jsonObj.fullanswer.indexOf(m))
396
435
  };
@@ -415,7 +454,7 @@ class OpenAIGpt extends gptbase_1.default {
415
454
  }
416
455
  ///单选题验证
417
456
  if (questiontype == 'singlechoice') {
418
- let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1; }) : [];
457
+ let rightAnswer = questionitem.choice ? questionitem.choice.filter((item) => { return item.iscorrect === 1; }) : [];
419
458
  ///单选题的正确选项大于了1个
420
459
  if (rightAnswer.length != 1 || !questionitem.answer || questionitem.answer.length !== 1)
421
460
  return null;
@@ -425,7 +464,7 @@ class OpenAIGpt extends gptbase_1.default {
425
464
  }
426
465
  ///多选题验证
427
466
  if (questiontype == 'multiplechoice') {
428
- let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1; }) : [];
467
+ let rightAnswer = questionitem.choice ? questionitem.choice.filter((item) => { return item.iscorrect === 1; }) : [];
429
468
  ///单选题的正确选项大于了1个
430
469
  if (rightAnswer.length === 0 || !questionitem.answer || questionitem.answer.length === 0)
431
470
  return null;
@@ -438,6 +477,55 @@ class OpenAIGpt extends gptbase_1.default {
438
477
  }
439
478
  return returnItems.filter(i => { return i != null; }).slice(0, count);
440
479
  }
480
+ /**
481
+ * 验证JSON字符串是否是真正可转换为JSON的合法格式
482
+ * 这里只能做一个最简单的处理,就是用两端的符号
483
+ * @param jsonstr
484
+ */
485
+ fixedJsonString(jsonstr) {
486
+ console.log('original json string:', jsonstr);
487
+ ///检查返回的是不是一个数组对象(我们需要的是数组对象)
488
+ let firstBracketSymbol = jsonstr.indexOf("["); ////必须过滤出来数组
489
+ let lastBracketSymbol = jsonstr.lastIndexOf("]");
490
+ ///第一个花括号出现的位置,如果花括号出现的位置早于 [ ,则默认返回的对象不是一个数组,仅仅是一个对象,
491
+ ///则需要我们用中括号包住
492
+ let firstBraceSymbol = jsonstr.indexOf("{");
493
+ let lastBraceSymbol = jsonstr.lastIndexOf("}");
494
+ ///返回的不是一个数组结构的,只是一个{},我们帮他完成数组拼接
495
+ if (firstBraceSymbol >= 0 &&
496
+ firstBraceSymbol < (firstBracketSymbol >= 0 ? firstBracketSymbol : 1000) &&
497
+ lastBraceSymbol > firstBraceSymbol &&
498
+ lastBraceSymbol >= 0 && lastBraceSymbol > lastBracketSymbol) {
499
+ jsonstr = '[' + jsonstr.substr(firstBraceSymbol, lastBraceSymbol - firstBraceSymbol + 1);
500
+ +']';
501
+ firstBracketSymbol = 0;
502
+ lastBracketSymbol = jsonstr.length - 1;
503
+ }
504
+ else if (firstBracketSymbol < 0 || lastBracketSymbol < 0 || lastBracketSymbol <= firstBracketSymbol) {
505
+ return [];
506
+ }
507
+ jsonstr = jsonstr.substr(firstBracketSymbol, lastBracketSymbol - firstBracketSymbol + 1);
508
+ ///尽量处理一些能够一眼识别出来的JSON错误
509
+ jsonstr = jsonstr.replace(/}{/g, '},{');
510
+ let mutilitems = jsonstr.split('][');
511
+ ///确实存在多个数组拼接在一起,中间没有逗号隔开的了
512
+ let retObject = [];
513
+ for (let str of mutilitems) {
514
+ if (!str.startsWith('['))
515
+ str = '[' + str;
516
+ if (!str.endsWith(']'))
517
+ str = str + ']';
518
+ // console.log('json str', str)
519
+ try {
520
+ let jsonObj = eval(str);
521
+ retObject = retObject.concat(jsonObj);
522
+ }
523
+ catch (err) {
524
+ console.log('json error', str);
525
+ }
526
+ }
527
+ return retObject;
528
+ }
441
529
  /**
442
530
  * 将一段很长的文本,按1024长度来划分到多个中
443
531
  * @param {*} content
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doomiaichat",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Doomisoft OpenAI",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/baiduai.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EmotionResult, SimilarityResult, ChatReponse, SummaryReponse, ExaminationPaperResult, ApiResult, CacheProvider, request } from "./declare";
1
+ import { EmotionResult, SimilarityResult, ChatReponse, SummaryReponse, ExaminationPaperResult, ApiResult, CacheProvider, request, CommentResult } from "./declare";
2
2
  import GptBase from "./gptbase"
3
3
  const TOKEN_CACHE_KEY = "key:_doomisoft:baiduwenxin:"
4
4
  export default class BaiduWenXinAI extends GptBase {
@@ -74,6 +74,9 @@ export default class BaiduWenXinAI extends GptBase {
74
74
  }
75
75
 
76
76
  }
77
+ commentQuestionAnswer(_question: string, _answer: string, _axiosOption: any): Promise<CommentResult>{
78
+ throw new Error("Method not implemented.");
79
+ }
77
80
  getScentenceEmotional(_s1: string, _axiosOption: any): Promise<EmotionResult> {
78
81
  throw new Error("Method not implemented.");
79
82
  }
package/src/declare.ts CHANGED
@@ -98,6 +98,13 @@ export interface SimilarityResult extends ApiResult {
98
98
  'value'?: number; ///相识度的值
99
99
  }
100
100
 
101
+ /**
102
+ * 调用OpenAI Api的参数约定
103
+ */
104
+ export interface CommentResult extends ApiResult {
105
+ 'score'?:number,
106
+ 'comment'?: string; ///评价内容
107
+ }
101
108
  /**
102
109
  * 调用OpenAI Api的参数约定
103
110
  */
package/src/gptbase.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from "events"
2
- import { ChatReponse, SummaryReponse, ExaminationPaperResult, EmotionResult, SimilarityResult, ApiResult } from './declare'
2
+ import { ChatReponse, SummaryReponse, ExaminationPaperResult, EmotionResult, SimilarityResult, ApiResult, CommentResult } from './declare'
3
3
 
4
4
  export default abstract class GptBase extends EventEmitter {
5
5
  /**
@@ -15,6 +15,13 @@ export default abstract class GptBase extends EventEmitter {
15
15
  * @param axiosOption
16
16
  */
17
17
  abstract chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption: any): Promise<ApiResult>;
18
+ /**
19
+ * 点评问题回答的评价
20
+ * @param question 问题题干
21
+ * @param answer 回答内容
22
+ * @param axiosOption
23
+ */
24
+ abstract commentQuestionAnswer(question: string, answer: string, axiosOption: any): Promise<CommentResult>;
18
25
  /**
19
26
  * 获取句子的情感
20
27
  * @param s1
package/src/openai.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "openai"
2
2
  // import { EventEmitter } from "events";
3
3
  import GptBase from "./gptbase"
4
- import { OpenAIApiParameters, ChatReponse, OutlineSummaryItem, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem } from './declare'
4
+ import { OpenAIApiParameters, ChatReponse, OutlineSummaryItem, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem, CommentResult } from './declare'
5
5
  const SECTION_LENGTH = 1600; ///每2400个字符分成一组
6
6
  const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
7
7
  //请将答案放在最后,标记为答案:()
@@ -35,8 +35,8 @@ export default class OpenAIGpt extends GptBase {
35
35
  /**
36
36
  * 初始化OpenAI 的聊天对象Api
37
37
  */
38
- createOpenAI(apiKey:string):OpenAIApi {
39
- return new OpenAIApi(new Configuration({ apiKey }))
38
+ createOpenAI(apiKey: string): OpenAIApi {
39
+ return new OpenAIApi(new Configuration({ apiKey }))
40
40
  }
41
41
  /**
42
42
  * 向OpenAI发送一个聊天请求
@@ -44,22 +44,22 @@ export default class OpenAIGpt extends GptBase {
44
44
  */
45
45
  public async chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
46
46
  if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
47
- if (!this.aiApi){
47
+ if (!this.aiApi) {
48
48
  this.aiApi = this.createOpenAI(this.apiKey);
49
49
  //return { successed: false, error: { errcode: 1, errmsg: '聊天机器人无效' } };
50
- }
50
+ }
51
51
 
52
52
  let message: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
53
53
  [{ role: 'user', content: chatText }] : chatText;
54
54
  // console.log('message', message)
55
55
  try {
56
- const response= await this.aiApi.createChatCompletion({
57
- model: callChatOption?.model || this.chatModel,
58
- messages: message,
59
- temperature: Number(callChatOption?.temperature || this.temperature),
60
- max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
61
- n: Number(callChatOption?.replyCounts || 1) || 1
62
- }, axiosOption);
56
+ const response = await this.aiApi.createChatCompletion({
57
+ model: callChatOption?.model || this.chatModel,
58
+ messages: message,
59
+ temperature: Number(callChatOption?.temperature || this.temperature),
60
+ max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
61
+ n: Number(callChatOption?.replyCounts || 1) || 1
62
+ }, axiosOption);
63
63
  return { successed: true, message: response.data.choices };
64
64
  } catch (error) {
65
65
  console.log('result is error ', error)
@@ -68,7 +68,36 @@ export default class OpenAIGpt extends GptBase {
68
68
 
69
69
  }
70
70
 
71
-
71
+ /**
72
+ * 点评问题回答的评价
73
+ * @param question
74
+ * @param answer
75
+ * @param axiosOption
76
+ */
77
+ async commentQuestionAnswer(question: string, answer: string, axiosOption: any = { timeout: 30000 }): Promise<CommentResult>{
78
+ if (!question || !answer) return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } }
79
+ let message = [
80
+ {role:'system',content:'你是一名专业的培训师。'},
81
+ { role: 'user', content: `问题题干:“${question}”`},
82
+ { role: 'user', content: `回答内容:“${answer}”` },
83
+ { role: 'user', content: `请根据以上的回答内容进行点评,给出一段不超过200字的评语,以及0-100的得分。最终结果按照{"comment":"评语","score":80}的JSON结构输出` }
84
+ ]
85
+ const result = await this.chatRequest(message, {}, axiosOption);
86
+ if (result.successed && result.message) {
87
+ let value = result.message[0].message.content.trim();
88
+ let replyJson = this.fixedJsonString(value);
89
+ ///能够提取到内容
90
+ if (replyJson.length)return { successed: true,...replyJson[0] }
91
+ ///回答的内容非JSON格式,自己来提取算了
92
+ console.log('自己组装')
93
+ let matched = value.match(/\d+分/g),score=0;
94
+ if (matched && matched.length){
95
+ score =Number(matched[0].replace('分',''));
96
+ }
97
+ return {successed:true,comment:value,score}
98
+ }
99
+ return { successed: false};
100
+ }
72
101
  /**
73
102
  * 判断一句话的表达情绪
74
103
  * @param {*} s1
@@ -241,16 +270,18 @@ export default class OpenAIGpt extends GptBase {
241
270
  */
242
271
  protected pickUpFaqContent(messages: Array<any>): Array<FaqItem> {
243
272
  let answerString = messages[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
244
- const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
245
- const lastsybmol = answerString.lastIndexOf("]");
273
+ // const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
274
+ // const lastsybmol = answerString.lastIndexOf("]");
246
275
 
247
- console.log('answerString', answerString)
248
- if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
249
- answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
250
- console.log('answerString', answerString)
276
+ // console.log('answerString', answerString)
277
+ // if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
278
+ // answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
279
+ // console.log('answerString', answerString)
280
+ let jsonObj = this.fixedJsonString(answerString);
281
+ if (!jsonObj.length) return []
251
282
  try {
252
283
  //let jsonObj = JSON.parse(answerString);
253
- let jsonObj = eval(answerString);
284
+ //let jsonObj = eval(answerString);
254
285
  jsonObj.map((item: FaqItem) => {
255
286
  let realKeyword: string[] = [];
256
287
  let keywords: string[] = (item.keywords + '').split(',');
@@ -349,29 +380,32 @@ export default class OpenAIGpt extends GptBase {
349
380
  */
350
381
  protected pickUpQuestions(result: Array<any>, count: number, questiontype: string, score: number = 1): Array<QuestionItem> {
351
382
  let answerString = result[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
352
- const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
353
- const lastsybmol = answerString.lastIndexOf("]");
383
+ // const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
384
+ // const lastsybmol = answerString.lastIndexOf("]");
354
385
 
355
- console.log('answerString', answerString)
356
- if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
357
- answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
358
- console.log('answerString', answerString)
386
+ // console.log('answerString', answerString)
387
+ // if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol) return [];
388
+ // answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
389
+ // console.log('answerString', answerString)
390
+ let jsonObj = this.fixedJsonString(answerString);
391
+ if (!jsonObj.length) return []
359
392
  let returnItems: QuestionItem[] = [];
360
393
  try {
361
- let jsonObj = JSON.parse(answerString);
362
- returnItems = jsonObj.map((questionitem: QuestionItem) => {
363
- console.log('answer item', questionitem);
394
+ // let jsonObj = JSON.parse(answerString);
395
+ returnItems = jsonObj.map((questionitem: any) => {
396
+ console.log('answer item from jsonObj', questionitem);
364
397
  if (questionitem.choice && Array.isArray(questionitem.choice) && questiontype != 'completion') {
365
398
  questionitem.fullanswer = (questionitem.answer + '').replace(/,|[^ABCDE]/g, '');
366
399
  questionitem.score = score;
367
400
  if (questionitem.choice) {
368
401
  questionitem.choice = questionitem.choice.map((item: string, index: number) => {
369
- let seqNo = String.fromCharCode(65 + index);
402
+ let seqNo = 'ABCDEFG'[index]; //String.fromCharCode(65 + index);
370
403
  let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig')
404
+ // console.log('itemitemitem', item)
371
405
  //let answer = jsonObj.fullanswer
372
406
  return {
373
407
  id: seqNo,
374
- content: item.replace(correctReg, '').trim(),
408
+ content: (item + '').replace(correctReg, '').trim(),
375
409
  iscorrect: (questionitem.fullanswer || '').indexOf(seqNo) >= 0 ? 1 : 0
376
410
  //|| jsonObj.fullanswer.indexOf(m))
377
411
  }
@@ -397,7 +431,7 @@ export default class OpenAIGpt extends GptBase {
397
431
  }
398
432
  ///单选题验证
399
433
  if (questiontype == 'singlechoice') {
400
- let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1 }) : [];
434
+ let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
401
435
  ///单选题的正确选项大于了1个
402
436
  if (rightAnswer.length != 1 || !questionitem.answer || questionitem.answer.length !== 1) return null;
403
437
  ///正确选项和答案不一致
@@ -405,7 +439,7 @@ export default class OpenAIGpt extends GptBase {
405
439
  }
406
440
  ///多选题验证
407
441
  if (questiontype == 'multiplechoice') {
408
- let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1 }) : [];
442
+ let rightAnswer = questionitem.choice ? questionitem.choice.filter((item: { iscorrect: number; }) => { return item.iscorrect === 1 }) : [];
409
443
  ///单选题的正确选项大于了1个
410
444
  if (rightAnswer.length === 0 || !questionitem.answer || questionitem.answer.length === 0) return null;
411
445
  }
@@ -417,6 +451,53 @@ export default class OpenAIGpt extends GptBase {
417
451
  }
418
452
  return returnItems.filter(i => { return i != null; }).slice(0, count);
419
453
  }
454
+ /**
455
+ * 验证JSON字符串是否是真正可转换为JSON的合法格式
456
+ * 这里只能做一个最简单的处理,就是用两端的符号
457
+ * @param jsonstr
458
+ */
459
+ protected fixedJsonString(jsonstr: string): any[] {
460
+ console.log('original json string:', jsonstr)
461
+ ///检查返回的是不是一个数组对象(我们需要的是数组对象)
462
+ let firstBracketSymbol = jsonstr.indexOf("["); ////必须过滤出来数组
463
+ let lastBracketSymbol = jsonstr.lastIndexOf("]");
464
+ ///第一个花括号出现的位置,如果花括号出现的位置早于 [ ,则默认返回的对象不是一个数组,仅仅是一个对象,
465
+ ///则需要我们用中括号包住
466
+ let firstBraceSymbol = jsonstr.indexOf("{");
467
+ let lastBraceSymbol = jsonstr.lastIndexOf("}");
468
+ ///返回的不是一个数组结构的,只是一个{},我们帮他完成数组拼接
469
+ if (firstBraceSymbol >= 0 &&
470
+ firstBraceSymbol < (firstBracketSymbol >= 0 ? firstBracketSymbol:1000) &&
471
+ lastBraceSymbol > firstBraceSymbol &&
472
+ lastBraceSymbol >= 0 && lastBraceSymbol > lastBracketSymbol){
473
+
474
+ jsonstr = '[' + jsonstr.substr(firstBraceSymbol, lastBraceSymbol - firstBraceSymbol + 1); +']';
475
+ firstBracketSymbol = 0;
476
+ lastBracketSymbol = jsonstr.length-1;
477
+ }
478
+ else if (firstBracketSymbol < 0 || lastBracketSymbol < 0 || lastBracketSymbol <= firstBracketSymbol){
479
+ return [];
480
+ }
481
+ jsonstr = jsonstr.substr(firstBracketSymbol, lastBracketSymbol - firstBracketSymbol + 1);
482
+ ///尽量处理一些能够一眼识别出来的JSON错误
483
+ jsonstr = jsonstr.replace(/}{/g,'},{');
484
+ let mutilitems = jsonstr.split('][');
485
+ ///确实存在多个数组拼接在一起,中间没有逗号隔开的了
486
+ let retObject:any[] = [];
487
+ for(let str of mutilitems){
488
+ if (!str.startsWith('[')) str = '[' + str;
489
+ if (!str.endsWith(']')) str = str+']';
490
+ // console.log('json str', str)
491
+ try{
492
+ let jsonObj = eval(str);
493
+ retObject = retObject.concat(jsonObj);
494
+ }catch(err){
495
+ console.log('json error', str)
496
+ }
497
+ }
498
+ return retObject;
499
+ }
500
+
420
501
  /**
421
502
  * 将一段很长的文本,按1024长度来划分到多个中
422
503
  * @param {*} content
@@ -439,4 +520,5 @@ export default class OpenAIGpt extends GptBase {
439
520
  }
440
521
  return message;
441
522
  }
523
+
442
524
  }