import { GeneralResponse } from "../../../model/generalResponse"; import { TranslateModel } from "../../../model/translate"; import { errorMessage, successMessage } from "../../Public/generalTools"; import { Translate } from "./Translate"; import { DEFINE_STRING } from "../../../define/define_string" import { TranslateAPIType, TranslateType } from "../../../define/enum/translate"; import { Book } from "../../../model/book"; import { ResponseMessageType } from "../../../define/enum/softwareEnum"; import { isEmpty } from "lodash"; import { ValidateJson } from "../../../define/Tools/validate"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic"; import { ExecuteConcurrently } from "../../../define/Tools/common"; /** * 翻译实现服务 */ export class TranslateService { translate: Translate bookServiceBasic: BookServiceBasic softWareServiceBasic: SoftWareServiceBasic constructor() { this.bookServiceBasic = new BookServiceBasic(); this.translate = new Translate(); this.softWareServiceBasic = new SoftWareServiceBasic(); } // 返回翻译结果。用于前端修改 private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.MAIN_DATA_RETURN): void { let win = global.newWindow[0] if (windowId) { win = global.newWindow.filter(item => item.id == windowId)[0]; } if (!message_name) { message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN } win.win.webContents.send(message_name, data) } //#region 翻译设置 /** * 初始化翻译设置 * @returns */ InitialTranslateSetting(): TranslateModel.TranslateModel { return { selectModel: TranslateAPIType.BAIDU, translation_auto: true, translates: [ { name: TranslateAPIType.LAITOOL, translation_business: "https://api.laitool.cc/v1/chat/completions", translation_app_id: "gpt-4o-mini", translation_secret: "LAI API 令牌" }, { name: TranslateAPIType.BAIDU, translation_business: "https://fanyi-api.baidu.com/api/trans/vip/translate", translation_app_id: "百度翻译的APP ID", translation_secret: "百度翻译的密钥" }, { name: TranslateAPIType.TENCENT, translation_business: "https://tmt.tencentcloudapi.com", translation_app_id: '腾讯云的APP ID', translation_secret: "腾讯云的密钥" }, { name: TranslateAPIType.VOLCENGINE, translation_business: "https://translate.volcengineapi.com?", translation_app_id: '火山引擎的APP ID', translation_secret: '火山引擎的密钥' }, { name: TranslateAPIType.ALI, translation_business: "https://mt.cn-hangzhou.aliyuncs.com", translation_app_id: '阿里云的APP ID', translation_secret: '阿里云的密钥' } ] } } /** * 获取翻译设置 */ async GetTranslateSetting(): Promise { try { let translateSetting = undefined as TranslateModel.TranslateModel let translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting'); if (isEmpty(translateSettingString)) { // 初始化 translateSetting = this.InitialTranslateSetting(); await this.ResetTranslateSetting(); translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting'); translateSetting = JSON.parse(translateSettingString); } else { // 解析 let tryParse = ValidateJson(translateSettingString) if (!tryParse) { throw new Error("翻译设置数据解析失败,请重置后重新配置") } translateSetting = JSON.parse(translateSettingString); } // v3.0.1 preview 4 版本新增laitool gpt翻译,之前版本没有,这边要检测下是不是有配置,没有初始化 let index = translateSetting.translates.findIndex(item => item.name == TranslateAPIType.LAITOOL); if (index < 0) { // 初始化,将数据加在最前面 let laitool = { name: TranslateAPIType.LAITOOL, translation_business: "https://api.laitool.cc/v1/chat/completions", translation_app_id: "gpt-4o-mini", translation_secret: "LAI API 令牌" } translateSetting.translates.unshift(laitool) } return successMessage(translateSetting, "获取翻译设置成功", "TranslateService_GetTranslateSetting") } catch (error) { return errorMessage("获取翻译设置失败,失败信息如下:" + error.toString(), "TranslateService_GetTranslateSetting") } } /** * 重置翻译设置 */ async ResetTranslateSetting(): Promise { try { let translateSetting = this.InitialTranslateSetting() let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(translateSetting)) return successMessage(translateSetting, "重置翻译设置成功", "TranslateService_ResetTranslateSetting") } catch (error) { return errorMessage("重置翻译设置失败,失败信息如下:" + error.toString(), "TranslateService_ResetTranslateSetting") } } /** * 保存翻译设置 * @param value 保存的数据 * @returns */ async SaveTranslateSetting(value: TranslateModel.TranslateModel): Promise { try { let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(value)) // 这边要判断是不是用的laitool let laitool = value.translates.filter(item => item.name == TranslateAPIType.LAITOOL) if (laitool.length > 0) { let laitoolData = laitool[0] if (!laitoolData.translation_business.includes('laitool')) { throw new Error("不允许修改laitool的地址为其他外站地址") } } return successMessage(value, "保存翻译设置成功", "TranslateService_SaveTranslateSetting") } catch (error) { return errorMessage("保存翻译设置失败,失败信息如下:" + error.toString(), "TranslateService_SaveTranslateSetting") } } //#endregion /** * 翻译反推提示词处理 * @param bookTaskDetailId 对应的分镜ID * @param reversePromptId 对应的反推提示词数据ID * @param to 目标语言 * @param dstString 翻译后的字符串 */ private async TranslateProcessReversePrompt(bookTaskDetailId: string, reversePromptId: string, to: string, dstString: string): Promise { // 开始修改翻译后的数据 let updateData = {} as Book.ReversePrompt if (to == "zh") { updateData.promptCN = dstString } else if (to == "en") { updateData.prompt = dstString updateData.promptCN = dstString } // 修改数据 await this.bookServiceBasic.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, updateData) } // 处理返回的数据 async TranslateReturnProcess(value: TranslateModel.TranslateNowIPCParams, to: string, dstString: string) { switch (value.type) { case TranslateType.REVERSE_PROMPT_TRANSLATE: await this.TranslateProcessReversePrompt(value.bookTaskDetailId, value.reversePromptId, to, dstString) break; case TranslateType.GPT_PROMPT_TRANSLATE: // 这个直接改就行 await this.bookServiceBasic.UpdateBookTaskDetail(value.bookTaskDetailId, { gptPrompt: dstString }) break; default: throw new Error("未知的翻译类型"); } } /** * 翻译 * @param value * @returns */ async TranslateNowReturn(value: TranslateModel.TranslateNowIPCParams[]): Promise { try { // 循环所有的数据,返回翻译结果 let tasks = [] for (let i = 0; i < value.length; i++) { const element = value[i]; tasks.push(async () => { let res = await this.translate.TranslateReturnNow(element) // global.logger.info("断点写出", JSON.stringify(res)) // 单个翻译,将返回的数据写入到原数据中 // 添加一个对返回信息进行处理的函数 let data = res.data // 先将数据进行拼接 let srcString = "" if (element.isSplit) { let dstStrs = [] } else { // 没有拆分的,只有一句 srcString = data.data[0].dst } // 写回数据库 await this.TranslateReturnProcess(element, data.to, srcString); let responseType = ResponseMessageType.REVERSE_PROMPT_TRANSLATE; if (element.type == TranslateType.GPT_PROMPT_TRANSLATE) { responseType = ResponseMessageType.GPT_PROMPT_TRANSLATE } // 做个返回数据 this.sendTranslateReturn(element.windowId, { code: 1, id: element.bookTaskDetailId, type: responseType, data: { progress: i + 1, total: value.length, from: element.from, to: data.to, bookTaskDetailId: element.bookTaskDetailId, reversePromptId: element.reversePromptId, prompt: srcString, promptCN: srcString } }, element.responseMessgeName) }) } let res = await ExecuteConcurrently(tasks, global.config.task_number) // 将翻译后的数据返回,前端进行修改 return successMessage(null, "全部翻译完成", "TranslateService_TranslateNowReturn") } catch (error) { return errorMessage("翻译失败,失败信息如下:" + error.toString(), "TranslateService_TranslateNowReturn") } } }