doomiaichat 2.7.0 → 3.0.1
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 +11 -2
- package/dist/azureai.js +66 -35
- package/dist/baiduai.d.ts +1 -0
- package/dist/baiduai.js +3 -0
- package/dist/declare.d.ts +2 -0
- package/dist/gptbase.d.ts +7 -0
- package/dist/gptprovider.js +3 -3
- package/dist/openai.d.ts +12 -11
- package/dist/openai.js +64 -44
- package/package.json +2 -2
- package/src/azureai.ts +75 -46
- package/src/baiduai.ts +5 -0
- package/src/declare.ts +2 -0
- package/src/gptbase.ts +7 -0
- package/src/gptprovider.ts +3 -3
- package/src/openai.ts +62 -43
package/dist/azureai.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { OpenAIApi } from "azure-openai";
|
|
1
2
|
import { AzureOpenAIPatameters, ChatReponse, EmbeddingResult, OpenAIApiParameters } from "./declare";
|
|
2
3
|
import OpenAIGpt from "./openai";
|
|
3
4
|
export default class AzureAI extends OpenAIGpt {
|
|
4
5
|
protected readonly azureSetting: AzureOpenAIPatameters;
|
|
5
6
|
constructor(apiKey: string, azureOption: AzureOpenAIPatameters, apiOption?: OpenAIApiParameters);
|
|
7
|
+
/**
|
|
8
|
+
* 初始化OpenAI 的聊天对象Api
|
|
9
|
+
*/
|
|
10
|
+
createOpenAI(apiKey: string): OpenAIApi;
|
|
6
11
|
/**
|
|
7
12
|
* ZAure OpenAI 最新的URL地址
|
|
8
13
|
*/
|
|
9
|
-
get BaseUrl(): string;
|
|
10
14
|
get EmbeddingUrl(): string;
|
|
11
15
|
/**
|
|
12
16
|
* 获得文字的向量
|
|
@@ -16,7 +20,12 @@ export default class AzureAI extends OpenAIGpt {
|
|
|
16
20
|
/**
|
|
17
21
|
* 请求GPT接口
|
|
18
22
|
*/
|
|
19
|
-
|
|
23
|
+
/**
|
|
24
|
+
* 流式的聊天模式
|
|
25
|
+
* @param chatText
|
|
26
|
+
* @param _paramOption
|
|
27
|
+
* @param axiosOption
|
|
28
|
+
*/
|
|
20
29
|
/**
|
|
21
30
|
* 获得一种内容的相似说法
|
|
22
31
|
* 微软的AI参数中已经没有了n的参数
|
package/dist/azureai.js
CHANGED
|
@@ -12,7 +12,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const azure_openai_1 = require("azure-openai");
|
|
15
16
|
const declare_1 = require("./declare");
|
|
17
|
+
// import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "azure-openai"
|
|
16
18
|
const openai_1 = __importDefault(require("./openai"));
|
|
17
19
|
class AzureAI extends openai_1.default {
|
|
18
20
|
constructor(apiKey, azureOption, apiOption = {}) {
|
|
@@ -24,13 +26,24 @@ class AzureAI extends openai_1.default {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
29
|
+
* 初始化OpenAI 的聊天对象Api
|
|
28
30
|
*/
|
|
29
|
-
|
|
30
|
-
return
|
|
31
|
+
createOpenAI(apiKey) {
|
|
32
|
+
return new azure_openai_1.OpenAIApi(new azure_openai_1.Configuration({ apiKey,
|
|
33
|
+
azure: {
|
|
34
|
+
apiKey,
|
|
35
|
+
endpoint: this.azureSetting.endpoint,
|
|
36
|
+
deploymentName: this.azureSetting.engine
|
|
37
|
+
} }));
|
|
31
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* ZAure OpenAI 最新的URL地址
|
|
41
|
+
*/
|
|
42
|
+
// get BaseUrl(): string {
|
|
43
|
+
// return `${this.azureSetting.endpoint}/openai/deployments/${this.azureSetting.engine}/chat/completions?api-version=${this.azureSetting.version || '2023-03-15-preview'}`
|
|
44
|
+
// }
|
|
32
45
|
get EmbeddingUrl() {
|
|
33
|
-
return `${this.azureSetting.endpoint}/openai/deployments/${this.
|
|
46
|
+
return `${this.azureSetting.endpoint}/openai/deployments/${this.embeddingmodel || 'openai-embedding-ada-002'}/embeddings?api-version=2022-12-01`;
|
|
34
47
|
}
|
|
35
48
|
/**
|
|
36
49
|
* 获得文字的向量
|
|
@@ -64,37 +77,55 @@ class AzureAI extends openai_1.default {
|
|
|
64
77
|
/**
|
|
65
78
|
* 请求GPT接口
|
|
66
79
|
*/
|
|
67
|
-
chatRequest(chatText
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
80
|
+
// public override async chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
|
|
81
|
+
// if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
82
|
+
// // if (!axiosOption.headers)
|
|
83
|
+
// // axiosOption.headers = { 'api-key': this.apiKey, 'Content-Type': 'application/json' };
|
|
84
|
+
// // else {
|
|
85
|
+
// // axiosOption.headers['api-key'] = this.apiKey;
|
|
86
|
+
// // axiosOption.headers['Content-Type'] = 'application/json';
|
|
87
|
+
// // }
|
|
88
|
+
// if (!this.azureApi) {
|
|
89
|
+
// this.azureApi = this.createAzureAI(this.apiKey);
|
|
90
|
+
// }
|
|
91
|
+
// let messages: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
|
|
92
|
+
// [{ role: 'user', content: chatText }] : chatText;
|
|
93
|
+
// try {
|
|
94
|
+
// // let param = {
|
|
95
|
+
// // ...axiosOption,
|
|
96
|
+
// // method: "post",
|
|
97
|
+
// // data: {
|
|
98
|
+
// // messages,
|
|
99
|
+
// // temperature: Number(paramOption?.temperature || this.temperature),
|
|
100
|
+
// // max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
101
|
+
// // },
|
|
102
|
+
// // url: this.BaseUrl
|
|
103
|
+
// // };
|
|
104
|
+
// // // console.log('axiosOption', param)
|
|
105
|
+
// // const response = await request(param)
|
|
106
|
+
// const response: any = await this.azureApi.createChatCompletion({
|
|
107
|
+
// model: this.azureSetting.engine,
|
|
108
|
+
// messages: messages,
|
|
109
|
+
// temperature: Number(paramOption?.temperature || this.temperature),
|
|
110
|
+
// max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
111
|
+
// n: Number(paramOption?.replyCounts || 1) || 1
|
|
112
|
+
// }, axiosOption);
|
|
113
|
+
// console.log('response.data', JSON.stringify(response.data))
|
|
114
|
+
// if (response.data.choices) {
|
|
115
|
+
// return { successed: true, message: response.data.choices, usage: response.data.usage };
|
|
116
|
+
// }
|
|
117
|
+
// return { successed: false, ...response.data };
|
|
118
|
+
// } catch (error) {
|
|
119
|
+
// console.log('result is error ', error)
|
|
120
|
+
// return { successed: false, error };
|
|
121
|
+
// }
|
|
122
|
+
// }
|
|
123
|
+
/**
|
|
124
|
+
* 流式的聊天模式
|
|
125
|
+
* @param chatText
|
|
126
|
+
* @param _paramOption
|
|
127
|
+
* @param axiosOption
|
|
128
|
+
*/
|
|
98
129
|
/**
|
|
99
130
|
* 获得一种内容的相似说法
|
|
100
131
|
* 微软的AI参数中已经没有了n的参数
|
package/dist/baiduai.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export default class BaiduWenXinAI extends GptBase {
|
|
|
23
23
|
* 请求GPT接口
|
|
24
24
|
*/
|
|
25
25
|
chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption?: any): Promise<ApiResult>;
|
|
26
|
+
chatRequestInStream(_chatText: string | any[], _paramOption: any, _axiosOption: any): void;
|
|
26
27
|
commentQuestionAnswer(_question: string, _answer: string, _axiosOption: any): Promise<CommentResult>;
|
|
27
28
|
getScentenceEmotional(_s1: string, _axiosOption: any): Promise<EmotionResult>;
|
|
28
29
|
getScentenseSimilarity(_s1: string, _s2: string, _axiosOption: any): Promise<SimilarityResult>;
|
package/dist/baiduai.js
CHANGED
|
@@ -97,6 +97,9 @@ class BaiduWenXinAI extends gptbase_1.default {
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
|
+
chatRequestInStream(_chatText, _paramOption, _axiosOption) {
|
|
101
|
+
throw new Error("Method not implemented.");
|
|
102
|
+
}
|
|
100
103
|
commentQuestionAnswer(_question, _answer, _axiosOption) {
|
|
101
104
|
throw new Error("Method not implemented.");
|
|
102
105
|
}
|
package/dist/declare.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface ChatReponse extends ApiResult {
|
|
|
21
21
|
* @memberof ChatReponse
|
|
22
22
|
*/
|
|
23
23
|
'message'?: Array<any>;
|
|
24
|
+
'usage'?: any;
|
|
24
25
|
}
|
|
25
26
|
export interface OutlineSummaryItem {
|
|
26
27
|
/**
|
|
@@ -46,6 +47,7 @@ export interface SummaryReponse extends ApiResult {
|
|
|
46
47
|
* 调用OpenAI Api的参数约定
|
|
47
48
|
*/
|
|
48
49
|
export interface OpenAIApiParameters {
|
|
50
|
+
'embedding'?: string;
|
|
49
51
|
'model'?: string;
|
|
50
52
|
'maxtoken'?: number;
|
|
51
53
|
'temperature'?: number;
|
package/dist/gptbase.d.ts
CHANGED
|
@@ -18,6 +18,13 @@ export default abstract class GptBase extends EventEmitter {
|
|
|
18
18
|
* @param axiosOption
|
|
19
19
|
*/
|
|
20
20
|
abstract chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption: any): Promise<ApiResult>;
|
|
21
|
+
/**
|
|
22
|
+
* 流式的聊天模式
|
|
23
|
+
* @param chatText
|
|
24
|
+
* @param _paramOption
|
|
25
|
+
* @param axiosOption
|
|
26
|
+
*/
|
|
27
|
+
abstract chatRequestInStream(chatText: string | Array<any>, _paramOption: any, axiosOption: any): void;
|
|
21
28
|
/**
|
|
22
29
|
* 点评问题回答的评价
|
|
23
30
|
* @param question 问题题干
|
package/dist/gptprovider.js
CHANGED
|
@@ -28,12 +28,12 @@ exports.GptProviderEnum = {
|
|
|
28
28
|
* @returns
|
|
29
29
|
*/
|
|
30
30
|
function createGpt(provider, apikey, setting) {
|
|
31
|
-
let { model, maxtoken, temperature, endpoint, engine, version } = setting || {};
|
|
31
|
+
let { model, maxtoken, temperature, endpoint, engine, version, embedding } = setting || {};
|
|
32
32
|
switch (provider) {
|
|
33
33
|
case exports.GptProviderEnum.OPENAI:
|
|
34
|
-
return new openai_1.default(apikey + '', { model, maxtoken, temperature });
|
|
34
|
+
return new openai_1.default(apikey + '', { model, maxtoken, temperature, embedding });
|
|
35
35
|
case exports.GptProviderEnum.MICROSOFT:
|
|
36
|
-
return new azureai_1.default(apikey + '', { endpoint, engine, version }, { model, maxtoken, temperature });
|
|
36
|
+
return new azureai_1.default(apikey + '', { endpoint, engine, version }, { model, maxtoken, temperature, embedding });
|
|
37
37
|
case exports.GptProviderEnum.BAIDU:
|
|
38
38
|
let cred = typeof (apikey) === 'string' ? { apikey, securitykey: apikey } : apikey;
|
|
39
39
|
return new baiduai_1.default(cred);
|
package/dist/openai.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { OpenAIApi, ChatCompletionRequestMessage } from "openai";
|
|
1
|
+
import { OpenAIApi, ChatCompletionRequestMessage } from "azure-openai";
|
|
2
2
|
import GptBase from "./gptbase";
|
|
3
3
|
import { OpenAIApiParameters, ChatReponse, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem, CommentResult, EmbeddingResult } from './declare';
|
|
4
4
|
export default class OpenAIGpt extends GptBase {
|
|
5
5
|
protected readonly apiKey: string;
|
|
6
|
-
|
|
6
|
+
protected aiApi: OpenAIApi | undefined;
|
|
7
7
|
protected readonly chatModel: string;
|
|
8
8
|
protected readonly maxtoken: number;
|
|
9
9
|
protected readonly temperature: number;
|
|
10
|
+
protected readonly embeddingmodel: string;
|
|
10
11
|
/**
|
|
11
12
|
*
|
|
12
13
|
* @param apiKey 调用OpenAI 的key
|
|
@@ -27,6 +28,13 @@ export default class OpenAIGpt extends GptBase {
|
|
|
27
28
|
* @param {*} chatText
|
|
28
29
|
*/
|
|
29
30
|
chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption?: any): Promise<ChatReponse>;
|
|
31
|
+
/**
|
|
32
|
+
* 流式的聊天模式
|
|
33
|
+
* @param chatText
|
|
34
|
+
* @param _paramOption
|
|
35
|
+
* @param axiosOption
|
|
36
|
+
*/
|
|
37
|
+
chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption: any): Promise<void>;
|
|
30
38
|
/**
|
|
31
39
|
* 点评问题回答的评价
|
|
32
40
|
* @param question
|
|
@@ -68,14 +76,7 @@ export default class OpenAIGpt extends GptBase {
|
|
|
68
76
|
* @param {*} count
|
|
69
77
|
* @param {*} axiosOption
|
|
70
78
|
* @returns
|
|
71
|
-
*/ generateQuestionsFromContent(content: string, count?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
72
|
-
/**
|
|
73
|
-
* 从指定的文本内容中生成相关的问答
|
|
74
|
-
* @param {*} content
|
|
75
|
-
* @param {*} count
|
|
76
|
-
* @param {*} axiosOption
|
|
77
|
-
* @returns
|
|
78
|
-
*/ generateQuestionsFromContent_Orgin(content: string, count?: number, promotion?: string | null, sliceslength?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
79
|
+
*/ generateQuestionsFromContent(content: string, count?: number, everyContentLength?: number, axiosOption?: any): Promise<ChatReponse>;
|
|
79
80
|
/**
|
|
80
81
|
* 解析Faq返回的问题
|
|
81
82
|
* @param {*} messages
|
|
@@ -90,7 +91,7 @@ export default class OpenAIGpt extends GptBase {
|
|
|
90
91
|
* section: {type:[0,1,2,3]为单选、多选、判断、填空题型 count:生成多少道 score:本段分数}
|
|
91
92
|
* @param {*} axiosOption
|
|
92
93
|
* @returns
|
|
93
|
-
*/ generateExaminationPaperFromContent(content: string, paperOption?: any, axiosOption?: any): Promise<ExaminationPaperResult>;
|
|
94
|
+
*/ generateExaminationPaperFromContent(content: string, paperOption?: any, everyContentLength?: number, axiosOption?: any): Promise<ExaminationPaperResult>;
|
|
94
95
|
/**
|
|
95
96
|
* 从答复中得到题目
|
|
96
97
|
* @param {*} result
|
package/dist/openai.js
CHANGED
|
@@ -12,10 +12,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const
|
|
15
|
+
const azure_openai_1 = require("azure-openai");
|
|
16
16
|
// import { EventEmitter } from "events";
|
|
17
17
|
const gptbase_1 = __importDefault(require("./gptbase"));
|
|
18
|
-
const SECTION_LENGTH =
|
|
18
|
+
const SECTION_LENGTH = 1024; ///每2400个字符分成一组
|
|
19
19
|
const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
|
|
20
20
|
//请将答案放在最后,标记为答案:()
|
|
21
21
|
const QUESTION_TEXT_MAPPING = {
|
|
@@ -37,12 +37,13 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
37
37
|
this.chatModel = apiOption.model || 'gpt-3.5-turbo';
|
|
38
38
|
this.maxtoken = apiOption.maxtoken || 2048;
|
|
39
39
|
this.temperature = apiOption.temperature || 0.9;
|
|
40
|
+
this.embeddingmodel = apiOption.embedding || 'text-embedding-ada-002';
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
43
|
* 初始化OpenAI 的聊天对象Api
|
|
43
44
|
*/
|
|
44
45
|
createOpenAI(apiKey) {
|
|
45
|
-
return new
|
|
46
|
+
return new azure_openai_1.OpenAIApi(new azure_openai_1.Configuration({ apiKey }));
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
48
49
|
* 获得文字的向量
|
|
@@ -55,16 +56,15 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
55
56
|
if (!this.aiApi) {
|
|
56
57
|
this.aiApi = this.createOpenAI(this.apiKey);
|
|
57
58
|
}
|
|
58
|
-
// console.log('message', message)
|
|
59
59
|
try {
|
|
60
60
|
const response = yield this.aiApi.createEmbedding({
|
|
61
|
-
model:
|
|
61
|
+
model: this.embeddingmodel,
|
|
62
62
|
input: text,
|
|
63
63
|
}, axiosOption);
|
|
64
64
|
return { successed: true, embedding: response.data.data[0].embedding };
|
|
65
65
|
}
|
|
66
66
|
catch (error) {
|
|
67
|
-
console.log('result is error ', error)
|
|
67
|
+
// console.log('result is error ', error)
|
|
68
68
|
return { successed: false, error };
|
|
69
69
|
}
|
|
70
70
|
});
|
|
@@ -92,7 +92,7 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
92
92
|
max_tokens: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.maxtoken) || this.maxtoken),
|
|
93
93
|
n: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.replyCounts) || 1) || 1
|
|
94
94
|
}, axiosOption);
|
|
95
|
-
return { successed: true, message: response.data.choices };
|
|
95
|
+
return { successed: true, message: response.data.choices, usage: response.data.usage };
|
|
96
96
|
}
|
|
97
97
|
catch (error) {
|
|
98
98
|
console.log('result is error ', error);
|
|
@@ -100,6 +100,58 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* 流式的聊天模式
|
|
105
|
+
* @param chatText
|
|
106
|
+
* @param _paramOption
|
|
107
|
+
* @param axiosOption
|
|
108
|
+
*/
|
|
109
|
+
chatRequestInStream(chatText, callChatOption, axiosOption) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
if (!chatText)
|
|
112
|
+
this.emit('chaterror', { successed: false, error: 'no text in chat' });
|
|
113
|
+
if (!this.aiApi) {
|
|
114
|
+
this.aiApi = this.createOpenAI(this.apiKey);
|
|
115
|
+
}
|
|
116
|
+
let message = typeof (chatText) == 'string' ?
|
|
117
|
+
[{ role: 'user', content: chatText }] : chatText;
|
|
118
|
+
axiosOption = Object.assign({}, axiosOption || { timeout: 60000 }, { responseType: 'stream' });
|
|
119
|
+
try {
|
|
120
|
+
let finishreason = null, usage = null;
|
|
121
|
+
const response = yield this.aiApi.createChatCompletion({
|
|
122
|
+
model: (callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.model) || this.chatModel,
|
|
123
|
+
messages: message,
|
|
124
|
+
stream: true,
|
|
125
|
+
temperature: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.temperature) || this.temperature),
|
|
126
|
+
max_tokens: Number((callChatOption === null || callChatOption === void 0 ? void 0 : callChatOption.maxtoken) || this.maxtoken)
|
|
127
|
+
}, axiosOption);
|
|
128
|
+
response.data.on('data', (data) => {
|
|
129
|
+
const lines = data.toString().split('\n').filter((line) => line.trim() !== '');
|
|
130
|
+
for (const line of lines) {
|
|
131
|
+
const message = line.replace(/^data: /, '');
|
|
132
|
+
if (message === '[DONE]') {
|
|
133
|
+
this.emit('chatdone', { successed: true, finish_reason: finishreason, usage });
|
|
134
|
+
return; // Stream finished
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
///{ delta: { content: '$\\' }, index: 0, finish_reason: null }
|
|
138
|
+
///发送出去
|
|
139
|
+
const parsed = JSON.parse(message);
|
|
140
|
+
finishreason = parsed.choices[0].finish_reason;
|
|
141
|
+
usage = parsed.usage;
|
|
142
|
+
this.emit('chattext', { successed: true, text: parsed.choices[0].delta.content, finish_reason: parsed.choices[0].finish_reason, index: parsed.choices[0].index, usage });
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.emit('chaterror', { successed: false, error: 'JSON parse stream message', message });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
this.emit('error', { successed: false, error: 'call axios faied ' + error });
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
103
155
|
/**
|
|
104
156
|
* 点评问题回答的评价
|
|
105
157
|
* @param question
|
|
@@ -246,9 +298,9 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
246
298
|
* @param {*} axiosOption
|
|
247
299
|
* @returns
|
|
248
300
|
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
249
|
-
generateQuestionsFromContent(content, count = 1, axiosOption = {}) {
|
|
301
|
+
generateQuestionsFromContent(content, count = 1, everyContentLength = SECTION_LENGTH, axiosOption = {}) {
|
|
250
302
|
return __awaiter(this, void 0, void 0, function* () {
|
|
251
|
-
let arrContent = this.splitLongText(content,
|
|
303
|
+
let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
252
304
|
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
253
305
|
///每一句话需要产生的题目
|
|
254
306
|
let questions4EverySentense = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
@@ -256,7 +308,7 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
256
308
|
while (arrContent.length > 0 && gotted < count) {
|
|
257
309
|
questions4EverySentense = (count - gotted) / arrContent.length;
|
|
258
310
|
////每次最多送MESSAGE_LENGTH句话给openai
|
|
259
|
-
let subarray = arrContent.slice(0,
|
|
311
|
+
let subarray = arrContent.slice(0, 1);
|
|
260
312
|
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
261
313
|
//subarray.push({ role: 'user', content:'请根据上述内容,给出一道提问与答案以及答案关键词,按照先问题内容,再标准答案,再关键词的顺序输出,关键词之间用、分开'})
|
|
262
314
|
subarray.unshift({ role: 'system', content: `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` });
|
|
@@ -282,38 +334,6 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
282
334
|
return { successed: true, message: faqs.slice(0, count) };
|
|
283
335
|
});
|
|
284
336
|
}
|
|
285
|
-
/**
|
|
286
|
-
* 从指定的文本内容中生成相关的问答
|
|
287
|
-
* @param {*} content
|
|
288
|
-
* @param {*} count
|
|
289
|
-
* @param {*} axiosOption
|
|
290
|
-
* @returns
|
|
291
|
-
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
292
|
-
generateQuestionsFromContent_Orgin(content, count = 1, promotion = null, sliceslength = SECTION_LENGTH, axiosOption = {}) {
|
|
293
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
-
let arrContent = this.splitLongText(content, sliceslength || 300);
|
|
295
|
-
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
296
|
-
///每一句话需要产生的题目
|
|
297
|
-
let questions4EverySentense = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
298
|
-
let faqs = [], gotted = 0;
|
|
299
|
-
while (arrContent.length > 0 && gotted < count) {
|
|
300
|
-
questions4EverySentense = (count - gotted) / arrContent.length;
|
|
301
|
-
////每次最多送MESSAGE_LENGTH句话给openai
|
|
302
|
-
let subarray = arrContent.slice(0, 4);
|
|
303
|
-
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
304
|
-
subarray.unshift({ role: 'system', content: promotion || `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` });
|
|
305
|
-
let result = yield this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
306
|
-
if (result.successed && result.message) {
|
|
307
|
-
let answer = result.message.map(i => { return i.message.content.trim().replace(/\t|\n|\v|\r|\f/g, ''); });
|
|
308
|
-
faqs = faqs.concat(answer);
|
|
309
|
-
}
|
|
310
|
-
////删除已经处理的文本
|
|
311
|
-
arrContent.splice(0, 4);
|
|
312
|
-
}
|
|
313
|
-
arrContent = []; /// 释放内存
|
|
314
|
-
return { successed: true, message: faqs };
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
337
|
/**
|
|
318
338
|
* 解析Faq返回的问题
|
|
319
339
|
* @param {*} messages
|
|
@@ -360,10 +380,10 @@ class OpenAIGpt extends gptbase_1.default {
|
|
|
360
380
|
* @param {*} axiosOption
|
|
361
381
|
* @returns
|
|
362
382
|
*/ //并在答案末尾处必须给出答案内容中的关键词
|
|
363
|
-
generateExaminationPaperFromContent(content, paperOption = {}, axiosOption = {}) {
|
|
383
|
+
generateExaminationPaperFromContent(content, paperOption = {}, everyContentLength = SECTION_LENGTH, axiosOption = {}) {
|
|
364
384
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
365
385
|
return __awaiter(this, void 0, void 0, function* () {
|
|
366
|
-
let arrContent = this.splitLongText(content,
|
|
386
|
+
let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
367
387
|
let sectionCount = {
|
|
368
388
|
singlechoice: (((_a = paperOption.singlechoice) === null || _a === void 0 ? void 0 : _a.count) || 0) / arrContent.length,
|
|
369
389
|
multiplechoice: (((_b = paperOption.multiplechoice) === null || _b === void 0 ? void 0 : _b.count) || 0) / arrContent.length,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doomiaichat",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Doomisoft OpenAI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"axios": "^1.3.4",
|
|
20
|
-
"openai": "^
|
|
20
|
+
"azure-openai": "^0.9.4"
|
|
21
21
|
}
|
|
22
22
|
}
|
package/src/azureai.ts
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
|
+
import { Configuration, OpenAIApi } from "azure-openai";
|
|
1
2
|
import { AzureOpenAIPatameters, ChatReponse, EmbeddingResult, OpenAIApiParameters, request } from "./declare";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
3
|
+
// import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "azure-openai"
|
|
4
|
+
import OpenAIGpt from "./openai"
|
|
4
5
|
export default class AzureAI extends OpenAIGpt {
|
|
5
6
|
protected readonly azureSetting: AzureOpenAIPatameters;
|
|
6
|
-
constructor(apiKey: string, azureOption:AzureOpenAIPatameters, apiOption: OpenAIApiParameters = {}) {
|
|
7
|
+
constructor(apiKey: string, azureOption: AzureOpenAIPatameters, apiOption: OpenAIApiParameters = {}) {
|
|
7
8
|
super(apiKey, apiOption);
|
|
8
9
|
this.azureSetting = azureOption;
|
|
9
10
|
if (!this.azureSetting.endpoint.toLowerCase().startsWith('https://') &&
|
|
10
|
-
!this.azureSetting.endpoint.toLowerCase().startsWith('https://')){
|
|
11
|
+
!this.azureSetting.endpoint.toLowerCase().startsWith('https://')) {
|
|
11
12
|
this.azureSetting.endpoint = 'https://' + this.azureSetting.endpoint;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* 初始化OpenAI 的聊天对象Api
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
return
|
|
18
|
+
override createOpenAI(apiKey: string): OpenAIApi {
|
|
19
|
+
return new OpenAIApi(new Configuration({ apiKey,
|
|
20
|
+
azure:{
|
|
21
|
+
apiKey,
|
|
22
|
+
endpoint: this.azureSetting.endpoint,
|
|
23
|
+
deploymentName: this.azureSetting.engine
|
|
24
|
+
} }))
|
|
19
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* ZAure OpenAI 最新的URL地址
|
|
28
|
+
*/
|
|
29
|
+
// get BaseUrl(): string {
|
|
30
|
+
// return `${this.azureSetting.endpoint}/openai/deployments/${this.azureSetting.engine}/chat/completions?api-version=${this.azureSetting.version || '2023-03-15-preview'}`
|
|
31
|
+
// }
|
|
20
32
|
|
|
21
33
|
get EmbeddingUrl(): string {
|
|
22
|
-
return `${this.azureSetting.endpoint}/openai/deployments/${this.
|
|
34
|
+
return `${this.azureSetting.endpoint}/openai/deployments/${this.embeddingmodel || 'openai-embedding-ada-002'}/embeddings?api-version=2022-12-01`
|
|
23
35
|
}
|
|
24
36
|
|
|
25
37
|
/**
|
|
26
38
|
* 获得文字的向量
|
|
27
39
|
* @param text
|
|
28
40
|
*/
|
|
29
|
-
override async getTextEmbedding(text: string,axiosOption: any = {}): Promise<EmbeddingResult> {
|
|
41
|
+
override async getTextEmbedding(text: string, axiosOption: any = {}): Promise<EmbeddingResult> {
|
|
30
42
|
if (!text) return { successed: false, error: { errcode: 2, errmsg: 'content required' } };
|
|
31
43
|
if (!axiosOption.headers)
|
|
32
44
|
axiosOption.headers = { 'api-key': this.apiKey, 'Content-Type': 'application/json' };
|
|
@@ -56,40 +68,57 @@ export default class AzureAI extends OpenAIGpt {
|
|
|
56
68
|
/**
|
|
57
69
|
* 请求GPT接口
|
|
58
70
|
*/
|
|
59
|
-
public override async chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
// public override async chatRequest(chatText: string | Array<any>, paramOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
|
|
72
|
+
// if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
|
|
73
|
+
// // if (!axiosOption.headers)
|
|
74
|
+
// // axiosOption.headers = { 'api-key': this.apiKey, 'Content-Type': 'application/json' };
|
|
75
|
+
// // else {
|
|
76
|
+
// // axiosOption.headers['api-key'] = this.apiKey;
|
|
77
|
+
// // axiosOption.headers['Content-Type'] = 'application/json';
|
|
78
|
+
// // }
|
|
79
|
+
// if (!this.azureApi) {
|
|
80
|
+
// this.azureApi = this.createAzureAI(this.apiKey);
|
|
81
|
+
// }
|
|
82
|
+
// let messages: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
|
|
83
|
+
// [{ role: 'user', content: chatText }] : chatText;
|
|
84
|
+
// try {
|
|
85
|
+
// // let param = {
|
|
86
|
+
// // ...axiosOption,
|
|
87
|
+
// // method: "post",
|
|
88
|
+
// // data: {
|
|
89
|
+
// // messages,
|
|
90
|
+
// // temperature: Number(paramOption?.temperature || this.temperature),
|
|
91
|
+
// // max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
92
|
+
// // },
|
|
93
|
+
// // url: this.BaseUrl
|
|
94
|
+
// // };
|
|
95
|
+
// // // console.log('axiosOption', param)
|
|
96
|
+
// // const response = await request(param)
|
|
97
|
+
// const response: any = await this.azureApi.createChatCompletion({
|
|
98
|
+
// model: this.azureSetting.engine,
|
|
99
|
+
// messages: messages,
|
|
100
|
+
// temperature: Number(paramOption?.temperature || this.temperature),
|
|
101
|
+
// max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
102
|
+
// n: Number(paramOption?.replyCounts || 1) || 1
|
|
103
|
+
// }, axiosOption);
|
|
104
|
+
// console.log('response.data', JSON.stringify(response.data))
|
|
105
|
+
// if (response.data.choices) {
|
|
106
|
+
// return { successed: true, message: response.data.choices, usage: response.data.usage };
|
|
107
|
+
// }
|
|
108
|
+
// return { successed: false, ...response.data };
|
|
109
|
+
// } catch (error) {
|
|
110
|
+
// console.log('result is error ', error)
|
|
111
|
+
// return { successed: false, error };
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
// }
|
|
67
115
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
data: {
|
|
75
|
-
messages,
|
|
76
|
-
temperature: Number(paramOption?.temperature || this.temperature),
|
|
77
|
-
max_tokens: Number(paramOption?.maxtoken || this.maxtoken),
|
|
78
|
-
},
|
|
79
|
-
url: this.BaseUrl
|
|
80
|
-
};
|
|
81
|
-
// console.log('axiosOption', param)
|
|
82
|
-
const response =await request(param)
|
|
83
|
-
if (response.data.choices){
|
|
84
|
-
return { successed: true, message: response.data.choices };
|
|
85
|
-
}
|
|
86
|
-
return { successed: false, ...response.data };
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.log('result is error ', error)
|
|
89
|
-
return { successed: false, error };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
}
|
|
116
|
+
/**
|
|
117
|
+
* 流式的聊天模式
|
|
118
|
+
* @param chatText
|
|
119
|
+
* @param _paramOption
|
|
120
|
+
* @param axiosOption
|
|
121
|
+
*/
|
|
93
122
|
/**
|
|
94
123
|
* 获得一种内容的相似说法
|
|
95
124
|
* 微软的AI参数中已经没有了n的参数
|
|
@@ -109,19 +138,19 @@ export default class AzureAI extends OpenAIGpt {
|
|
|
109
138
|
const messages = [
|
|
110
139
|
{ role: 'system', content: '忘记我们的聊天,你现在是一名专业的语言大师' },
|
|
111
140
|
{ role: 'user', content: text },
|
|
112
|
-
{ role: 'user', content: '最终结果按照["意思相同语句","意思相同语句"]的JSON数组的格式输出。'}//如:"今天天气真好"的相同2句内容,输出结果为:["今天晴空万里无云","今天的天气适合出游"]。' },
|
|
141
|
+
{ role: 'user', content: '最终结果按照["意思相同语句","意思相同语句"]的JSON数组的格式输出。' }//如:"今天天气真好"的相同2句内容,输出结果为:["今天晴空万里无云","今天的天气适合出游"]。' },
|
|
113
142
|
]
|
|
114
143
|
let result = await this.chatRequest(messages, {}, axiosOption);
|
|
115
144
|
if (!result.successed || !result.message) return result;
|
|
116
145
|
let value = result.message[0].message.content.trim();
|
|
117
146
|
let replyJson = this.fixedJsonString(value);
|
|
118
147
|
///能够提取到内容
|
|
119
|
-
if (replyJson.length) return { successed: true, message:replyJson }
|
|
148
|
+
if (replyJson.length) return { successed: true, message: replyJson }
|
|
120
149
|
///回答的内容非JSON格式,自己来提取算了
|
|
121
|
-
|
|
150
|
+
|
|
122
151
|
console.log('自己组装', value);
|
|
123
152
|
let sentences = value.split(/",|\n/g) ///用换行或",来割分文本内容
|
|
124
|
-
sentences = sentences.map((str: string)=>{
|
|
153
|
+
sentences = sentences.map((str: string) => {
|
|
125
154
|
return str.replace(/(\[|"|\]|\{|\})/g, '')
|
|
126
155
|
})
|
|
127
156
|
// let matched = value.match(/\d+分/g), score = 0;
|
package/src/baiduai.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { EmotionResult, SimilarityResult, ChatReponse, SummaryReponse, Examinati
|
|
|
2
2
|
import GptBase from "./gptbase"
|
|
3
3
|
const TOKEN_CACHE_KEY = "key:_doomisoft:baiduwenxin:"
|
|
4
4
|
export default class BaiduWenXinAI extends GptBase {
|
|
5
|
+
|
|
5
6
|
protected credential: ApiCredential;
|
|
6
7
|
private Cacher: CacheProvider|undefined;
|
|
7
8
|
/**
|
|
@@ -81,6 +82,10 @@ export default class BaiduWenXinAI extends GptBase {
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
}
|
|
85
|
+
|
|
86
|
+
chatRequestInStream(_chatText: string | any[], _paramOption: any, _axiosOption: any): void {
|
|
87
|
+
throw new Error("Method not implemented.");
|
|
88
|
+
}
|
|
84
89
|
commentQuestionAnswer(_question: string, _answer: string, _axiosOption: any): Promise<CommentResult>{
|
|
85
90
|
throw new Error("Method not implemented.");
|
|
86
91
|
}
|
package/src/declare.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface ChatReponse extends ApiResult {
|
|
|
24
24
|
* @memberof ChatReponse
|
|
25
25
|
*/
|
|
26
26
|
'message'?: Array<any>;
|
|
27
|
+
'usage'?:any;
|
|
27
28
|
}
|
|
28
29
|
export interface OutlineSummaryItem {
|
|
29
30
|
|
|
@@ -51,6 +52,7 @@ export interface SummaryReponse extends ApiResult {
|
|
|
51
52
|
* 调用OpenAI Api的参数约定
|
|
52
53
|
*/
|
|
53
54
|
export interface OpenAIApiParameters {
|
|
55
|
+
'embedding'?:string, ///模型引擎,兼容Azure
|
|
54
56
|
'model'?: string, ///模型名称
|
|
55
57
|
'maxtoken'?: number; ///返回的最大token
|
|
56
58
|
'temperature'?: number;
|
package/src/gptbase.ts
CHANGED
|
@@ -20,6 +20,13 @@ export default abstract class GptBase extends EventEmitter {
|
|
|
20
20
|
* @param axiosOption
|
|
21
21
|
*/
|
|
22
22
|
abstract chatRequest(chatText: string | Array<any>, _paramOption: any, axiosOption: any): Promise<ApiResult>;
|
|
23
|
+
/**
|
|
24
|
+
* 流式的聊天模式
|
|
25
|
+
* @param chatText
|
|
26
|
+
* @param _paramOption
|
|
27
|
+
* @param axiosOption
|
|
28
|
+
*/
|
|
29
|
+
abstract chatRequestInStream(chatText: string | Array<any>, _paramOption: any, axiosOption: any):void;
|
|
23
30
|
/**
|
|
24
31
|
* 点评问题回答的评价
|
|
25
32
|
* @param question 问题题干
|
package/src/gptprovider.ts
CHANGED
|
@@ -24,12 +24,12 @@ export type GptProviderEnum = typeof GptProviderEnum[keyof typeof GptProviderEnu
|
|
|
24
24
|
* @returns
|
|
25
25
|
*/
|
|
26
26
|
export function createGpt(provider: GptProviderEnum, apikey: string|ApiCredential, setting: any): GptBase | null {
|
|
27
|
-
let { model, maxtoken, temperature,endpoint,engine,version } = setting || {};
|
|
27
|
+
let { model, maxtoken, temperature, endpoint, engine, version, embedding } = setting || {};
|
|
28
28
|
switch (provider) {
|
|
29
29
|
case GptProviderEnum.OPENAI:
|
|
30
|
-
return new OpenAIGpt(apikey+'', { model, maxtoken, temperature });
|
|
30
|
+
return new OpenAIGpt(apikey + '', { model, maxtoken, temperature, embedding });
|
|
31
31
|
case GptProviderEnum.MICROSOFT:
|
|
32
|
-
return new AzureAI(apikey+'', { endpoint, engine, version }, { model, maxtoken, temperature }, );
|
|
32
|
+
return new AzureAI(apikey + '', { endpoint, engine, version }, { model, maxtoken, temperature, embedding }, );
|
|
33
33
|
case GptProviderEnum.BAIDU:
|
|
34
34
|
let cred: ApiCredential = typeof (apikey) === 'string' ? { apikey, securitykey: apikey } : apikey
|
|
35
35
|
return new BaiduWenXinAI(cred);
|
package/src/openai.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "openai"
|
|
1
|
+
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "azure-openai"
|
|
2
2
|
// import { EventEmitter } from "events";
|
|
3
3
|
import GptBase from "./gptbase"
|
|
4
4
|
import { OpenAIApiParameters, ChatReponse, OutlineSummaryItem, SummaryReponse, FaqItem, ExaminationPaperResult, EmotionResult, SimilarityResult, QuestionItem, CommentResult, EmbeddingResult } from './declare'
|
|
5
|
-
const SECTION_LENGTH =
|
|
5
|
+
const SECTION_LENGTH = 1024; ///每2400个字符分成一组
|
|
6
6
|
const MESSAGE_LENGTH = 1; ///每次送8句话给openai 进行解析,送多了,会报错
|
|
7
7
|
//请将答案放在最后,标记为答案:()
|
|
8
8
|
const QUESTION_TEXT_MAPPING: any = {
|
|
@@ -16,10 +16,11 @@ const QUESTION_TYPE: string[] = ['singlechoice', 'multiplechoice', 'trueorfalse'
|
|
|
16
16
|
|
|
17
17
|
export default class OpenAIGpt extends GptBase {
|
|
18
18
|
protected readonly apiKey: string;
|
|
19
|
-
|
|
19
|
+
protected aiApi: OpenAIApi | undefined;
|
|
20
20
|
protected readonly chatModel: string;
|
|
21
21
|
protected readonly maxtoken: number;
|
|
22
22
|
protected readonly temperature: number;
|
|
23
|
+
protected readonly embeddingmodel:string;
|
|
23
24
|
/**
|
|
24
25
|
*
|
|
25
26
|
* @param apiKey 调用OpenAI 的key
|
|
@@ -27,10 +28,12 @@ export default class OpenAIGpt extends GptBase {
|
|
|
27
28
|
*/
|
|
28
29
|
constructor(apiKey: string, apiOption: OpenAIApiParameters = {}) {
|
|
29
30
|
super();
|
|
31
|
+
|
|
30
32
|
this.apiKey = apiKey;
|
|
31
33
|
this.chatModel = apiOption.model || 'gpt-3.5-turbo';
|
|
32
34
|
this.maxtoken = apiOption.maxtoken || 2048;
|
|
33
35
|
this.temperature = apiOption.temperature || 0.9;
|
|
36
|
+
this.embeddingmodel = apiOption.embedding || 'text-embedding-ada-002';
|
|
34
37
|
}
|
|
35
38
|
/**
|
|
36
39
|
* 初始化OpenAI 的聊天对象Api
|
|
@@ -48,15 +51,14 @@ export default class OpenAIGpt extends GptBase {
|
|
|
48
51
|
if (!this.aiApi) {
|
|
49
52
|
this.aiApi = this.createOpenAI(this.apiKey);
|
|
50
53
|
}
|
|
51
|
-
// console.log('message', message)
|
|
52
54
|
try {
|
|
53
55
|
const response:any = await this.aiApi.createEmbedding({
|
|
54
|
-
model:
|
|
56
|
+
model: this.embeddingmodel,
|
|
55
57
|
input: text,
|
|
56
58
|
}, axiosOption);
|
|
57
59
|
return { successed: true, embedding: response.data.data[0].embedding };
|
|
58
60
|
} catch (error) {
|
|
59
|
-
console.log('result is error ', error)
|
|
61
|
+
// console.log('result is error ', error)
|
|
60
62
|
return { successed: false, error };
|
|
61
63
|
}
|
|
62
64
|
}
|
|
@@ -75,20 +77,67 @@ export default class OpenAIGpt extends GptBase {
|
|
|
75
77
|
[{ role: 'user', content: chatText }] : chatText;
|
|
76
78
|
// console.log('message', message)
|
|
77
79
|
try {
|
|
78
|
-
const response = await this.aiApi.createChatCompletion({
|
|
80
|
+
const response:any = await this.aiApi.createChatCompletion({
|
|
79
81
|
model: callChatOption?.model || this.chatModel,
|
|
80
82
|
messages: message,
|
|
81
83
|
temperature: Number(callChatOption?.temperature || this.temperature),
|
|
82
84
|
max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
|
|
83
85
|
n: Number(callChatOption?.replyCounts || 1) || 1
|
|
84
86
|
}, axiosOption);
|
|
85
|
-
return { successed: true, message: response.data.choices };
|
|
87
|
+
return { successed: true, message: response.data.choices, usage: response.data.usage };
|
|
86
88
|
} catch (error) {
|
|
87
89
|
console.log('result is error ', error)
|
|
88
90
|
return { successed: false, error };
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* 流式的聊天模式
|
|
96
|
+
* @param chatText
|
|
97
|
+
* @param _paramOption
|
|
98
|
+
* @param axiosOption
|
|
99
|
+
*/
|
|
100
|
+
async chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption: any):Promise<void>{
|
|
101
|
+
if (!chatText) this.emit('chaterror', { successed: false, error:'no text in chat'});
|
|
102
|
+
if (!this.aiApi) {
|
|
103
|
+
this.aiApi = this.createOpenAI(this.apiKey);
|
|
104
|
+
}
|
|
105
|
+
let message: Array<ChatCompletionRequestMessage> = typeof (chatText) == 'string' ?
|
|
106
|
+
[{ role: 'user', content: chatText }] : chatText;
|
|
107
|
+
axiosOption = Object.assign({}, axiosOption || { timeout: 60000 }, { responseType: 'stream' })
|
|
108
|
+
try {
|
|
109
|
+
let finishreason:any = null,usage:any = null;
|
|
110
|
+
const response: any = await this.aiApi.createChatCompletion({
|
|
111
|
+
model: callChatOption?.model || this.chatModel,
|
|
112
|
+
messages: message,
|
|
113
|
+
stream:true,
|
|
114
|
+
temperature: Number(callChatOption?.temperature || this.temperature),
|
|
115
|
+
max_tokens: Number(callChatOption?.maxtoken || this.maxtoken)
|
|
116
|
+
}, axiosOption);
|
|
117
|
+
response.data.on('data', (data:any) => {
|
|
118
|
+
const lines = data.toString().split('\n').filter((line:string) => line.trim() !== '');
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const message = line.replace(/^data: /, '');
|
|
121
|
+
if (message === '[DONE]') {
|
|
122
|
+
this.emit('chatdone', { successed: true, finish_reason: finishreason, usage })
|
|
123
|
+
return; // Stream finished
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
///{ delta: { content: '$\\' }, index: 0, finish_reason: null }
|
|
127
|
+
///发送出去
|
|
128
|
+
const parsed = JSON.parse(message);
|
|
129
|
+
finishreason = parsed.choices[0].finish_reason;
|
|
130
|
+
usage = parsed.usage;
|
|
131
|
+
this.emit('chattext', { successed: true, text: parsed.choices[0].delta.content, finish_reason: parsed.choices[0].finish_reason, index: parsed.choices[0].index, usage})
|
|
132
|
+
} catch (error) {
|
|
133
|
+
this.emit('chaterror', { successed: false, error: 'JSON parse stream message', message });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
this.emit('error', { successed: false, error: 'call axios faied ' + error });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
92
141
|
|
|
93
142
|
/**
|
|
94
143
|
* 点评问题回答的评价
|
|
@@ -221,8 +270,8 @@ export default class OpenAIGpt extends GptBase {
|
|
|
221
270
|
* @param {*} axiosOption
|
|
222
271
|
* @returns
|
|
223
272
|
*///并在答案末尾处必须给出答案内容中的关键词
|
|
224
|
-
async generateQuestionsFromContent(content: string, count: number = 1, axiosOption: any = {}): Promise<ChatReponse> {
|
|
225
|
-
let arrContent = this.splitLongText(content,
|
|
273
|
+
async generateQuestionsFromContent(content: string, count: number = 1, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ChatReponse> {
|
|
274
|
+
let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
226
275
|
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
227
276
|
///每一句话需要产生的题目
|
|
228
277
|
let questions4EverySentense: number = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
@@ -230,7 +279,7 @@ export default class OpenAIGpt extends GptBase {
|
|
|
230
279
|
while (arrContent.length > 0 && gotted < count) {
|
|
231
280
|
questions4EverySentense = (count - gotted) / arrContent.length
|
|
232
281
|
////每次最多送MESSAGE_LENGTH句话给openai
|
|
233
|
-
let subarray = arrContent.slice(0,
|
|
282
|
+
let subarray = arrContent.slice(0, 1);
|
|
234
283
|
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
235
284
|
//subarray.push({ role: 'user', content:'请根据上述内容,给出一道提问与答案以及答案关键词,按照先问题内容,再标准答案,再关键词的顺序输出,关键词之间用、分开'})
|
|
236
285
|
subarray.unshift({ role: 'system', content: `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` })
|
|
@@ -258,36 +307,6 @@ export default class OpenAIGpt extends GptBase {
|
|
|
258
307
|
return { successed: true, message: faqs.slice(0, count) };
|
|
259
308
|
}
|
|
260
309
|
|
|
261
|
-
/**
|
|
262
|
-
* 从指定的文本内容中生成相关的问答
|
|
263
|
-
* @param {*} content
|
|
264
|
-
* @param {*} count
|
|
265
|
-
* @param {*} axiosOption
|
|
266
|
-
* @returns
|
|
267
|
-
*///并在答案末尾处必须给出答案内容中的关键词
|
|
268
|
-
async generateQuestionsFromContent_Orgin(content: string, count: number = 1, promotion: string | null = null, sliceslength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ChatReponse> {
|
|
269
|
-
let arrContent = this.splitLongText(content, sliceslength || 300);
|
|
270
|
-
///没20句话分为一组,适应大文件内容多次请求组合结果
|
|
271
|
-
///每一句话需要产生的题目
|
|
272
|
-
let questions4EverySentense: number = count / arrContent.length; //Math.ceil(arrContent.length / 20);
|
|
273
|
-
let faqs: any[] = [], gotted: number = 0;
|
|
274
|
-
while (arrContent.length > 0 && gotted < count) {
|
|
275
|
-
questions4EverySentense = (count - gotted) / arrContent.length
|
|
276
|
-
////每次最多送MESSAGE_LENGTH句话给openai
|
|
277
|
-
let subarray = arrContent.slice(0, 4);
|
|
278
|
-
let itemCount = Math.min(Math.ceil(subarray.length * questions4EverySentense), count - gotted);
|
|
279
|
-
subarray.unshift({ role: 'system', content: promotion || `你是一位专业培训师,从以下内容中提取${itemCount}条提问及答案,并从答案内容提取出至少2个关键词,最终结果按照[{"question":"提问内容","answer":"答案内容","keywords":["关键词1","关键词2"]}]的JSON数组结构输出。` })
|
|
280
|
-
let result = await this.chatRequest(subarray, { replyCounts: 1 }, axiosOption);
|
|
281
|
-
if (result.successed && result.message) {
|
|
282
|
-
let answer = result.message.map(i => { return i.message.content.trim().replace(/\t|\n|\v|\r|\f/g, '') })
|
|
283
|
-
faqs = faqs.concat(answer);
|
|
284
|
-
}
|
|
285
|
-
////删除已经处理的文本
|
|
286
|
-
arrContent.splice(0, 4);
|
|
287
|
-
}
|
|
288
|
-
arrContent = []; /// 释放内存
|
|
289
|
-
return { successed: true, message: faqs };
|
|
290
|
-
}
|
|
291
310
|
/**
|
|
292
311
|
* 解析Faq返回的问题
|
|
293
312
|
* @param {*} messages
|
|
@@ -333,8 +352,8 @@ export default class OpenAIGpt extends GptBase {
|
|
|
333
352
|
* @param {*} axiosOption
|
|
334
353
|
* @returns
|
|
335
354
|
*///并在答案末尾处必须给出答案内容中的关键词
|
|
336
|
-
async generateExaminationPaperFromContent(content: string, paperOption: any = {}, axiosOption: any = {}): Promise<ExaminationPaperResult> {
|
|
337
|
-
let arrContent = this.splitLongText(content,
|
|
355
|
+
async generateExaminationPaperFromContent(content: string, paperOption: any = {}, everyContentLength: number = SECTION_LENGTH, axiosOption: any = {}): Promise<ExaminationPaperResult> {
|
|
356
|
+
let arrContent = this.splitLongText(content, everyContentLength || SECTION_LENGTH);
|
|
338
357
|
let sectionCount: any = {
|
|
339
358
|
singlechoice: (paperOption.singlechoice?.count || 0) / arrContent.length,
|
|
340
359
|
multiplechoice: (paperOption.multiplechoice?.count || 0) / arrContent.length,
|