182 lines
5.3 KiB
TypeScript
182 lines
5.3 KiB
TypeScript
import { isEmpty } from "lodash";
|
||
import { gptDefine } from "../../../define/gptDefine";
|
||
import axios from "axios";
|
||
import { RetryWithBackoff } from "../../../define/Tools/common";
|
||
|
||
/**
|
||
* 一些GPT相关的服务都在这边
|
||
*/
|
||
export class GptService {
|
||
gptUrl: string = undefined
|
||
gptModel: string = undefined
|
||
gptApiKey: string = undefined
|
||
|
||
|
||
//#region GPT 设置
|
||
|
||
/**
|
||
* 获取GPT的所有的服务商
|
||
* @param type 获取的类型,就是all
|
||
* @param callback 这个是个回调函数,干嘛的不知道
|
||
* @returns
|
||
*/
|
||
private async GetGPTBusinessOption(type: string, callback: Function = null): Promise<any> {
|
||
let res = await gptDefine.getGptDataByTypeAndProperty(type, "gpt_options", []);
|
||
if (res.code == 0) {
|
||
throw new Error(res.message)
|
||
} else {
|
||
if (callback) {
|
||
callback(res.data)
|
||
}
|
||
return res.data
|
||
}
|
||
}
|
||
|
||
async RefreshGptSetting() {
|
||
let all_options = await this.GetGPTBusinessOption("all", (value) => value.gpt_url);
|
||
let index = all_options.findIndex(item => item.value == global.config.gpt_business && item.gpt_url)
|
||
if (index < 0) {
|
||
throw new Error("没有找到指定的GPT服务商的配置,请检查")
|
||
}
|
||
this.gptUrl = all_options[index].gpt_url;
|
||
this.gptApiKey = global.config.gpt_key;
|
||
this.gptModel = global.config.gpt_model;
|
||
}
|
||
|
||
/**
|
||
* 初始化GPT的设置
|
||
*/
|
||
async InitGptSetting(refresh = false) {
|
||
if (refresh) {
|
||
await this.RefreshGptSetting()
|
||
} else {
|
||
// 判断是不是存在必要信息
|
||
if (isEmpty(this.gptUrl) || isEmpty(this.gptModel) || isEmpty(this.gptApiKey)) {
|
||
await this.RefreshGptSetting();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 适配一些请求体中的参数
|
||
* @param data
|
||
* @param gpt_url
|
||
* @returns
|
||
*/
|
||
ModifyData(data: any, gpt_url: string = null) {
|
||
let res = data;
|
||
if (!gpt_url) {
|
||
gpt_url = this.gptUrl
|
||
}
|
||
if (gpt_url.includes("dashscope.aliyuncs.com")) {
|
||
res = {
|
||
"model": data.model,
|
||
"input": {
|
||
"messages": data.messages,
|
||
},
|
||
"parameters": {
|
||
"result_format": "message"
|
||
}
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* 适配返回来的数据
|
||
* @param res 返回的数据
|
||
* @param gpt_url 请求的URL
|
||
* @returns
|
||
*/
|
||
GetResponseContent(res: any, gpt_url: string = null) {
|
||
let content = "";
|
||
if (!gpt_url) {
|
||
gpt_url = this.gptUrl
|
||
}
|
||
if (gpt_url.includes("dashscope.aliyuncs.com")) {
|
||
content = res.data.output.choices[0].message.content;
|
||
} else {
|
||
content = res.data.choices[0].message.content;
|
||
}
|
||
return content;
|
||
}
|
||
|
||
//#endregion
|
||
|
||
/**
|
||
* 发送GPT请求
|
||
* @param {*} message 请求的信息
|
||
* @param {*} gpt_url gpt的url,默认在global中取
|
||
* @param {*} gpt_key gpt的key,默认在global中取
|
||
* @param {*} gpt_model gpt的model,默认在global中取
|
||
* @returns
|
||
*/
|
||
async FetchGpt(message: any, gpt_model: string = null, gpt_key: string = null, gpt_url: string = null): Promise<string> {
|
||
try {
|
||
await this.InitGptSetting();
|
||
let data = {
|
||
"model": gpt_model ? gpt_model : this.gptModel,
|
||
"messages": message
|
||
};
|
||
|
||
data = this.ModifyData(data, gpt_url);
|
||
let config = {
|
||
method: 'post',
|
||
maxBodyLength: Infinity,
|
||
url: gpt_url ? gpt_url : this.gptUrl,
|
||
headers: {
|
||
'Authorization': `Bearer ${gpt_key ? gpt_key : this.gptApiKey}`,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
data: JSON.stringify(data)
|
||
};
|
||
|
||
let res = await axios.request(config);
|
||
let content = this.GetResponseContent(res, this.gptUrl);
|
||
return content;
|
||
} catch (error) {
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
//#region 繁体中文 -> 简体中文
|
||
|
||
/**
|
||
* 将繁体中文转换为简体中文
|
||
* @param traditionalText 繁体中文文本
|
||
* @param apiKey Lai API的 Key
|
||
* @param baseUrl 请求的baseurl
|
||
* @returns
|
||
*/
|
||
async ChineseTraditionalToSimplified(traditionalText: string, apiKey: string, baseUrl: string = null): Promise<string> {
|
||
try {
|
||
let message = [
|
||
{
|
||
"role": "system",
|
||
"content": '我想让你充当中文繁体转简体专家,用简体中文100%还原繁体中文,不要加其他的联想,只把原有的繁体中文转换为简体中文,请检查所有信息是否准确,并在回答时保持简活,不需要任何其他反馈。'
|
||
}, {
|
||
"role": "user",
|
||
"content": '上研究生後,發現導師竟然是曾經網戀的前男友。'
|
||
}, {
|
||
"role": "assistant",
|
||
"content": '上研究生后,发现导师竟然是曾经网恋的前男友。'
|
||
}, {
|
||
"role": "user",
|
||
"content": traditionalText
|
||
}
|
||
]
|
||
|
||
let baseSubUrl = baseUrl ? (baseUrl.endsWith('/') ? baseUrl + 'v1/chat/completions' : baseUrl + '/v1/chat/completions') : null;
|
||
let url = baseSubUrl ? baseSubUrl : "https://api.laitool.cc/v1/chat/completions"
|
||
// 开始请求,这个默认是使用的是LAI API的gpt-4o-mini
|
||
let content = await RetryWithBackoff<string>(async () => {
|
||
return await this.FetchGpt(message, 'gpt-4o-mini', apiKey, url);
|
||
}, 5, 2000)
|
||
|
||
return content
|
||
} catch (error) {
|
||
throw error
|
||
}
|
||
}
|
||
//#endregion
|
||
} |