LaiTool/src/main/Service/Translate/TranslateService.ts

256 lines
9.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
import { Book } from "../../../model/book";
import { ResponseMessageType } from "../../../define/enum/softwareEnum";
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService'
import { isEmpty } from "lodash";
import { ValidateJson } from "../../../define/Tools/validate";
/**
* 翻译实现服务
*/
export class TranslateService {
translate: Translate
bookTaskDetail: BookTaskDetailService;
softwareService: SoftwareService
constructor() {
}
async InitService() {
if (!this.bookTaskDetail) {
this.bookTaskDetail = await BookTaskDetailService.getInstance()
}
if (!this.softwareService) {
this.softwareService = await SoftwareService.getInstance()
}
if (!this.translate) {
this.translate = new Translate()
}
}
// 返回翻译结果。用于前端修改
private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse): void {
let win = global.newWindow[0]
if (windowId) {
win = global.newWindow.filter(item => item.id == windowId)[0];
}
win.win.webContents.send(DEFINE_STRING.BOOK.MAIN_DATA_RETURN, 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<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
await this.InitService()
let translateSetting = undefined as TranslateModel.TranslateModel
let translateSettingString = this.softwareService.GetSoftWarePropertyData('translationSetting');
if (isEmpty(translateSettingString)) {
// 初始化
translateSetting = this.InitialTranslateSetting();
await this.ResetTranslateSetting();
translateSettingString = this.softwareService.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<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
let translateSetting = this.InitialTranslateSetting()
let res = this.softwareService.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<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
let res = this.softwareService.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<void> {
// 开始修改翻译后的数据
let updateData = {} as Book.ReversePrompt
if (to == "zh") {
updateData.promptCN = dstString
} else if (to == "en") {
updateData.prompt = dstString
updateData.promptCN = dstString
}
// 修改数据
this.bookTaskDetail.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;
default:
throw new Error("未知的翻译类型");
}
}
// 翻译
async TranslateNowReturn(value: TranslateModel.TranslateNowIPCParams[]): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
await this.InitService()
// 循环所有的数据,返回翻译结果
for (let i = 0; i < value.length; i++) {
const element = value[i];
let res = await this.translate.TranslateReturnNow(element)
// 单个翻译,将返回的数据写入到原数据中
// 添加一个对返回信息进行处理的函数
let data = res.data
// 先将数据进行拼接
let srcString = ""
if (element.isSplit) {
let dstStrs = []
} else {
// 没有拆分的,只有一句
srcString = data.data[0].dst
}
// 写回数据库
await this.TranslateReturnProcess(element, data.to, srcString);
// 做个返回数据
this.sendTranslateReturn(element.windowId, {
code: 1,
id: element.bookTaskDetailId,
type: ResponseMessageType.PROMPT_TRANSLATE,
data: {
progress: i + 1,
total: value.length,
from: element.from,
to: data.to,
bookTaskDetailId: element.bookTaskDetailId,
reversePromptId: element.reversePromptId,
prompt: srcString,
promptCN: srcString
}
})
}
return successMessage(null, "全部翻译完成", "TranslateService_TranslateNowReturn")
} catch (error) {
return errorMessage("翻译失败,失败信息如下:" + error.toString(), "TranslateService_TranslateNowReturn")
}
}
}