2024-08-18 16:22:19 +08:00
|
|
|
|
import { isEmpty } from "lodash";
|
|
|
|
|
|
import { gptDefine } from "../../../define/gptDefine";
|
|
|
|
|
|
import axios from "axios";
|
2024-08-20 10:37:38 +08:00
|
|
|
|
import { RetryWithBackoff } from "../../../define/Tools/common";
|
2024-11-09 16:46:06 +08:00
|
|
|
|
import { Book } from "../../../model/book/book";
|
2024-08-18 16:22:19 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 一些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;
|
2024-11-19 20:28:31 +08:00
|
|
|
|
return {
|
|
|
|
|
|
gptUrl: this.gptUrl,
|
|
|
|
|
|
gptApiKey: this.gptApiKey,
|
|
|
|
|
|
gptModel: this.gptModel
|
|
|
|
|
|
}
|
2024-08-18 16:22:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化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
|
|
|
|
|
|
|
2024-09-12 14:13:09 +08:00
|
|
|
|
//#region GPT 通用请求
|
2024-08-18 16:22:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 发送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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-12 14:13:09 +08:00
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
|
|
//#region 原创推理
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取当前分镜的上下文数据
|
|
|
|
|
|
* @param currentBookTaskDetail 当前分镜数据
|
|
|
|
|
|
* @param bookTaskDetails 所有的小说分镜数据
|
|
|
|
|
|
* @param contextCount 上下文行数
|
|
|
|
|
|
*/
|
|
|
|
|
|
GetBookTaskDetailContextData(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number): string {
|
|
|
|
|
|
let prefix = "";
|
|
|
|
|
|
// 拼接一个word
|
|
|
|
|
|
let i = currentBookTaskDetail.no - 1
|
|
|
|
|
|
if (i <= contextCount) {
|
|
|
|
|
|
prefix = bookTaskDetails
|
|
|
|
|
|
.filter((item, index) => index < i)
|
|
|
|
|
|
.map((item) => item.afterGpt)
|
|
|
|
|
|
.join('\r\n')
|
|
|
|
|
|
} else if (i > contextCount) {
|
|
|
|
|
|
prefix = bookTaskDetails
|
|
|
|
|
|
.filter((item, index) => i - index <= contextCount && i - index > 0)
|
|
|
|
|
|
.map((item) => item.afterGpt)
|
|
|
|
|
|
.join('\r\n')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let suffix = "";
|
|
|
|
|
|
let o_i = bookTaskDetails.length - i
|
|
|
|
|
|
if (o_i <= contextCount) {
|
|
|
|
|
|
suffix = bookTaskDetails
|
|
|
|
|
|
.filter((item, index) => index > i)
|
|
|
|
|
|
.map((item) => item.afterGpt)
|
|
|
|
|
|
.join('\r\n')
|
|
|
|
|
|
} else if (o_i > contextCount) {
|
|
|
|
|
|
suffix = bookTaskDetails
|
|
|
|
|
|
.filter((item, index) => index - i <= contextCount && index - i > 0)
|
|
|
|
|
|
.map((item) => item.afterGpt)
|
|
|
|
|
|
.join('\r\n')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return `${prefix}\r\n${currentBookTaskDetail.afterGpt}\r\n${suffix}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 返回当前推理数据的请求体中的message
|
|
|
|
|
|
* @param currentBookTaskDetail 当前推理的提示词数据
|
|
|
|
|
|
* @param contextData 上下文数据
|
|
|
|
|
|
* @param autoAnalyzeCharacter 自动分析的角色数据
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
GetGPTRequestMessage(currentBookTaskDetail: Book.SelectBookTaskDetail, contextData: string, autoAnalyzeCharacter: string): any[] {
|
|
|
|
|
|
let message = []
|
|
|
|
|
|
if (
|
2024-11-19 20:28:31 +08:00
|
|
|
|
['superSinglePrompt', 'onlyPromptMJ', 'superSinglePromptChinese', "superPromptOverall", "superPromptCharacterEnhancement", "superPromptAdvancedEffects", "superPromptNotWord"].includes(
|
2024-09-12 14:13:09 +08:00
|
|
|
|
global.config.gpt_auto_inference
|
|
|
|
|
|
)
|
|
|
|
|
|
) {
|
|
|
|
|
|
// 有返回案例的
|
|
|
|
|
|
message = gptDefine.GetExamplePromptMessage(global.config.gpt_auto_inference)
|
|
|
|
|
|
// 加当前提问的
|
|
|
|
|
|
message.push({
|
|
|
|
|
|
role: 'user',
|
|
|
|
|
|
content: currentBookTaskDetail.afterGpt
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 直接返回,没有案例的
|
|
|
|
|
|
message = [
|
|
|
|
|
|
{
|
|
|
|
|
|
role: 'system',
|
|
|
|
|
|
content: gptDefine.getSystemContentByType(global.config.gpt_auto_inference, {
|
|
|
|
|
|
textContent: contextData,
|
|
|
|
|
|
characterContent: autoAnalyzeCharacter
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
role: 'user',
|
|
|
|
|
|
content: gptDefine.getUserContentByType(global.config.gpt_auto_inference, {
|
|
|
|
|
|
textContent: currentBookTaskDetail.afterGpt,
|
|
|
|
|
|
wordCount:
|
|
|
|
|
|
global.config.gpt_model && global.config.gpt_model.includes('gpt-4')
|
|
|
|
|
|
? '20'
|
|
|
|
|
|
: '40'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
return message
|
|
|
|
|
|
}
|
2024-08-18 16:22:19 +08:00
|
|
|
|
|
2024-09-12 14:13:09 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 原创推理提示词数据
|
|
|
|
|
|
* @param currentBookTaskDetail 要推理的小说分镜任务
|
|
|
|
|
|
* @param bookTaskDetails 所有的小说分镜任务
|
|
|
|
|
|
* @param contextCount 上下文的数量
|
|
|
|
|
|
* @param autoAnalyzeCharacter 自动分析的角色数据字符串
|
|
|
|
|
|
*/
|
|
|
|
|
|
async OriginalInferencePrompt(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number, autoAnalyzeCharacter: string) {
|
|
|
|
|
|
let gptPromptType = global.config.gpt_auto_inference;
|
|
|
|
|
|
let message = []
|
|
|
|
|
|
if (gptPromptType == "customize") { //自定义模式
|
|
|
|
|
|
// 自定义模式
|
|
|
|
|
|
// 获取当前自定义的推理提示词
|
|
|
|
|
|
let customize_gpt_prompt = (
|
|
|
|
|
|
await gptDefine.getGptDataByTypeAndProperty('dynamic', 'customize_gpt_prompt', [])
|
|
|
|
|
|
).data
|
|
|
|
|
|
let index = customize_gpt_prompt.findIndex(
|
|
|
|
|
|
(item: any) => item.id == global.config.customize_gpt_prompt
|
|
|
|
|
|
)
|
|
|
|
|
|
if (global.config.customize_gpt_prompt && index < 0) {
|
|
|
|
|
|
throw new Error('自定义推理时要选择对应的自定义推理词')
|
|
|
|
|
|
}
|
|
|
|
|
|
message = gptDefine.CustomizeGptPrompt(customize_gpt_prompt[index], currentBookTaskDetail.afterGpt)
|
|
|
|
|
|
message.push({
|
|
|
|
|
|
role: 'user',
|
|
|
|
|
|
content: currentBookTaskDetail.afterGpt
|
|
|
|
|
|
})
|
|
|
|
|
|
} else { // 内置模式
|
|
|
|
|
|
let context = this.GetBookTaskDetailContextData(currentBookTaskDetail, bookTaskDetails, contextCount);
|
|
|
|
|
|
message = this.GetGPTRequestMessage(currentBookTaskDetail, context, autoAnalyzeCharacter);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 开始请求
|
|
|
|
|
|
let res = await RetryWithBackoff(async () => {
|
|
|
|
|
|
return this.FetchGpt(message)
|
|
|
|
|
|
}, 5, 1000)
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
res = res
|
|
|
|
|
|
.replace(/\)\s*\(/g, ', ')
|
|
|
|
|
|
.replace(/^\(/, '')
|
|
|
|
|
|
.replace(/\)$/, '')
|
|
|
|
|
|
.replaceAll('*', '')
|
|
|
|
|
|
.replaceAll('--', ' ')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//#endregion
|
2024-08-18 16:22:19 +08:00
|
|
|
|
|
2024-09-12 14:13:09 +08:00
|
|
|
|
//#region 中文 繁体转简体
|
2024-08-18 16:22:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 将繁体中文转换为简体中文
|
|
|
|
|
|
* @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
|
2024-08-20 10:37:38 +08:00
|
|
|
|
let content = await RetryWithBackoff<string>(async () => {
|
|
|
|
|
|
return await this.FetchGpt(message, 'gpt-4o-mini', apiKey, url);
|
|
|
|
|
|
}, 5, 2000)
|
|
|
|
|
|
|
2024-08-18 16:22:19 +08:00
|
|
|
|
return content
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#endregion
|
2024-11-02 18:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
//#region 聚合推文 文案洗稿
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 聚合推文的文案洗稿
|
|
|
|
|
|
* @param word 之前的提示词
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
async GenerateAfterGptWordByGPT(word: string,) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let prompt = `## - Role: 文案去重
|
|
|
|
|
|
<Background>: 用户需要将小说的文本进行细致的分析,并将原文文本内容进行同义转换,换一种描述,不要改变文案的结构,不改变原来的意思,要求参考原文案的写作风格,不要书面词,要尽可能的口语化输出,但不要太过于运用东北话的一些词语,比如“瞅“,“爱咋咋地“,“咋地“,等类似的词语。
|
|
|
|
|
|
|
|
|
|
|
|
## 要求
|
|
|
|
|
|
严格执行以下要求进行小说内容的段落分行:
|
|
|
|
|
|
1.严格要求根据原文进行同义输出:不允许将原文一行内容所表达的内容分成多行来输出。
|
|
|
|
|
|
2.仅对原文中的话换一种描述,但不能完全脱离这句话的意思。
|
|
|
|
|
|
3.输出的内容每一句话与原文的字数尽量保持一致,严格遵守不能远少于原文每个句子的字数,再次强调不能少于原文每句话的字数。
|
|
|
|
|
|
4.输出的文案的相似度必须低于百分之五十
|
|
|
|
|
|
|
|
|
|
|
|
## 示例
|
|
|
|
|
|
输入1:这个世界的女人每结一次婚,就会在手上戴一枚戒指,手上的戒指越多,那么就代表着她的老公越多。
|
|
|
|
|
|
输出1: 雌性每洞房一次,就会带上一枚戒指,手上的戒指越多,就代表被她宠幸的雄性越多。
|
|
|
|
|
|
|
|
|
|
|
|
输入2:我重生到末日前的第一件事,就是从学校后山徒手抓了一条黑曼巴蛇,并丧心病狂的将之活生生吞下。
|
|
|
|
|
|
输出2: 我重生后的第一件事就是生吞羊辣子,然后挖出自己双眼,再割掉自己头颅,众人以为我是疯子得了精神病,但只有我知道我是重生者。
|
|
|
|
|
|
|
|
|
|
|
|
输入3:我明明觉醒了SSS级异能紫霄神器,却被全校所有人嘲笑,原因我觉醒的异能在别人眼里只是一个人形电击棒。
|
|
|
|
|
|
输出3: 我明明觉醒了sss级暗黑系异能,却被超神学院五大院长同时除名,就连唯一的妹妹夜哭着劝我放弃修炼。
|
|
|
|
|
|
|
|
|
|
|
|
输入3:我的奶奶觉醒级凶兽烈焰巨龙,我的爷爷觉醒级凶兽暴虐滔天,而我却在这个觉醒凶兽的世界觉醒了个破烂石板
|
|
|
|
|
|
输出3: 我爷爷觉醒了s级凶兽黄金朱厌,奶奶觉醒了ss级神兽泰坦巨猿,可我却在这个人人觉醒泰坦战士的世界
|
|
|
|
|
|
|
|
|
|
|
|
输入5: 一个先天满属性的天才却被称为废物,只因我在转职时觉醒了史上最垃圾的道士职业,就连重金挖我来的学校也将我当成了耻辱
|
|
|
|
|
|
输出5: 一个先天满属性的天才却被称为废物,只因我在转职时觉醒了史上最垃圾的道士职业,就连重金挖我来的学校也将我当成了耻辱
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
|
最后再强调,你作为一位优秀的小说改写者,每一次输出都要严格遵守<要求>,一步一步慢慢思考,参考<示例>的格式,一步一步思考,按顺序执行<要求>,不需要做解释说明,只呈现最后的结果,严格要求理解全文之后再进行分组,无需要在输出用户,直接输出Ai部分。
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
let message = [
|
|
|
|
|
|
{
|
|
|
|
|
|
"role": "system",
|
|
|
|
|
|
"content": prompt,
|
|
|
|
|
|
}, {
|
|
|
|
|
|
"role": "user",
|
|
|
|
|
|
"content": word
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 开始请求,这个默认是使用的是LAI API的gpt-4o-mini
|
|
|
|
|
|
let content = await RetryWithBackoff<string>(async () => {
|
|
|
|
|
|
return await this.FetchGpt(message, null, null, null);
|
|
|
|
|
|
}, 5, 2000)
|
|
|
|
|
|
return content;
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#endregion
|
2024-08-18 16:22:19 +08:00
|
|
|
|
}
|