doomiaichat 2.0.0 → 2.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 +14 -0
- package/dist/azureai.js +73 -0
- package/dist/index.d.ts +1 -179
- package/dist/index.js +24 -506
- package/dist/openai.d.ts +6 -7
- package/dist/openaiprovider.d.ts +22 -0
- package/dist/openaiprovider.js +39 -0
- package/package.json +2 -1
- package/src/azureai.ts +21 -9
- package/src/openai.ts +8 -10
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AzureOpenAIPatameters, ChatReponse, OpenAIApiParameters } from "./declare";
|
|
2
|
+
import OpenAIGpt from "./openai";
|
|
3
|
+
export default class AzureAI extends OpenAIGpt {
|
|
4
|
+
protected readonly azureSetting: AzureOpenAIPatameters;
|
|
5
|
+
constructor(apiKey: string, azureOption: AzureOpenAIPatameters, apiOption?: OpenAIApiParameters);
|
|
6
|
+
/**
|
|
7
|
+
* ZAure OpenAI 最新的URL地址
|
|
8
|
+
*/
|
|
9
|
+
get BaseUrl(): string;
|
|
10
|
+
/**
|
|
11
|
+
* 请求GPT接口
|
|
12
|
+
*/
|
|
13
|
+
chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption?: any): Promise<ChatReponse>;
|
|
14
|
+
}
|
package/dist/azureai.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const axios_1 = __importDefault(require("axios"));
|
|
16
|
+
const openai_1 = __importDefault(require("./openai"));
|
|
17
|
+
class AzureAI extends openai_1.default {
|
|
18
|
+
constructor(apiKey, azureOption, apiOption = {}) {
|
|
19
|
+
super(apiKey, apiOption);
|
|
20
|
+
this.azureSetting = azureOption;
|
|
21
|
+
if (!this.azureSetting.endpoint.toLowerCase().startsWith('https://') &&
|
|
22
|
+
!this.azureSetting.endpoint.toLowerCase().startsWith('https://')) {
|
|
23
|
+
this.azureSetting.endpoint = 'https://' + this.azureSetting.endpoint;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* ZAure OpenAI 最新的URL地址
|
|
28
|
+
*/
|
|
29
|
+
get BaseUrl() {
|
|
30
|
+
return `${this.azureSetting.endpoint}/openai/deployments/${this.azureSetting.engine}/chat/completions?api-version=${this.azureSetting.version || '2023-03-15-preview'}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 请求GPT接口
|
|
34
|
+
*/
|
|
35
|
+
chatRequest(chatText, paramOption, axiosOption = {}) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
if (!chatText)
|
|
38
|
+
return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
39
|
+
if (!axiosOption.headers)
|
|
40
|
+
axiosOption.headers = { 'api-key': this.apiKey, 'Content-Type': 'application/json' };
|
|
41
|
+
else {
|
|
42
|
+
axiosOption.headers['api-key'] = this.apiKey;
|
|
43
|
+
axiosOption.headers['Content-Type'] = 'application/json';
|
|
44
|
+
}
|
|
45
|
+
let messages = typeof (chatText) == 'string' ?
|
|
46
|
+
[{ role: 'user', content: chatText }] : chatText;
|
|
47
|
+
//let axios = new Axios(axiosOption)
|
|
48
|
+
try {
|
|
49
|
+
// const response = await axios.post(this.BaseUrl, {
|
|
50
|
+
// messages,
|
|
51
|
+
// temperature: Number(paramOption?.temperature || this.temperature),
|
|
52
|
+
// max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
53
|
+
// })
|
|
54
|
+
let param = Object.assign(Object.assign({}, axiosOption), { method: "post", data: {
|
|
55
|
+
messages,
|
|
56
|
+
temperature: Number((paramOption === null || paramOption === void 0 ? void 0 : paramOption.temperature) || this.temperature),
|
|
57
|
+
max_tokens: Number((paramOption === null || paramOption === void 0 ? void 0 : paramOption.maxtoken) || this.maxtoken),
|
|
58
|
+
}, url: this.BaseUrl });
|
|
59
|
+
console.log('axiosOption', param);
|
|
60
|
+
const response = yield (0, axios_1.default)(param);
|
|
61
|
+
if (response.data.choices) {
|
|
62
|
+
return { successed: true, message: response.data.choices };
|
|
63
|
+
}
|
|
64
|
+
return Object.assign({ successed: false }, response.data);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.log('result is error ', error);
|
|
68
|
+
return { successed: false, error };
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.default = AzureAI;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,179 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { EventEmitter } from "events";
|
|
3
|
-
import { AxiosRequestConfig } from "axios";
|
|
4
|
-
export declare class AIChat extends EventEmitter {
|
|
5
|
-
private readonly chatRobot;
|
|
6
|
-
private readonly chatModel;
|
|
7
|
-
private readonly maxtoken;
|
|
8
|
-
private readonly temperature;
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
11
|
-
* @param apiKey 调用OpenAI 的key
|
|
12
|
-
* @param apiOption
|
|
13
|
-
*/
|
|
14
|
-
constructor(apiKey: string, apiOption?: CallChatApiOption);
|
|
15
|
-
/**
|
|
16
|
-
* 向OpenAI发送一个聊天请求
|
|
17
|
-
* @param {*} chatText
|
|
18
|
-
*/
|
|
19
|
-
chatRequest(chatText: string | Array<any>, callChatOption: CallChatApiOption, axiosOption?: AxiosRequestConfig): Promise<ChatReponse>;
|
|
20
|
-
/**
|
|
21
|
-
* 判断一句话的表达情绪
|
|
22
|
-
* @param {*} s1
|
|
23
|
-
* @param {*} axiosOption
|
|
24
|
-
*/
|
|
25
|
-
getScentenceEmotional(s1: string, axiosOption?: any): Promise<EmotionResult>;
|
|
26
|
-
/**
|
|
27
|
-
* 获取两句话的相似度取值
|
|
28
|
-
* @param {*} s1
|
|
29
|
-
* @param {*} s2
|
|
30
|
-
*/
|
|
31
|
-
getScentenseSimilarity(s1: string, s2: string, axiosOption?: any): Promise<SimilarityResult>;
|
|
32
|
-
/**
|
|
33
|
-
* 获得一种内容的相似说法
|
|
34
|
-
* 比如:
|
|
35
|
-
* 你今年多大?
|
|
36
|
-
* 相似问法:您是哪一年出生的
|
|
37
|
-
* 您今年贵庚?
|
|
38
|
-
* @param {*} content
|
|
39
|
-
* @param {需要出来的数量} count
|
|
40
|
-
*/
|
|
41
|
-
getSimilarityContent(content: string, count?: number, axiosOption?: AxiosRequestConfig): Promise<ChatReponse>;
|
|
42
|
-
/**
|
|
43
|
-
* 提取内容的中心思想摘要
|
|
44
|
-
* @param content
|
|
45
|
-
* @param axiosOption
|
|
46
|
-
*/
|
|
47
|
-
getSummaryOfContent(content: string | Array<any>, axiosOption?: AxiosRequestConfig): Promise<SummaryReponse>;
|
|
48
|
-
/**
|
|
49
|
-
* 从指定的文本内容中生成相关的问答
|
|
50
|
-
* @param {*} content
|
|
51
|
-
* @param {*} count
|
|
52
|
-
* @param {*} axiosOption
|
|
53
|
-
* @returns
|
|
54
|
-
*/ generateQuestionsFromContent(content: string, count?: number, axiosOption?: AxiosRequestConfig): Promise<ChatReponse>;
|
|
55
|
-
/**
|
|
56
|
-
* 从指定的文本内容中生成相关的问答
|
|
57
|
-
* @param {*} content
|
|
58
|
-
* @param {*} count
|
|
59
|
-
* @param {*} axiosOption
|
|
60
|
-
* @returns
|
|
61
|
-
*/ generateQuestionsFromContent_Orgin(content: string, count?: number, promotion?: string | null, sliceslength?: number, axiosOption?: AxiosRequestConfig): Promise<ChatReponse>;
|
|
62
|
-
/**
|
|
63
|
-
* 解析Faq返回的问题
|
|
64
|
-
* @param {*} messages
|
|
65
|
-
* @returns
|
|
66
|
-
*/
|
|
67
|
-
private pickUpFaqContent;
|
|
68
|
-
/**
|
|
69
|
-
* 从指定的文本内容中生成一张试卷
|
|
70
|
-
* @param {*} content
|
|
71
|
-
* @param {试卷的参数} paperOption
|
|
72
|
-
* totalscore: 试卷总分,默认100
|
|
73
|
-
* section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
74
|
-
* @param {*} axiosOption
|
|
75
|
-
* @returns
|
|
76
|
-
*/ generateExaminationPaperFromContent(content: string, paperOption?: any, axiosOption?: AxiosRequestConfig): Promise<ExaminationPaperResult>;
|
|
77
|
-
/**
|
|
78
|
-
* 从答复中得到题目
|
|
79
|
-
* @param {*} result
|
|
80
|
-
*
|
|
81
|
-
*/
|
|
82
|
-
private pickUpQuestions;
|
|
83
|
-
/**
|
|
84
|
-
* 将一段很长的文本,按1024长度来划分到多个中
|
|
85
|
-
* @param {*} content
|
|
86
|
-
*/
|
|
87
|
-
private splitLongText;
|
|
88
|
-
}
|
|
89
|
-
interface ApiResult {
|
|
90
|
-
/**
|
|
91
|
-
* return the result of api called
|
|
92
|
-
* @type {boolean}
|
|
93
|
-
*/
|
|
94
|
-
'successed': boolean;
|
|
95
|
-
/**
|
|
96
|
-
* The error info
|
|
97
|
-
* @type {any}
|
|
98
|
-
* @memberof ChatReponse
|
|
99
|
-
*/
|
|
100
|
-
'error'?: any;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Api封装后的返回结果
|
|
104
|
-
*/
|
|
105
|
-
export interface ChatReponse extends ApiResult {
|
|
106
|
-
/**
|
|
107
|
-
* The name of the user in a multi-user chat
|
|
108
|
-
* @type {Array<any>}
|
|
109
|
-
* @memberof ChatReponse
|
|
110
|
-
*/
|
|
111
|
-
'message'?: Array<any>;
|
|
112
|
-
}
|
|
113
|
-
interface OutlineSummaryItem {
|
|
114
|
-
/**
|
|
115
|
-
* The name of the user in a multi-user chat
|
|
116
|
-
* @type {Array<any>}
|
|
117
|
-
* @memberof SummaryReponse
|
|
118
|
-
*/
|
|
119
|
-
'outline'?: string;
|
|
120
|
-
'summary'?: Array<string>;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* 摘要信息
|
|
124
|
-
*/
|
|
125
|
-
export interface SummaryReponse extends ApiResult {
|
|
126
|
-
/**
|
|
127
|
-
* The name of the user in a multi-user chat
|
|
128
|
-
* @type {Array<any>}
|
|
129
|
-
* @memberof SummaryReponse
|
|
130
|
-
*/
|
|
131
|
-
'article'?: Array<OutlineSummaryItem>;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* 调用OpenAI Api的参数约定
|
|
135
|
-
*/
|
|
136
|
-
export interface CallChatApiOption {
|
|
137
|
-
'model'?: string;
|
|
138
|
-
'maxtoken'?: number;
|
|
139
|
-
'temperature'?: number;
|
|
140
|
-
'replyCounts'?: number;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* 调用OpenAI Api的参数约定
|
|
144
|
-
*/
|
|
145
|
-
export interface FaqItem {
|
|
146
|
-
'question': string;
|
|
147
|
-
'answer'?: string;
|
|
148
|
-
'keywords'?: Array<string>;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* 调用OpenAI Api的参数约定
|
|
152
|
-
*/
|
|
153
|
-
export interface ExaminationPaperResult extends ApiResult {
|
|
154
|
-
'score': number;
|
|
155
|
-
'paper': any;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* 调用OpenAI Api的参数约定
|
|
159
|
-
*/
|
|
160
|
-
export interface QuestionItem {
|
|
161
|
-
'question': string;
|
|
162
|
-
'fullanswer'?: string;
|
|
163
|
-
'answer'?: Array<string>;
|
|
164
|
-
'choice'?: any[];
|
|
165
|
-
'score'?: number;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* 调用OpenAI Api的参数约定
|
|
169
|
-
*/
|
|
170
|
-
export interface SimilarityResult extends ApiResult {
|
|
171
|
-
'value'?: number;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* 调用OpenAI Api的参数约定
|
|
175
|
-
*/
|
|
176
|
-
export interface EmotionResult extends ApiResult {
|
|
177
|
-
'emotion'?: string;
|
|
178
|
-
}
|
|
179
|
-
export {};
|
|
1
|
+
export * as AIFactory from "./openaiprovider";
|
package/dist/index.js
CHANGED
|
@@ -1,509 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
10
24
|
};
|
|
11
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
13
|
-
|
|
14
|
-
const events_1 = require("events");
|
|
15
|
-
const SECTION_LENGTH = 1600; ///每2400个字符分成一组
|
|
16
|
-
const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
|
|
17
|
-
//请将答案放在最后,标记为答案:()
|
|
18
|
-
const QUESTION_TEXT_MAPPING = {
|
|
19
|
-
singlechoice: '你是一名专业的出题老师,根据以下内容,生成@ITEMCOUNT@道单选题,每道题目4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题一个正确答案,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出',
|
|
20
|
-
multiplechoice: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道多选题,提供4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题的答案至少有两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":[],"answer":[]}]的结构输出',
|
|
21
|
-
trueorfalse: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道判断题,每道题正确和错误两个选项,输出结果必须是JSON数组并按照[{"question":"","choice":["A.正确","B.错误"],"answer":[]}]的结构输出',
|
|
22
|
-
completion: '你是一名专业的出题老师,根据以下内容,请生成@ITEMCOUNT@道填空题和对应答案,输出结果必须是JSON数组并按照[{"question":"","answer":["填空答案1","填空答案2"]}]的结构输出' //请将答案放在最后,标记为答案:()
|
|
23
|
-
};
|
|
24
|
-
// singlechoice: '你是一名专业的培训老师,根据以下内容,生成@ITEMCOUNT@道单选题,每道题目4个选项,每道题的选项中的元素用大写字母ABCD开头,每道题的只能有一个正确答案,最终结果按照[{"question":"","choice":[],"answer":[]}]的JSON数组输出',
|
|
25
|
-
// multiplechoice: '你是一名专业的培训老师,根据以下内容,请生成@ITEMCOUNT@道多选题,提供4个选项,答案至少1个以上选项,请按照{"question":"","choice":[],"answer":[]}的JSON结构输出,choice中的元素用大写字母ABCD开头,answer数组中包含正确答案选项', //请将答案放在最后,标记为答案:()
|
|
26
|
-
// trueorfalse: '你是一名专业的培训老师,根据以下内容,请生成@ITEMCOUNT@道判断题,请按照{"question":"","choice":["A.正确","B.错误"],"answer":[]}的JSON结构输出,answer数组中包含一个元素,"正确"或"错误"', //标记为答案:(正确或错误)
|
|
27
|
-
// completion: '你是一名专业的培训老师,根据以下内容,请生成@ITEMCOUNT@道填空题,每道题目1个填空,请按照{"question":"","answer":[]}的JSON结构输出,answer数组中包含填空答案' //请将答案放在最后,标记为答案:()
|
|
28
|
-
const QUESTION_TYPE = ['singlechoice', 'multiplechoice', 'trueorfalse', 'completion'];
|
|
29
|
-
class AIChat extends events_1.EventEmitter {
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
32
|
-
* @param apiKey 调用OpenAI 的key
|
|
33
|
-
* @param apiOption
|
|
34
|
-
*/
|
|
35
|
-
constructor(apiKey, apiOption = {}) {
|
|
36
|
-
super();
|
|
37
|
-
this.chatRobot = new openai_1.OpenAIApi(new openai_1.Configuration({ apiKey }));
|
|
38
|
-
this.chatModel = apiOption.model || 'gpt-3.5-turbo';
|
|
39
|
-
this.maxtoken = apiOption.maxtoken || 2048;
|
|
40
|
-
this.temperature = apiOption.temperature || 0.9;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* 向OpenAI发送一个聊天请求
|
|
44
|
-
* @param {*} chatText
|
|
45
|
-
*/
|
|
46
|
-
chatRequest(chatText, callChatOption, axiosOption = {}) {
|
|
47
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
if (!chatText)
|
|
49
|
-
return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
50
|
-
if (!this.chatRobot)
|
|
51
|
-
return { successed: false, error: { errcode: 1, errmsg: '聊天机器人无效' } };
|
|
52
|
-
let message = typeof (chatText) == 'string' ?
|
|
53
|
-
[{ role: 'user', content: chatText }] : chatText;
|
|
54
|
-
// console.log('message', message)
|
|
55
|
-
try {
|
|
56
|
-
const response = yield this.chatRobot.createChatCompletion({
|
|
57
|
-
model: (callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.model) || this.chatModel,
|
|
58
|
-
messages: message,
|
|
59
|
-
temperature: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.temperature) || this.temperature),
|
|
60
|
-
max_tokens: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.maxtoken) || this.maxtoken),
|
|
61
|
-
n: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.replyCounts) || 1) || 1
|
|
62
|
-
}, axiosOption);
|
|
63
|
-
return { successed: true, message: response.data.choices };
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
console.log('result is error ', error);
|
|
67
|
-
return { successed: false, error };
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* 判断一句话的表达情绪
|
|
73
|
-
* @param {*} s1
|
|
74
|
-
* @param {*} axiosOption
|
|
75
|
-
*/
|
|
76
|
-
getScentenceEmotional(s1, axiosOption = { timeout: 30000 }) {
|
|
77
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
-
if (!s1)
|
|
79
|
-
return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } };
|
|
80
|
-
const emotion = ['愤怒', '威胁', '讽刺', '愧疚', '兴奋', '友好', '消极', '生气', '正常'];
|
|
81
|
-
const messages = [
|
|
82
|
-
{ role: 'user', content: s1 },
|
|
83
|
-
{ role: 'user', content: `请分析上述内容的语言情绪,请从"${emotion.join(',')}"这些情绪中对应一个输出` },
|
|
84
|
-
];
|
|
85
|
-
const result = yield this.chatRequest(messages, {}, axiosOption);
|
|
86
|
-
if (result.successed && result.message) {
|
|
87
|
-
let value = result.message[0].message.content.trim();
|
|
88
|
-
for (const word of emotion) {
|
|
89
|
-
if (value.indexOf(word) >= 0)
|
|
90
|
-
return { successed: true, emotion: word };
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return { successed: true, emotion: '未知' };
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* 获取两句话的相似度取值
|
|
98
|
-
* @param {*} s1
|
|
99
|
-
* @param {*} s2
|
|
100
|
-
*/
|
|
101
|
-
getScentenseSimilarity(s1, s2, axiosOption = { timeout: 30000 }) {
|
|
102
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
if (!s1 || !s2)
|
|
104
|
-
return { successed: false, error: { errcode: 2, errmsg: '缺失参数' } };
|
|
105
|
-
const messages = [
|
|
106
|
-
{ role: 'user', content: s1 },
|
|
107
|
-
{ role: 'user', content: s2 },
|
|
108
|
-
{ role: 'user', content: '请从语义上对比以上两句话的相似度,请仅输出0至100之间的整数对比结果即可' },
|
|
109
|
-
];
|
|
110
|
-
const result = yield this.chatRequest(messages, { maxtoken: 32 }, axiosOption);
|
|
111
|
-
if (result.successed && result.message) {
|
|
112
|
-
let value = result.message[0].message.content.replace(/[^\d]/g, "");
|
|
113
|
-
if (value > 100)
|
|
114
|
-
value = Math.floor(value / 10);
|
|
115
|
-
return { successed: true, value: Number(value) };
|
|
116
|
-
}
|
|
117
|
-
return { successed: false, error: result.error, value: 0 };
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* 获得一种内容的相似说法
|
|
122
|
-
* 比如:
|
|
123
|
-
* 你今年多大?
|
|
124
|
-
* 相似问法:您是哪一年出生的
|
|
125
|
-
* 您今年贵庚?
|
|
126
|
-
* @param {*} content
|
|
127
|
-
* @param {需要出来的数量} count
|
|
128
|
-
*/
|
|
129
|
-
getSimilarityContent(content, count = 1, axiosOption = {}) {
|
|
130
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
-
let chnReg = /([\u4e00-\u9fa5]|[\ufe30-\uffa0])/.test(content); ///检查源话是否含有中文内容
|
|
132
|
-
let engReg = /[a-zA-Z]/.test(content); ///检查源话是否含有英文内容
|
|
133
|
-
///如果源话是全中文,那么结果中不应该出来英文的相似说法,如果源话是全英文,则结果不能出现全中文的说法
|
|
134
|
-
let prefix = (!chnReg && engReg) ? '请用完整的英文表达,' : ((chnReg && !engReg) ? '请用完整的中文表达,' : '');
|
|
135
|
-
const text = `${prefix}生成与下面句子意思相同的内容"${content}"`;
|
|
136
|
-
let result = yield this.chatRequest(text, { replyCounts: count }, axiosOption);
|
|
137
|
-
if (!result.successed || !result.message)
|
|
138
|
-
return result;
|
|
139
|
-
let replys = result.message.map(item => { return item.message.content.trim(); });
|
|
140
|
-
return { successed: true, message: replys };
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* 提取内容的中心思想摘要
|
|
145
|
-
* @param content
|
|
146
|
-
* @param axiosOption
|
|
147
|
-
*/
|
|
148
|
-
getSummaryOfContent(content, axiosOption = {}) {
|
|
149
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
150
|
-
const arrContent = typeof (content) == 'string' ? this.splitLongText(content) : content;
|
|
151
|
-
let summary = [];
|
|
152
|
-
while (arrContent.length > 0) {
|
|
153
|
-
let subarray = arrContent.slice(0, MESSAGE_LENGTH);
|
|
154
|
-
subarray.push({ role: 'user', content: '根据上述内容精简,提炼内容提纲及摘要内容,每项摘要内容尽量精简数据化不超过100字,结果严格按照[{outline:"提纲标题","summary":["摘要内容1","摘要内容2","摘要内容3"]}]的JSON结构输出' });
|
|
155
|
-
let result = yield this.chatRequest(subarray, {}, axiosOption);
|
|
156
|
-
if (result.successed && result.message) {
|
|
157
|
-
try {
|
|
158
|
-
// console.log('result.message[0].content', result.message[0].message.content)
|
|
159
|
-
let jsonObjItems = JSON.parse(result.message[0].message.content);
|
|
160
|
-
if (Array.isArray(jsonObjItems))
|
|
161
|
-
summary = summary.concat(jsonObjItems);
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
console.log('result.message[0].content', error);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
////删除已经处理的文本
|
|
168
|
-
arrContent.splice(0, MESSAGE_LENGTH);
|
|
169
|
-
}
|
|
170
|
-
return { successed: true, article: summary };
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* 从指定的文本内容中生成相关的问答
|
|
175
|
-
* @param {*} content
|
|
176
|
-
* @param {*} count
|
|
177
|
-
* @param {*} axiosOption
|
|
178
|
-
* @returns
|
|
179
|
-
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
180
|
-
generateQuestionsFromContent(content, count = 1, axiosOption = {}) {
|
|
181
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
-
let arrContent = this.splitLongText(content, 300);
|
|
183
|
-
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
184
|
-
///每一句话需要产生的题目
|
|
185
|
-
let questions4EverySentense = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
186
|
-
let faqs = [], gotted = 0;
|
|
187
|
-
while (arrContent.length > 0 && gotted < count) {
|
|
188
|
-
questions4EverySentense = (count - gotted) / arrContent.length;
|
|
189
|
-
////每次最多送MESSAGE_LENGTH句话给openai
|
|
190
|
-
let subarray = arrContent.slice(0, 4);
|
|
191
|
-
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
192
|
-
//subarray.push({ role: 'user', content:'请根据上述内容,给出一道提问与答案以及答案关键词,按照先问题内容,再标准答案,再关键词的顺序输出,关键词之间用、分开'})
|
|
193
|
-
subarray.unshift({ role: 'system', content: `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` });
|
|
194
|
-
//subarray.unshift({ role: 'system', content: `你是一位专业程序开发工程师,根据以下内容,按照[{"question":"问题内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]JSON数组结构,给出${itemCount}条提问问题及答案以及答案关键词` })
|
|
195
|
-
console.log('subarray', subarray);
|
|
196
|
-
let result = yield this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
197
|
-
if (result.successed && result.message) {
|
|
198
|
-
// console.log('result is ', result.message[0].message.content)
|
|
199
|
-
let msgs = this.pickUpFaqContent(result.message);
|
|
200
|
-
if (msgs.length) {
|
|
201
|
-
///对外发送检出问答题的信号
|
|
202
|
-
this.emit('parseout', { type: 'qa', items: msgs });
|
|
203
|
-
gotted += msgs.length; //result.message.length;
|
|
204
|
-
// console.log('gotted=', gotted)
|
|
205
|
-
faqs = faqs.concat(msgs);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
////删除已经处理的文本
|
|
209
|
-
arrContent.splice(0, 4);
|
|
210
|
-
}
|
|
211
|
-
arrContent = []; /// 释放内存
|
|
212
|
-
///发出信号,解析完毕
|
|
213
|
-
this.emit('parseover', { type: 'qa', items: faqs });
|
|
214
|
-
return { successed: true, message: faqs };
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* 从指定的文本内容中生成相关的问答
|
|
219
|
-
* @param {*} content
|
|
220
|
-
* @param {*} count
|
|
221
|
-
* @param {*} axiosOption
|
|
222
|
-
* @returns
|
|
223
|
-
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
224
|
-
generateQuestionsFromContent_Orgin(content, count = 1, promotion = null, sliceslength = SECTION_LENGTH, axiosOption = {}) {
|
|
225
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
226
|
-
let arrContent = this.splitLongText(content, sliceslength || 300);
|
|
227
|
-
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
228
|
-
///每一句话需要产生的题目
|
|
229
|
-
let questions4EverySentense = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
230
|
-
let faqs = [], gotted = 0;
|
|
231
|
-
while (arrContent.length > 0 && gotted < count) {
|
|
232
|
-
questions4EverySentense = (count - gotted) / arrContent.length;
|
|
233
|
-
////每次最多送MESSAGE_LENGTH句话给openai
|
|
234
|
-
let subarray = arrContent.slice(0, 4);
|
|
235
|
-
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
236
|
-
subarray.unshift({ role: 'system', content: promotion || `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` });
|
|
237
|
-
let result = yield this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
238
|
-
if (result.successed && result.message) {
|
|
239
|
-
let answer = result.message.map(i => { return i.message.content.trim().replace(/\t|\n|\v|\r|\f/g, ''); });
|
|
240
|
-
faqs = faqs.concat(answer);
|
|
241
|
-
}
|
|
242
|
-
////删除已经处理的文本
|
|
243
|
-
arrContent.splice(0, 4);
|
|
244
|
-
}
|
|
245
|
-
arrContent = []; /// 释放内存
|
|
246
|
-
return { successed: true, message: faqs };
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* 解析Faq返回的问题
|
|
251
|
-
* @param {*} messages
|
|
252
|
-
* @returns
|
|
253
|
-
*/
|
|
254
|
-
pickUpFaqContent(messages) {
|
|
255
|
-
let answerString = messages[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
256
|
-
const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
|
|
257
|
-
const lastsybmol = answerString.lastIndexOf("]");
|
|
258
|
-
console.log('answerString', answerString);
|
|
259
|
-
if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol)
|
|
260
|
-
return [];
|
|
261
|
-
answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
|
|
262
|
-
console.log('answerString', answerString);
|
|
263
|
-
try {
|
|
264
|
-
//let jsonObj = JSON.parse(answerString);
|
|
265
|
-
let jsonObj = eval(answerString);
|
|
266
|
-
jsonObj.map((item) => {
|
|
267
|
-
let realKeyword = [];
|
|
268
|
-
let keywords = (item.keywords + '').split(',');
|
|
269
|
-
let answer = item.answer || '';
|
|
270
|
-
for (const k of keywords) {
|
|
271
|
-
if (k && answer.indexOf(k) >= 0)
|
|
272
|
-
realKeyword.push(k);
|
|
273
|
-
}
|
|
274
|
-
item.keywords = realKeyword;
|
|
275
|
-
return item;
|
|
276
|
-
});
|
|
277
|
-
return jsonObj;
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
console.log('JSON error', err);
|
|
281
|
-
return [];
|
|
282
|
-
}
|
|
283
|
-
// let replys = messages.map(item => {
|
|
284
|
-
// let content = item.message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
285
|
-
// try {
|
|
286
|
-
// let jsonObj = JSON.parse(content);
|
|
287
|
-
// if (!Array.isArray(jsonObj.keywords)) {
|
|
288
|
-
// jsonObj.keywords = (jsonObj.keywords || '').split(',')
|
|
289
|
-
// }
|
|
290
|
-
// return jsonObj ;
|
|
291
|
-
// } catch (err) {
|
|
292
|
-
// console.log('JSON error', content, err)
|
|
293
|
-
// return {question:null};
|
|
294
|
-
// }
|
|
295
|
-
// })
|
|
296
|
-
// return replys.filter(n => { return n.question != null });
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* 从指定的文本内容中生成一张试卷
|
|
300
|
-
* @param {*} content
|
|
301
|
-
* @param {试卷的参数} paperOption
|
|
302
|
-
* totalscore: 试卷总分,默认100
|
|
303
|
-
* section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
304
|
-
* @param {*} axiosOption
|
|
305
|
-
* @returns
|
|
306
|
-
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
307
|
-
generateExaminationPaperFromContent(content, paperOption = {}, axiosOption = {}) {
|
|
308
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
309
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
-
let arrContent = this.splitLongText(content, 1024);
|
|
311
|
-
let sectionCount = {
|
|
312
|
-
singlechoice: (((_a = paperOption.singlechoice) === null || _a === void 0 ? void 0 : _a.count) || 0) / arrContent.length,
|
|
313
|
-
multiplechoice: (((_b = paperOption.multiplechoice) === null || _b === void 0 ? void 0 : _b.count) || 0) / arrContent.length,
|
|
314
|
-
trueorfalse: (((_c = paperOption.trueorfalse) === null || _c === void 0 ? void 0 : _c.count) || 0) / arrContent.length,
|
|
315
|
-
completion: (((_d = paperOption.completion) === null || _d === void 0 ? void 0 : _d.count) || 0) / arrContent.length
|
|
316
|
-
};
|
|
317
|
-
///剩余待生成的题目数量
|
|
318
|
-
let remainCount = {
|
|
319
|
-
singlechoice: ((_e = paperOption.singlechoice) === null || _e === void 0 ? void 0 : _e.count) || 0,
|
|
320
|
-
multiplechoice: ((_f = paperOption.multiplechoice) === null || _f === void 0 ? void 0 : _f.count) || 0,
|
|
321
|
-
trueorfalse: ((_g = paperOption.trueorfalse) === null || _g === void 0 ? void 0 : _g.count) || 0,
|
|
322
|
-
completion: ((_h = paperOption.completion) === null || _h === void 0 ? void 0 : _h.count) || 0
|
|
323
|
-
};
|
|
324
|
-
///每种类型的题目的分数
|
|
325
|
-
let ITEM_SCORE = {
|
|
326
|
-
singlechoice: ((_j = paperOption.singlechoice) === null || _j === void 0 ? void 0 : _j.score) || 0,
|
|
327
|
-
multiplechoice: ((_k = paperOption.multiplechoice) === null || _k === void 0 ? void 0 : _k.score) || 0,
|
|
328
|
-
trueorfalse: ((_l = paperOption.trueorfalse) === null || _l === void 0 ? void 0 : _l.score) || 0,
|
|
329
|
-
completion: ((_m = paperOption.completion) === null || _m === void 0 ? void 0 : _m.score) || 0
|
|
330
|
-
};
|
|
331
|
-
///最后生成出来的结果
|
|
332
|
-
let paperReturned = {
|
|
333
|
-
singlechoice: [], multiplechoice: [], trueorfalse: [], completion: []
|
|
334
|
-
}, noMoreQuestionRetrive = false, totalscore = 0;
|
|
335
|
-
while (arrContent.length > 0 && !noMoreQuestionRetrive) {
|
|
336
|
-
////每次最多送MESSAGE_LENGTH句话给openai
|
|
337
|
-
let subarray = arrContent.slice(0, MESSAGE_LENGTH);
|
|
338
|
-
/**
|
|
339
|
-
* 每种类型的题目进行遍历
|
|
340
|
-
*/
|
|
341
|
-
noMoreQuestionRetrive = true;
|
|
342
|
-
for (const key of QUESTION_TYPE) {
|
|
343
|
-
///还需要抓取题目
|
|
344
|
-
if (remainCount[key] > 0) {
|
|
345
|
-
noMoreQuestionRetrive = false;
|
|
346
|
-
let itemCount = Math.min(remainCount[key], Math.ceil(subarray.length * sectionCount[key]));
|
|
347
|
-
subarray.unshift({ role: 'system', content: QUESTION_TEXT_MAPPING[key].replace('@ITEMCOUNT@', itemCount) });
|
|
348
|
-
console.log(subarray);
|
|
349
|
-
let result = yield this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
350
|
-
if (result.successed && result.message) {
|
|
351
|
-
//console.log('paper result', key, result.message.length)
|
|
352
|
-
let pickedQuestions = this.pickUpQuestions(result.message, itemCount, key, ITEM_SCORE[key]);
|
|
353
|
-
if (pickedQuestions.length) {
|
|
354
|
-
///对外发送检出题目的信号
|
|
355
|
-
this.emit('parseout', { type: 'question', name: key, items: pickedQuestions });
|
|
356
|
-
paperReturned[key] = paperReturned[key].concat(pickedQuestions);
|
|
357
|
-
remainCount[key] = remainCount[key] - pickedQuestions.length;
|
|
358
|
-
totalscore = totalscore + pickedQuestions.length * ITEM_SCORE[key];
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
subarray.splice(0, 1); ///把第一个角色定位的问法删除
|
|
362
|
-
// subarray.splice(subarray.length - 1, 1); ///把第一个角色定位的问法删除
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
////删除已经处理的文本
|
|
366
|
-
arrContent.splice(0, MESSAGE_LENGTH);
|
|
367
|
-
}
|
|
368
|
-
///发出信号,解析完毕
|
|
369
|
-
this.emit('parseover', { type: 'question', items: paperReturned });
|
|
370
|
-
return { successed: true, score: totalscore, paper: paperReturned };
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* 从答复中得到题目
|
|
375
|
-
* @param {*} result
|
|
376
|
-
*
|
|
377
|
-
*/
|
|
378
|
-
pickUpQuestions(result, count, questiontype, score = 1) {
|
|
379
|
-
let answerString = result[0].message.content.trim().replace(/\t|\n|\v|\r|\f/g, '');
|
|
380
|
-
const firstsybmol = answerString.indexOf("["); ////必须过滤出来数组
|
|
381
|
-
const lastsybmol = answerString.lastIndexOf("]");
|
|
382
|
-
console.log('answerString', answerString);
|
|
383
|
-
if (firstsybmol < 0 || lastsybmol < 0 || lastsybmol <= firstsybmol)
|
|
384
|
-
return [];
|
|
385
|
-
answerString = answerString.substr(firstsybmol, lastsybmol - firstsybmol + 1);
|
|
386
|
-
console.log('answerString', answerString);
|
|
387
|
-
let returnItems = [];
|
|
388
|
-
try {
|
|
389
|
-
let jsonObj = JSON.parse(answerString);
|
|
390
|
-
returnItems = jsonObj.map((questionitem) => {
|
|
391
|
-
console.log('answer item', questionitem);
|
|
392
|
-
if (questionitem.choice && Array.isArray(questionitem.choice) && questiontype != 'completion') {
|
|
393
|
-
questionitem.fullanswer = (questionitem.answer + '').replace(/,|[^ABCDE]/g, '');
|
|
394
|
-
questionitem.score = score;
|
|
395
|
-
if (questionitem.choice) {
|
|
396
|
-
questionitem.choice = questionitem.choice.map((item, index) => {
|
|
397
|
-
let seqNo = String.fromCharCode(65 + index);
|
|
398
|
-
let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig');
|
|
399
|
-
//let answer = jsonObj.fullanswer
|
|
400
|
-
return {
|
|
401
|
-
id: seqNo,
|
|
402
|
-
content: item.replace(correctReg, '').trim(),
|
|
403
|
-
iscorrect: (questionitem.fullanswer || '').indexOf(seqNo) >= 0 ? 1 : 0
|
|
404
|
-
//|| jsonObj.fullanswer.indexOf(m))
|
|
405
|
-
};
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
///如果是非判断题,题目的选项数量小于2 ,则无效
|
|
409
|
-
///如果是判断题,题目的选项必须=2
|
|
410
|
-
if (!questionitem.choice || (questiontype != 'trueorfalse' && questionitem.choice.length < 3) || (questiontype == 'trueorfalse' && questionitem.choice.length != 2)) {
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
switch (questiontype) {
|
|
415
|
-
case 'singlechoice':
|
|
416
|
-
questionitem.answer = (questionitem.answer + '').replace(/,|[^ABCDEFG]/g, '').split('').slice(0, 1);
|
|
417
|
-
break;
|
|
418
|
-
case 'multiplechoice':
|
|
419
|
-
questionitem.answer = (questionitem.answer + '').replace(/,|[^ABCDEFG]/g, '').split('');
|
|
420
|
-
break;
|
|
421
|
-
case 'trueorfalse':
|
|
422
|
-
questionitem.answer = [(questionitem.answer + '').indexOf('正确') >= 0 ? 'A' : 'B'];
|
|
423
|
-
break;
|
|
424
|
-
}
|
|
425
|
-
///单选题验证
|
|
426
|
-
if (questiontype == 'singlechoice') {
|
|
427
|
-
let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1; }) : [];
|
|
428
|
-
///单选题的正确选项大于了1个
|
|
429
|
-
if (rightAnswer.length != 1 || !questionitem.answer || questionitem.answer.length !== 1)
|
|
430
|
-
return null;
|
|
431
|
-
///正确选项和答案不一致
|
|
432
|
-
if (rightAnswer[0].id.toUpperCase() != (questionitem.answer[0] || '').toUpperCase())
|
|
433
|
-
return null;
|
|
434
|
-
}
|
|
435
|
-
///多选题验证
|
|
436
|
-
if (questiontype == 'multiplechoice') {
|
|
437
|
-
let rightAnswer = questionitem.choice ? questionitem.choice.filter(item => { return item.iscorrect === 1; }) : [];
|
|
438
|
-
///单选题的正确选项大于了1个
|
|
439
|
-
if (rightAnswer.length === 0 || !questionitem.answer || questionitem.answer.length === 0)
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
442
|
-
return questionitem;
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
catch (err) {
|
|
446
|
-
console.log('error happened:', err);
|
|
447
|
-
}
|
|
448
|
-
return returnItems.filter(i => { return i != null; }).slice(0, count);
|
|
449
|
-
// let item = result.map(m => {
|
|
450
|
-
// ////防止输出的JSON格式不合法
|
|
451
|
-
// try {
|
|
452
|
-
// let jsonObj = JSON.parse(m.message.content)
|
|
453
|
-
// jsonObj.score = score;
|
|
454
|
-
// if (jsonObj.choice && Array.isArray(jsonObj.choice) && questiontype != 'completion') {
|
|
455
|
-
// jsonObj.fullanswer = (jsonObj.answer + '').replace(/,|[^ABCDE]/g, '');
|
|
456
|
-
// jsonObj.choice = jsonObj.choice.map((item:string, index:number) => {
|
|
457
|
-
// let seqNo = String.fromCharCode(65 + index);
|
|
458
|
-
// let correctReg = new RegExp(`${seqNo}.|${seqNo}`, 'ig')
|
|
459
|
-
// //let answer = jsonObj.fullanswer
|
|
460
|
-
// return {
|
|
461
|
-
// id: seqNo,
|
|
462
|
-
// content: item.replace(correctReg, '').trim(),
|
|
463
|
-
// iscorrect: (jsonObj.fullanswer.indexOf(seqNo) >= 0 || jsonObj.fullanswer.indexOf(m)) >= 0 ? 1 : 0
|
|
464
|
-
// }
|
|
465
|
-
// })
|
|
466
|
-
// }
|
|
467
|
-
// switch (questiontype) {
|
|
468
|
-
// case 'singlechoice':
|
|
469
|
-
// jsonObj.answer = (jsonObj.answer + '').replace(/,|[^ABCDEFG]/g, '').split('').slice(0, 1);
|
|
470
|
-
// break;
|
|
471
|
-
// case 'multiplechoice':
|
|
472
|
-
// jsonObj.answer = (jsonObj.answer + '').replace(/,|[^ABCDEFG]/g, '').split('');
|
|
473
|
-
// break;
|
|
474
|
-
// case 'trueorfalse':
|
|
475
|
-
// jsonObj.answer = [(jsonObj.answer + '').indexOf('正确') >= 0 ? 'A' : 'B']
|
|
476
|
-
// break;
|
|
477
|
-
// }
|
|
478
|
-
// return jsonObj;
|
|
479
|
-
// } catch (err) {
|
|
480
|
-
// console.log('error happened:', err);
|
|
481
|
-
// return null;
|
|
482
|
-
// }
|
|
483
|
-
// })
|
|
484
|
-
// return item.filter(i => { return i != null; });
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* 将一段很长的文本,按1024长度来划分到多个中
|
|
488
|
-
* @param {*} content
|
|
489
|
-
*/
|
|
490
|
-
splitLongText(content, len = SECTION_LENGTH) {
|
|
491
|
-
let start = 0, message = [], length = content.length;
|
|
492
|
-
while (start < length) {
|
|
493
|
-
let realLength = len;
|
|
494
|
-
////以句号或引号进行分段,不要随意截取
|
|
495
|
-
for (let i = start + len; i >= start; i--) {
|
|
496
|
-
if (/[。”"??]/.test(content[i] + '')) {
|
|
497
|
-
realLength = i - start + 1;
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
const subtext = content.substr(start, realLength);
|
|
502
|
-
if (subtext)
|
|
503
|
-
message.push({ role: 'user', content: subtext });
|
|
504
|
-
start += realLength || len;
|
|
505
|
-
}
|
|
506
|
-
return message;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
exports.AIChat = AIChat;
|
|
26
|
+
exports.AIFactory = void 0;
|
|
27
|
+
exports.AIFactory = __importStar(require("./openaiprovider"));
|
package/dist/openai.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { OpenAIApi, ChatCompletionRequestMessage } from "openai";
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
|
-
import { AxiosRequestConfig } from "axios";
|
|
5
4
|
import { OpenAIApiParameters, ChatReponse, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem } from './declare';
|
|
6
5
|
export default class OpenAIGpt extends EventEmitter {
|
|
7
6
|
protected readonly apiKey: string;
|
|
@@ -23,7 +22,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
23
22
|
* 向OpenAI发送一个聊天请求
|
|
24
23
|
* @param {*} chatText
|
|
25
24
|
*/
|
|
26
|
-
chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption?:
|
|
25
|
+
chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption?: any): Promise<ChatReponse>;
|
|
27
26
|
/**
|
|
28
27
|
* 判断一句话的表达情绪
|
|
29
28
|
* @param {*} s1
|
|
@@ -45,27 +44,27 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
45
44
|
* @param {*} content
|
|
46
45
|
* @param {需要出来的数量} count
|
|
47
46
|
*/
|
|
48
|
-
getSimilarityContent(content: string, count?: number, axiosOption?:
|
|
47
|
+
getSimilarityContent(content: string, count?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
49
48
|
/**
|
|
50
49
|
* 提取内容的中心思想摘要
|
|
51
50
|
* @param content
|
|
52
51
|
* @param axiosOption
|
|
53
52
|
*/
|
|
54
|
-
getSummaryOfContent(content: string | Array<any>, axiosOption?:
|
|
53
|
+
getSummaryOfContent(content: string | Array<any>, axiosOption?: any): Promise<SummaryReponse>;
|
|
55
54
|
/**
|
|
56
55
|
* 从指定的文本内容中生成相关的问答
|
|
57
56
|
* @param {*} content
|
|
58
57
|
* @param {*} count
|
|
59
58
|
* @param {*} axiosOption
|
|
60
59
|
* @returns
|
|
61
|
-
*/ generateQuestionsFromContent(content: string, count?: number, axiosOption?:
|
|
60
|
+
*/ generateQuestionsFromContent(content: string, count?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
62
61
|
/**
|
|
63
62
|
* 从指定的文本内容中生成相关的问答
|
|
64
63
|
* @param {*} content
|
|
65
64
|
* @param {*} count
|
|
66
65
|
* @param {*} axiosOption
|
|
67
66
|
* @returns
|
|
68
|
-
*/ generateQuestionsFromContent_Orgin(content: string, count?: number, promotion?: string | null, sliceslength?: number, axiosOption?:
|
|
67
|
+
*/ generateQuestionsFromContent_Orgin(content: string, count?: number, promotion?: string | null, sliceslength?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
69
68
|
/**
|
|
70
69
|
* 解析Faq返回的问题
|
|
71
70
|
* @param {*} messages
|
|
@@ -80,7 +79,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
80
79
|
* section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
81
80
|
* @param {*} axiosOption
|
|
82
81
|
* @returns
|
|
83
|
-
*/ generateExaminationPaperFromContent(content: string, paperOption?: any, axiosOption?:
|
|
82
|
+
*/ generateExaminationPaperFromContent(content: string, paperOption?: any, axiosOption?: any): Promise<ExaminationPaperResult>;
|
|
84
83
|
/**
|
|
85
84
|
* 从答复中得到题目
|
|
86
85
|
* @param {*} result
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 语音转文字服务商工厂
|
|
3
|
+
*/
|
|
4
|
+
import OpenAIGpt from './openai';
|
|
5
|
+
/**
|
|
6
|
+
* OpenAI/NLP 的服务提供商 OpenAI,微软,百度文心(待接入),google(待接入)
|
|
7
|
+
*/
|
|
8
|
+
export declare const AIProviderEnum: {
|
|
9
|
+
readonly OPENAI: "openai";
|
|
10
|
+
readonly MICROSOFT: "microsoft";
|
|
11
|
+
readonly BAIDU: "baidu";
|
|
12
|
+
readonly GOOGLE: "google";
|
|
13
|
+
};
|
|
14
|
+
export type AIProviderEnum = typeof AIProviderEnum[keyof typeof AIProviderEnum];
|
|
15
|
+
/**
|
|
16
|
+
* 根据类型创建不同的TTS引擎对象
|
|
17
|
+
* @param {*} provider
|
|
18
|
+
* @param {*} apikey
|
|
19
|
+
* @param {*} setting
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
export declare function createAIInstance(provider: AIProviderEnum, apikey: string, setting: any): OpenAIGpt | null;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createAIInstance = exports.AIProviderEnum = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* 语音转文字服务商工厂
|
|
9
|
+
*/
|
|
10
|
+
const openai_1 = __importDefault(require("./openai"));
|
|
11
|
+
const azureai_1 = __importDefault(require("./azureai"));
|
|
12
|
+
/**
|
|
13
|
+
* OpenAI/NLP 的服务提供商 OpenAI,微软,百度文心(待接入),google(待接入)
|
|
14
|
+
*/
|
|
15
|
+
exports.AIProviderEnum = {
|
|
16
|
+
OPENAI: 'openai',
|
|
17
|
+
MICROSOFT: 'microsoft',
|
|
18
|
+
BAIDU: 'baidu',
|
|
19
|
+
GOOGLE: 'google'
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 根据类型创建不同的TTS引擎对象
|
|
23
|
+
* @param {*} provider
|
|
24
|
+
* @param {*} apikey
|
|
25
|
+
* @param {*} setting
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
function createAIInstance(provider, apikey, setting) {
|
|
29
|
+
let { model, maxtoken, temperature, endpoint, engine, version } = setting;
|
|
30
|
+
switch (provider) {
|
|
31
|
+
case exports.AIProviderEnum.OPENAI:
|
|
32
|
+
return new openai_1.default(apikey, { model, maxtoken, temperature });
|
|
33
|
+
case exports.AIProviderEnum.MICROSOFT:
|
|
34
|
+
return new azureai_1.default(apikey, { endpoint, engine, version }, { model, maxtoken, temperature });
|
|
35
|
+
default: return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.createAIInstance = createAIInstance;
|
|
39
|
+
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doomiaichat",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Doomisoft OpenAI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"typescript": "^4.9.5"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"axios": "^1.3.4",
|
|
19
20
|
"openai": "^3.2.1"
|
|
20
21
|
}
|
|
21
22
|
}
|
package/src/azureai.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { AzureOpenAIPatameters, ChatReponse, OpenAIApiParameters } from "./declare";
|
|
2
|
-
import
|
|
2
|
+
import axios from 'axios';
|
|
3
3
|
import OpenAIGpt from "./openai"
|
|
4
4
|
import { ChatCompletionRequestMessage } from "openai";
|
|
5
5
|
export default class AzureAI extends OpenAIGpt {
|
|
6
|
-
protected readonly apiKey: string;
|
|
7
6
|
protected readonly azureSetting: AzureOpenAIPatameters;
|
|
8
7
|
constructor(apiKey: string, azureOption:AzureOpenAIPatameters, apiOption: OpenAIApiParameters = {}) {
|
|
9
8
|
super(apiKey, apiOption);
|
|
@@ -22,7 +21,7 @@ export default class AzureAI extends OpenAIGpt {
|
|
|
22
21
|
/**
|
|
23
22
|
* 请求GPT接口
|
|
24
23
|
*/
|
|
25
|
-
public async chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption:
|
|
24
|
+
public override async chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
|
|
26
25
|
if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
27
26
|
if (!axiosOption.headers )
|
|
28
27
|
axiosOption.headers = { 'api-key': this.apiKey,'Content-Type':'application/json'};
|
|
@@ -33,13 +32,26 @@ export default class AzureAI extends OpenAIGpt {
|
|
|
33
32
|
|
|
34
33
|
let messages: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
|
|
35
34
|
[{ role: 'user', content: chatText }] : chatText;
|
|
36
|
-
let axios = new Axios(axiosOption)
|
|
35
|
+
//let axios = new Axios(axiosOption)
|
|
37
36
|
try{
|
|
38
|
-
const response = await axios.post(this.BaseUrl, {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
})
|
|
37
|
+
// const response = await axios.post(this.BaseUrl, {
|
|
38
|
+
// messages,
|
|
39
|
+
// temperature: Number(paramOption?.temperature || this.temperature),
|
|
40
|
+
// max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
41
|
+
// })
|
|
42
|
+
let param = {
|
|
43
|
+
...axiosOption,
|
|
44
|
+
method: "post",
|
|
45
|
+
data: {
|
|
46
|
+
messages,
|
|
47
|
+
temperature: Number(paramOption?.temperature || this.temperature),
|
|
48
|
+
max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
49
|
+
},
|
|
50
|
+
url: this.BaseUrl
|
|
51
|
+
};
|
|
52
|
+
console.log('axiosOption', param)
|
|
53
|
+
|
|
54
|
+
const response = await axios(param)
|
|
43
55
|
if (response.data.choices){
|
|
44
56
|
return { successed: true, message: response.data.choices };
|
|
45
57
|
}
|
package/src/openai.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Configuration, OpenAIApi,
|
|
1
|
+
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "openai"
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
|
-
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
4
3
|
import { OpenAIApiParameters, ChatReponse, OutlineSummaryItem, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem } from './declare'
|
|
5
4
|
const SECTION_LENGTH = 1600; ///每2400个字符分成一组
|
|
6
5
|
const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
|
|
@@ -42,7 +41,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
42
41
|
* 向OpenAI发送一个聊天请求
|
|
43
42
|
* @param {*} chatText
|
|
44
43
|
*/
|
|
45
|
-
public async chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption:
|
|
44
|
+
public async chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
|
|
46
45
|
if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
47
46
|
if (!this.aiApi){
|
|
48
47
|
this.aiApi = this.createOpenAI(this.apiKey);
|
|
@@ -53,8 +52,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
53
52
|
[{ role: 'user', content: chatText }] : chatText;
|
|
54
53
|
// console.log('message', message)
|
|
55
54
|
try {
|
|
56
|
-
const response
|
|
57
|
-
= await this.aiApi.createChatCompletion({
|
|
55
|
+
const response= await this.aiApi.createChatCompletion({
|
|
58
56
|
model: callChatOption?.model || this.chatModel,
|
|
59
57
|
messages: message,
|
|
60
58
|
temperature: Number(callChatOption?.temperature || this.temperature),
|
|
@@ -124,7 +122,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
124
122
|
* @param {*} content
|
|
125
123
|
* @param {需要出来的数量} count
|
|
126
124
|
*/
|
|
127
|
-
async getSimilarityContent(content: string, count: number = 1, axiosOption:
|
|
125
|
+
async getSimilarityContent(content: string, count: number = 1, axiosOption: any = {}): Promise<ChatReponse> {
|
|
128
126
|
let chnReg: boolean = /([\u4e00-\u9fa5]|[\ufe30-\uffa0])/.test(content) ///检查源话是否含有中文内容
|
|
129
127
|
let engReg: boolean = /[a-zA-Z]/.test(content) ///检查源话是否含有英文内容
|
|
130
128
|
///如果源话是全中文,那么结果中不应该出来英文的相似说法,如果源话是全英文,则结果不能出现全中文的说法
|
|
@@ -140,7 +138,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
140
138
|
* @param content
|
|
141
139
|
* @param axiosOption
|
|
142
140
|
*/
|
|
143
|
-
async getSummaryOfContent(content: string | Array<any>, axiosOption:
|
|
141
|
+
async getSummaryOfContent(content: string | Array<any>, axiosOption: any = {}): Promise<SummaryReponse> {
|
|
144
142
|
const arrContent = typeof (content) == 'string' ? this.splitLongText(content) : content;
|
|
145
143
|
let summary: Array<OutlineSummaryItem> = [];
|
|
146
144
|
while (arrContent.length > 0) {
|
|
@@ -168,7 +166,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
168
166
|
* @param {*} axiosOption
|
|
169
167
|
* @returns
|
|
170
168
|
*///并在答案末尾处必须给出答案内容中的关键词
|
|
171
|
-
async generateQuestionsFromContent(content: string, count: number = 1, axiosOption:
|
|
169
|
+
async generateQuestionsFromContent(content: string, count: number = 1, axiosOption: any = {}): Promise<ChatReponse> {
|
|
172
170
|
let arrContent = this.splitLongText(content, 300);
|
|
173
171
|
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
174
172
|
///每一句话需要产生的题目
|
|
@@ -212,7 +210,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
212
210
|
* @param {*} axiosOption
|
|
213
211
|
* @returns
|
|
214
212
|
*///并在答案末尾处必须给出答案内容中的关键词
|
|
215
|
-
async generateQuestionsFromContent_Orgin(content: string, count: number = 1, promotion: string | null = null, sliceslength: number = SECTION_LENGTH, axiosOption:
|
|
213
|
+
async generateQuestionsFromContent_Orgin(content: string, count: number = 1, promotion: string | null = null, sliceslength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ChatReponse> {
|
|
216
214
|
let arrContent = this.splitLongText(content, sliceslength || 300);
|
|
217
215
|
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
218
216
|
///每一句话需要产生的题目
|
|
@@ -278,7 +276,7 @@ export default class OpenAIGpt extends EventEmitter {
|
|
|
278
276
|
* @param {*} axiosOption
|
|
279
277
|
* @returns
|
|
280
278
|
*///并在答案末尾处必须给出答案内容中的关键词
|
|
281
|
-
async generateExaminationPaperFromContent(content: string, paperOption: any = {}, axiosOption:
|
|
279
|
+
async generateExaminationPaperFromContent(content: string, paperOption: any = {}, axiosOption: any = {}): Promise<ExaminationPaperResult> {
|
|
282
280
|
let arrContent = this.splitLongText(content, 1024);
|
|
283
281
|
let sectionCount: any = {
|
|
284
282
|
singlechoice: (paperOption.singlechoice?.count || 0) / arrContent.length,
|