1. 添加英文配音

2. 修复聚合推文 任务没有文件不能删掉
3. 修复聚合推文删除所有的批次任务之后,不能再添加的问题
4. 添加版本更新通知,版本更新内容提醒
5. 添加MJ代理MJ账号设置,可以删除本地的账号和同步云端的账号(主要是状态和禁用原因)
This commit is contained in:
lq1405 2024-10-18 12:39:40 +08:00
parent 224ee47984
commit efa8d3b2a2
41 changed files with 1875 additions and 2963 deletions

1628
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "laitool",
"version": "3.1.5",
"version": "3.1.6",
"description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js",
"author": "laitool.cn",
@ -18,34 +18,29 @@
},
"dependencies": {
"@alicloud/alimt20181012": "^1.2.0",
"@alicloud/openapi-client": "^0.4.12",
"@alicloud/tea-util": "^1.4.9",
"@electron-toolkit/preload": "^3.0.0",
"@electron-toolkit/utils": "^3.0.0",
"@vicons/ionicons5": "^0.12.0",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@volcengine/openapi": "^1.16.0",
"7zip-min": "^1.4.4",
"artplayer": "^5.1.6",
"awesome-js": "^2.0.0",
"axios": "^1.6.5",
"blob-to-buffer": "^1.2.9",
"compressing": "^1.10.0",
"crypto-js": "^4.2.0",
"electron-store": "^9.0.0",
"electron-updater": "^6.1.7",
"fluent-ffmpeg": "^2.1.3",
"form-data": "^4.0.1",
"highlight.js": "^11.9.0",
"install": "^0.13.0",
"jieba-js": "^1.0.2",
"https-proxy-agent": "^7.0.5",
"jsdom": "^24.0.0",
"lodash": "^4.17.21",
"moment-timezone": "^0.5.45",
"music-metadata": "^7.14.0",
"node-edge-tts": "^1.2.3",
"node-gyp": "^10.2.0",
"node-machine-id": "^1.1.12",
"node-pre-gyp": "^0.17.0",
"npm": "^10.7.0",
"paddle": "^1.0.0",
"pinia": "^2.1.7",
"realm": "^12.9.0",
"sharp": "^0.33.2",

Binary file not shown.

Binary file not shown.

View File

@ -2,10 +2,12 @@ import * as image from './image';
import * as common from './common';
import * as file from './file'
import * as validate from './validate';
import * as write from './write';
export {
image,
common,
file,
validate
validate,
write
};

36
src/define/Tools/write.ts Normal file
View File

@ -0,0 +1,36 @@
import { isEmpty } from "lodash";
/**
*
*
* @param text -
* @param simpleSplitChar - 使
* @param specialSplitChat - 使
* @returns
*/
export function FormatWord(text: string, simpleSplitChar?: string, specialSplitChat?: string[],): string[] {
const defaultSimpleSplitChar = '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;';
const defaultSpecialSplitChat = ['.', '*', '?', '+', '^', '$', '[', ']', '(', ')', '{', '}', '|', '\\'];
if (isEmpty(simpleSplitChar)) {
simpleSplitChar = defaultSimpleSplitChar;
}
if (specialSplitChat == null || specialSplitChat.length === 0) {
specialSplitChat = defaultSpecialSplitChat;
}
Array.from(simpleSplitChar).forEach((item) => {
let regex: RegExp;
if (defaultSpecialSplitChat.includes(item)) {
regex = new RegExp('\\' + item, 'g')
} else {
regex = new RegExp(item, 'g')
}
text = text.replace(regex, '\n')
})
let wordArr = text.split('\n')
wordArr = wordArr.filter((item) => item != '' && item != null)
return wordArr
}

View File

@ -39,7 +39,7 @@ export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
accountId: string | null
channelId: string
coreSize: number
guildId: string
guildId: string
enable: boolean // 是否启用
mjBotChannelId: string | null
nijiBotChannelId: string | null
@ -52,6 +52,7 @@ export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
createTime: Date
updateTime: Date
version: string
blockMessage?: string
static schema: ObjectSchema = {
name: 'RemoteMJ',
properties: {
@ -71,7 +72,8 @@ export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
userToken: 'string',
createTime: 'date',
updateTime: 'date',
version: 'string'
version: 'string',
blockMessage: 'string?'
},
// 主键为_id
primaryKey: 'id'

View File

@ -300,6 +300,9 @@ export class MJSettingService extends BaseSoftWareService {
if (remoteMjQuery?.id) {
remoteMjSettings = this.realm.objects('RemoteMJ').filtered('id = $0', remoteMjQuery.id)
}
if (remoteMjQuery?.accountId) {
remoteMjSettings = this.realm.objects('RemoteMJ').filtered('accountId = $0', remoteMjQuery.accountId)
}
let resRemoteMj = Array.from(remoteMjSettings).map((remoteMj) => {
return {
...remoteMj
@ -348,9 +351,12 @@ export class MJSettingService extends BaseSoftWareService {
remoteMjSetting.createTime = new Date()
remoteMjSetting.updateTime = new Date()
remoteMjSetting.version = version
remoteMjSetting.enable = true
remoteMjSetting.remark = global.machineId
if (remoteMjSetting.hasOwnProperty('enable') == false) {
remoteMjSetting.enable = true
}
// 判断当前this.relam 是不是已经处于一个事务中
if (this.realm.isInTransaction) {
this.realm.create('RemoteMJ', remoteMjSetting)

View File

@ -159,6 +159,14 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
if (oldRealm.schemaVersion < 22) {
}
if (oldRealm.schemaVersion < 23) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('RemoteMJ')
for (let software of newSoftwares) {
software.blockMessage = ''
}
})
}
}
export class BaseSoftWareService extends BaseService {
@ -198,7 +206,7 @@ export class BaseSoftWareService extends BaseService {
PresetModel
],
path: dbPath,
schemaVersion: 23, // 当前版本号
schemaVersion: 24, // 当前版本号
migration: migration
}
// 判断当前全局是不是又当前这个

View File

@ -149,4 +149,8 @@ define['serverUrl'] = 'http://lapi.laitool.cn'
define['hkServerUrl'] = 'https://laitool.net/'
define['bakServerUrl'] = 'https://laitool.net/'
define['API'] = 'f85d39ed5a40fd09966f13f12b6cf0f0'
define['lms'] =
process.env.NODE_ENV == 'development' ? 'https://localhost:44362' : 'https://lms.laitool.cn'
export { define }

View File

@ -1,9 +1,13 @@
import { SYSTEM } from "./systemDefineString"
import TASK from "./taskDefineString"
import TTS from "./ttsDefineString"
import SETTING from "./settingDefineString"
export const DEFINE_STRING = {
SYSTEM: SYSTEM,
TASK: TASK,
TTS: TTS,
SETTING: SETTING,
SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE",
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
@ -361,25 +365,6 @@ export const DEFINE_STRING = {
//#endregion
},
SETTING: {
GET_DATA_BY_TYPE_AND_PROPERTY: 'GET_DATA_BY_TYPE_AND_PROPERTY',
SAVE_DATA_BY_TYPE_AND_PROPERTY: 'SAVE_DATA_BY_TYPE_AND_PROPERTY',
DELETE_DATA_BY_TYPE_AND_PROPERTY: 'DELETE_DATA_BY_TYPE_AND_PROPERTY',
GET_SOFTWARE_SETTING: 'GET_SOFTWARE_SETTING',
SAVE_SOFT_WARE_SETTING: 'SAVE_SOFT_WARE_SETTING',
GET_COMPONENT_SIZE: 'GET_COMPONENT_SIZE',
GET_MJ_SETTING_TREE_DATA: 'GET_MJ_SETTING_TREE_DATA',
SAVE_MJ_SETTING_TREE_DATA: 'SAVE_MJ_SETTING_TREE_DATA',
MJ_REMOTE_ACCOUNT_SYNC: 'MJ_REMOTE_ACCOUNT_SYNC',
GET_MJ_SETTING: 'GET_MJ_SETTING',
UPDATE_MJ_SETTING: 'UPDATE_MJ_SETTING',
GET_REMOTE_MJ_SETTINGS: 'GET_REMOTE_MJ_SETTINGS',
ADD_REMOTE_MJ_SETTING: 'ADD_REMOTE_MJ_SETTING',
UPDATE_REMOTE_MJ_SETTING: 'UPDATE_REMOTE_MJ_SETTING',
DELETE_REMOTE_MJ_SETTING: 'DELETE_REMOTE_MJ_SETTING',
GET_WATER_MARK_SETTING: 'GET_WATER_MARK_SETTING',
SAVE_WATER_MARK_SETTING: 'SAVE_WATER_MARK_SETTING'
},
PROMPT: {
GET_SORT_OPTIONS: 'GET_SORT_OPTIONS',
SAVE_PROMPT_SORT_DATA: 'SAVE_PROMPT_SORT_DATA',
@ -399,14 +384,6 @@ export const DEFINE_STRING = {
*/
GET_SCENE_PRESET: "GET_SCENE_PRESET"
},
TTS: {
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
GENERATE_AUDIO: 'GENERATE_AUDIO',
SAVE_TTS_CONFIG: 'SAVE_TTS_CONFIG',
GENERATE_SRT: "GENERATE_SRT",
GET_TTS_HISTORY_DATA: 'GET_TTS_HISTORY_DATA',
DELETE_TTS_HISTORY: 'DELETE_TTS_HISTORY',
},
WRITE: {
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',

View File

@ -0,0 +1,23 @@
const SETTING = {
GET_DATA_BY_TYPE_AND_PROPERTY: 'GET_DATA_BY_TYPE_AND_PROPERTY',
SAVE_DATA_BY_TYPE_AND_PROPERTY: 'SAVE_DATA_BY_TYPE_AND_PROPERTY',
DELETE_DATA_BY_TYPE_AND_PROPERTY: 'DELETE_DATA_BY_TYPE_AND_PROPERTY',
GET_SOFTWARE_SETTING: 'GET_SOFTWARE_SETTING',
SAVE_SOFT_WARE_SETTING: 'SAVE_SOFT_WARE_SETTING',
GET_COMPONENT_SIZE: 'GET_COMPONENT_SIZE',
GET_MJ_SETTING_TREE_DATA: 'GET_MJ_SETTING_TREE_DATA',
SAVE_MJ_SETTING_TREE_DATA: 'SAVE_MJ_SETTING_TREE_DATA',
MJ_REMOTE_ACCOUNT_SYNC: 'MJ_REMOTE_ACCOUNT_SYNC',
GET_MJ_SETTING: 'GET_MJ_SETTING',
UPDATE_MJ_SETTING: 'UPDATE_MJ_SETTING',
GET_REMOTE_MJ_SETTINGS: 'GET_REMOTE_MJ_SETTINGS',
ADD_REMOTE_MJ_SETTING: 'ADD_REMOTE_MJ_SETTING',
UPDATE_REMOTE_MJ_SETTING: 'UPDATE_REMOTE_MJ_SETTING',
DELETE_REMOTE_MJ_SETTING: 'DELETE_REMOTE_MJ_SETTING',
GET_WATER_MARK_SETTING: 'GET_WATER_MARK_SETTING',
SAVE_WATER_MARK_SETTING: 'SAVE_WATER_MARK_SETTING',
/** 获取远程代理服务器的账号信息 */
GET_REMOTE_MJ_SETTINGS_FROM_SERVICE: "GET_REMOTE_MJ_SETTINGS_FROM_SERVICE"
}
export default SETTING

View File

@ -8,5 +8,7 @@ export const SYSTEM = {
/** 获取机器码 */
GET_MACHINE_ID: "GET_MACHINE_ID",
/** 检查机器码状态 */
CHECK_MACHINE_STATUS : "CHECK_MACHINE_STATUS"
CHECK_MACHINE_STATUS: "CHECK_MACHINE_STATUS",
/** 获取软件版本信息,更新信息,首页内容,公告等 */
GET_REMOTE_SYSTEM_INFORMATION: 'GET_REMOTE_SYSTEM_INFORMATION'
}

View File

@ -0,0 +1,19 @@
/** TTS 相关的消息任务 */
const TTS = {
/** 获取TTS配置 */
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
/** 生成配音 */
GENERATE_AUDIO: 'GENERATE_AUDIO',
/** 保存TTS配置 */
SAVE_TTS_CONFIG: 'SAVE_TTS_CONFIG',
/** 生成SRT文件 */
GENERATE_SRT: "GENERATE_SRT",
/** 获取TTS历史数据 */
GET_TTS_HISTORY_DATA: 'GET_TTS_HISTORY_DATA',
/** 删除TTS配音历史记录 */
DELETE_TTS_HISTORY: 'DELETE_TTS_HISTORY',
/** 获取TTS的Options */
GET_TTS_OPTIONS: 'GET_TTS_OPTIONS',
}
export default TTS;

View File

@ -11,6 +11,9 @@ export function GetTTSSelect() {
* edge-tts
*/
export function GetEdgeTTSRole() {
//
return [
{
value: 'zh-CN-XiaoxiaoNeural',

View File

@ -1,19 +1,19 @@
import { PromptIpc } from './promptIpc'
import { SettingIpc } from './settingIpc.js'
import { ImageGenerateIpc } from './imageGenerateIpc.js'
import { WritingIpc } from './writingIpc.js'
import { SettingIpc } from './settingIpc'
import { ImageGenerateIpc } from './imageGenerateIpc'
import { WritingIpc } from './writingIpc'
import { VideoGenerateIpc } from './videoGenerateIpc'
import { TranslateIpc } from './translateIpc.js'
import { GptIpc } from './gptIpc.js'
import { MjIpc } from './mjIpc.js'
import { TranslateIpc } from './translateIpc'
import { GptIpc } from './gptIpc'
import { MjIpc } from './mjIpc'
import { OriginalImageGenerateIpc } from './originalImageGenerateIpc'
import { SdIpc } from './sdIpc.js'
import { MainIpc } from './mainIpc.js'
import { GlobalIpc } from './globalIpc.js'
import { ImageIpc } from './imageIpc.js'
import { SdIpc } from './sdIpc'
import { MainIpc } from './mainIpc'
import { GlobalIpc } from './globalIpc'
import { ImageIpc } from './imageIpc'
import { SystemIpc } from './systemIpc'
import { BookIpc } from './bookIpc'
import { TTSIpc } from './ttsIpc.js'
import { TTSIpc } from './ttsIpc'
import { DBIpc } from './dbIpc'
import { PresetIpc } from './presetIpc'
import { TaskIpc } from './taskIpc'

View File

@ -206,7 +206,7 @@ async function SettingIpc() {
// 创建新的代理MJ信息
ipcMain.handle(
DEFINE_STRING.SETTING.ADD_REMOTE_MJ_SETTING,
async (event, value) => await mjSetting.AddRemoteMJSetting(value)
async (event, value, isRemote) => await mjSetting.AddRemoteMJSetting(value, isRemote)
)
// 修改MJ账号并重连
@ -218,7 +218,13 @@ async function SettingIpc() {
// 删除指定的MJ账号
ipcMain.handle(
DEFINE_STRING.SETTING.DELETE_REMOTE_MJ_SETTING,
async (event, value) => await mjSetting.DeleteRemoteMJSetting(value)
async (event, value, isRemote) => await mjSetting.DeleteRemoteMJSetting(value, isRemote)
)
/** 同步MJ远程代理服务器账户信息 */
ipcMain.handle(
DEFINE_STRING.SETTING.GET_REMOTE_MJ_SETTINGS_FROM_SERVICE,
async (event) => await mjSetting.GetRemoteMJSettingsFromService()
)
//#endregion

View File

@ -26,5 +26,7 @@ function SystemIpc() {
ipcMain.handle(DEFINE_STRING.SYSTEM.GET_MACHINE_ID, async (event) => await systemInfo.GetMachineId())
/** 检查机器码状态 */
ipcMain.handle(DEFINE_STRING.SYSTEM.CHECK_MACHINE_STATUS, async (event, value: string) => await systemInfo.CheckMachineStatus(value))
/** 获取软件版本信息,更新信息,首页内容,公告等 */
ipcMain.handle(DEFINE_STRING.SYSTEM.GET_REMOTE_SYSTEM_INFORMATION, async (event) => await systemInfo.GetRemoteSystemInformation())
}
export { SystemIpc }

View File

@ -37,4 +37,7 @@ export function TTSIpc() {
DEFINE_STRING.TTS.GET_TTS_HISTORY_DATA,
async (event, queryCondition) => await tts.GetTTSHistoryData(queryCondition)
)
ipcMain.handle(
DEFINE_STRING.TTS.GET_TTS_OPTIONS, async (event, key) => await tts.GetTTSOptions(key))
}

View File

@ -181,21 +181,25 @@ export class BookTask {
async AddNewBookTask(addNewBookTask: Book.AddBookTask): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
console.log(addNewBookTask)
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(addNewBookTask.selectBookTask)
let oldBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
bookTaskId: addNewBookTask.selectBookTask
})
if (isEmpty(addNewBookTask.selectBookId)) {
throw new Error("请选择对应的小说")
}
let bookTasks = [] as Book.SelectBookTask[]
let bookTaskDetail = [] as Book.SelectBookTaskDetail[]
let maxNo = await this.bookServiceBasic.GetMaxBookTaskNo(bookTask.bookId)
let maxNo = await this.bookServiceBasic.GetMaxBookTaskNo(addNewBookTask.selectBookId)
for (let i = 0; i < addNewBookTask.count; i++) {
if (addNewBookTask.copyBookTask) {
if (addNewBookTask.copyBookTask && !isEmpty(addNewBookTask.selectBookTask)) {
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(addNewBookTask.selectBookTask)
let oldBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
bookTaskId: addNewBookTask.selectBookTask
})
let { newBookTask, newBookTaskDetails } = await this.AddOneBookTask(bookTask, oldBookTaskDetail, addNewBookTask, maxNo + i)
bookTasks.push(newBookTask)
bookTaskDetail.push(...newBookTaskDetails)
} else {
let newBookTask = this.CopyBookTaskBaseData({ bookId: bookTask.bookId }, addNewBookTask, maxNo + i)
let newBookTask = this.CopyBookTaskBaseData({ bookId: addNewBookTask.selectBookId }, addNewBookTask, maxNo + i)
bookTasks.push(newBookTask);
}
}
@ -236,7 +240,9 @@ export class BookTask {
// 数据库删除完毕,看是删除对应的文件(主要是图片)
let imageFolder = bookTask.imageFolder;
// 整个删掉在重建
await DeleteFolderAllFile(imageFolder)
if (await CheckFileOrDirExist(imageFolder)) {
await DeleteFolderAllFile(imageFolder)
}
await CheckFolderExistsOrCreate(imageFolder)
return successMessage(null, "重置小说数据成功", "BookTask_ReSetBookTask")
} catch (error) {
@ -255,7 +261,9 @@ export class BookTask {
// 先删除每个批次对应的数据,然后删除批次
await this.bookServiceBasic.DeleteBookTaskData(bookTaskId);
// 删除成功,直接把对应的出图文件夹删掉
await DeleteFolderAllFile(imageFolder, true)
if (await CheckFileOrDirExist(imageFolder)) {
await DeleteFolderAllFile(imageFolder, true)
}
return successMessage(null, "删除小说批次数据成功", "BookTask_DeleteBookTask")
} catch (error) {
return errorMessage('删除小说批次数据失败,错误信息如下' + error.toString(), "BookTask_DeleteBookTask");

View File

@ -6,10 +6,49 @@ import { version } from '../../../../package.json';
import { graphics } from 'systeminformation';
import { machineId } from 'node-machine-id';
import axios from 'axios';
import { TaskManager } from '../task/taskManage';
export default class SystemInfo {
constructor() { }
/**
*
* @returns
*/
public async GetRemoteSystemInformation() {
try {
let remoteSysteminformationRes = await axios.get(define.lms + "/lms/LaitoolOptions/GetSimpleOptions/laitoolinfo");
if (remoteSysteminformationRes.data.code != 1) {
throw new Error(remoteSysteminformationRes.data.message)
}
let data = remoteSysteminformationRes.data.data;
let remoteVersionData = data.filter((item: any) => item.key == "LaitoolVersion");
let remoteVersion = remoteVersionData && remoteVersionData.length > 0 && remoteVersionData[0].value ? remoteVersionData[0].value : version;
let remoteHomePageData = data.filter((item: any) => item.key == "LaitoolHomePage");
let remoteHomePage = remoteHomePageData && remoteHomePageData.length > 0 && remoteHomePageData[0].value ? remoteHomePageData[0].value : '';
let remoteNoticeData = data.filter((item: any) => item.key == "LaitoolNotice");
let remoteNotice = remoteNoticeData && remoteNoticeData.length > 0 && remoteNoticeData[0].value ? remoteNoticeData[0].value : '';
let remoteUpdateContentData = data.filter((item: any) => item.key == "LaitoolUpdateContent");
let remoteUpdateContent = remoteUpdateContentData && remoteUpdateContentData.length > 0 && remoteUpdateContentData[0].value ? remoteUpdateContentData[0].value : '';
// 开始返回数据
return successMessage({
remoteVersion,
remoteHomePage,
remoteNotice,
remoteUpdateContent
}, '获取软件信息成功', 'SystemIpc_GET_SYSTEM_INFORMATION')
} catch (error) {
return errorMessage('获取软件信息错误,错误信息如下:' + error.message, 'SystemIpc_GET_SYSTEM_INFORMATION')
}
}
/**
*
* @returns
@ -26,7 +65,7 @@ export default class SystemInfo {
}
// 读取配置文件
let systemConfig = JSON.parse(await fs.promises.readFile(systemConfigPath, 'utf-8')) as SystemConfig.SystemConfig;
if (systemConfig && systemConfig.gpu && systemConfig.gpu.name && systemConfig.gpu.updateTime) {
const currentDate = new Date(systemConfig.gpu.updateTime);
const nextDate = new Date(currentDate);
@ -36,7 +75,7 @@ export default class SystemInfo {
return successMessage(version + ' ' + (global.gpu?.name ? global.gpu.name : ''), '获取成功')
}
}
// 获取当前电脑的显卡信息
let da = await graphics()
for (let i = 0; i < da.controllers.length; i++) {

View File

@ -7,11 +7,13 @@ import { isEmpty } from 'lodash'
import { ValidateJson } from '../../define/Tools/validate'
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, DeleteFolderAllFile } from '../../define/Tools/file'
import { TTSSelectModel } from '../../define/enum/tts'
const { EdgeTTS } = require('node-edge-tts')
import { EdgeTTS } from 'node-edge-tts'
const { v4: uuidv4 } = require('uuid')
import { TTSService } from '../../define/db/tts/ttsService'
import { tts } from '../../model/tts'
import { GeneralResponse } from '../../model/generalResponse'
import axios from 'axios'
import { GetEdgeTTSRole } from '../../define/tts/ttsDefine'
export class TTS {
softService: SoftwareService
@ -34,6 +36,41 @@ export class TTS {
//#region 设置相关
/**
* TTS配置选项
*
* @param {string} key - TTS配置的键值
* @returns {Promise<any>} TTS配置选项的Promise对象
*
* @throws {Error}
*
* @example
* ```typescript
* const options = await GetTTSOptions('someKey');
* console.log(options);
* ```
*/
async GetTTSOptions(key: string): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
try {
// 开始请求数据
let res = await axios.get(define.lms + '/lms/LaitoolOptions/GetSimpleOptions/ttsrole');
if (res.data.code != 1) {
throw new Error(res.data.message)
}
let data = res.data.data.filter(item => item.key == "EdgeTTsRoles")
if (data.length != 1) {
throw new Error("获取TTS角色配置失败")
}
if (isEmpty(data[0].value) || !ValidateJson(data[0].value)) {
return successMessage(GetEdgeTTSRole(), "获取远程配置失败,获取默认配音角色", "TTS_GetTTSCOnfig"); // 使用默认值
}
// 返回远程值
return successMessage(JSON.parse(data[0].value), '获取TTS配置成功', 'TTS_GetTTSCOnfig')
} catch (error) {
return errorMessage('获取TTS配置失败错误信息如下' + error.toString(), 'TTS_GetTTSCOnfig')
}
}
/**
* TTS设置
*/
@ -166,7 +203,7 @@ export class TTS {
saveSubtitles: true,
pitch: `${edgeTTS.pitch}%`,
rate: `${edgeTTS.rate}%`,
volumn: `${edgeTTS.volumn}%`
volume: `${edgeTTS.volumn}%`
})
let ttsRes = await tts.ttsPromise(text, mp3Path)
console.log(ttsRes)

View File

@ -11,7 +11,7 @@ import { AsyncQueue } from './quene'
import { DEFINE_STRING } from '../define/define_string'
import { Tools } from './tools.js'
import { ImageGenerate } from './ReverseManage/imageGenerate.js'
import { Setting } from './setting/setting.js'
import { Setting } from './setting/setting'
import { has, isEmpty } from 'lodash'
import { AutoSync } from './setting/autoSync.js'
import { TaskManager } from './Service/task/taskManage'
@ -95,6 +95,7 @@ async function createWindow(hash = 'ShowMessage', data, url = null) {
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/#/' + hash)
// mainWindow.webContents.openDevTools()
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
} else {
if (hash != '') {
mainWindow.loadURL(`file://${path.join(__dirname, '../renderer/index.html')}#/${hash}`)

View File

@ -8,6 +8,85 @@ const { v4: uuidv4 } = require('uuid')
export class MJSetting {
constructor() {}
/**
* 同步远程代理服务器中的MJ账号信息
*/
async GetRemoteMJSettingsFromService() {
try {
let url = define.remotemj_api + 'mj/account/query'
let res = await axios.post(
url,
{ remark: global.machineId, current: 1, pageNumber: 0, pageSize: 30 },
{ headers: { 'mj-api-secret': define.API } }
)
console.log('GetRemoteMJSettingsFromService', res)
if (res.status != 200) {
throw new Error(res.statusText)
}
if (!res.data || !res.data.content) {
throw new Error('远程服务器返回数据格式错误')
}
let content = res.data.content
let remoteMjSetting = await this.GetRemoteMJSettings()
if (remoteMjSetting.code == 0) {
throw new Error(remoteMjSetting.message)
}
let remoteIds = remoteMjSetting.data.map((item) => item.id)
for (let i = 0; i < remoteIds.length; i++) {
const element = remoteIds[i]
let deleteRes = await this.DeleteRemoteMJSetting(element, false)
if (deleteRes.code == 0) {
throw new Error(deleteRes.message)
}
}
if (content.length <= 0) {
// 没有数据,删除当前的所有的配置
} else {
// 先将所有的数据删除,再添加
for (let i = 0; i < content.length; i++) {
const element = content[i]
let addRes = await this.AddRemoteMJSetting(
{
channelId: element.channelId,
guildId: element.guildId,
userToken: element.userToken,
coreSize: element.coreSize,
queueSize: element.queueSize,
timeoutMinutes: element.timeoutMinutes,
userAgent: element.userAgent,
remark: element.remark,
enable: element.enable,
remixAutoSubmit: element.remixAutoSubmit,
mjBotChannelId: element.mjBotChannelId,
nijiBotChannelId: element.nijiBotChannelId,
accountId: element.id,
blockMessage: element.properties.disabledReason
},
false
)
if (addRes.code == 0) {
throw new Error(addRes.message)
}
}
}
return successMessage(
null,
'同步远程代理服务器中的MJ账号信息成功',
'MJSetting_GetRemoteMJSettingsFromService'
)
} catch (error) {
return errorMessage(
'同步远程代理服务器中的MJ账号信息错误详细错误信息如下' + error.toString(),
'MJSetting_GetRemoteMJSettingsFromService'
)
}
}
/**
* 获取MJ的基础设置数据
*/
@ -94,7 +173,7 @@ export class MJSetting {
* 创建新的代理MJ信息
* @param {*} value
*/
async AddRemoteMJSetting(value) {
async AddRemoteMJSetting(value, isRemote) {
try {
// 先检查必填字段
console.log(value)
@ -134,22 +213,34 @@ export class MJSetting {
if (value.nijiBotChannelId) {
remoteData.nijiBotChannelId = value.nijiBotChannelId
}
// 添加账号
let accountRes = await axios.post(createUrl, remoteData, {
headers: {
'mj-api-secret': define.API
}
})
console.log(accountRes)
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description)
if (value.accountId) {
remoteData.accountId = value.accountId
}
if (!isEmpty(value.blockMessage)) {
remoteData.blockMessage = value.blockMessage
}
if (value.hasOwnProperty('enable')) {
remoteData.enable = value.enable
}
if (isRemote) {
// 添加账号
let accountRes = await axios.post(createUrl, remoteData, {
headers: {
'mj-api-secret': define.API
}
})
console.log(accountRes)
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description)
}
// 添加成功,修改数据,将数据返回 (服务器添加成功,开始在本地数据库添加)s
let accountId = accountRes.data.result
remoteData.accountId = accountId
}
// 添加成功,修改数据,将数据返回 (服务器添加成功,开始在本地数据库添加)s
let accountId = accountRes.data.result
remoteData.accountId = accountId
remoteData.remixAutoSubmit = false
let _mjSettingService = await MJSettingService.getInstance()
@ -248,7 +339,7 @@ export class MJSetting {
* 删除指定的MJ账号
* @param {*} id 数据库中存放的ID
*/
async DeleteRemoteMJSetting(id) {
async DeleteRemoteMJSetting(id, isRemote) {
try {
// 先检查必填字段
if (isEmpty(id)) {
@ -261,24 +352,27 @@ export class MJSetting {
throw new Error('没有要删除的数据')
}
// 开始删除
let deleteData = deleteConfig.data[0]
let deleteUrl = define.remotemj_api + `mj/account/${deleteData.accountId}/delete`
let accountRes = await axios.delete(deleteUrl, {
headers: {
'mj-api-secret': define.API
if (isRemote) {
// 开始删除
let deleteData = deleteConfig.data[0]
let deleteUrl = define.remotemj_api + `mj/account/${deleteData.accountId}/delete`
let accountRes = await axios.delete(deleteUrl, {
headers: {
'mj-api-secret': define.API
}
})
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description)
}
})
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description)
}
// 删除本地数据
// 删除成功,修改数据
let save_res = _mjSetting.DeleteRemoteMJSetting(id)
if (save_res.code == 0) {
throw new Error(save_res.message)
}
return successMessage(deleteData, 'MJ账号删除成功', 'MJSetting_DeleteRemoteMJSetting')
return successMessage(null, 'MJ账号删除成功', 'MJSetting_DeleteRemoteMJSetting')
} catch (error) {
return errorMessage(
'删除指定的MJ账号错误详细错误信息如下' + error.toString(),

1
src/model/book.d.ts vendored
View File

@ -84,6 +84,7 @@ declare namespace Book {
suffixPrompt?: string // 后缀提示词
selectBookTask?: string // 选择的旧的小说任务
selectTaskDataCategory?: string[] // 选择复制的数据类型
selectBookId: string // 选择的小说ID
}
// 字幕相关

8
src/model/tts.d.ts vendored
View File

@ -27,4 +27,12 @@ declare namespace tts {
ttsCount: number
}
/** TTS 配音角色列表 */
type TTSRoleName = {
gender: string | "Male" | 'Female'
label: string
lang: string
value: string
}
}

View File

@ -1,19 +1,19 @@
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
import { DEFINE_STRING } from '../define/define_string'
import { discord } from './discord.js'
import { mj } from './mj.js'
import { discord } from './discord'
import { mj } from './mj'
import { sd } from './sd'
import { img } from './img.js'
import { img } from './img'
import { system } from './system'
import { setting } from './setting.js'
import { prompt } from './prompt.js'
import { setting } from './setting'
import { prompt } from './prompt'
import { book } from './book'
import { tts } from './tts.js'
import { write } from './write.js'
import { gpt } from './gpt.js'
import { tts } from './tts'
import { write } from './write'
import { gpt } from './gpt'
import { db } from './db'
import { translate } from './translate.js'
import { translate } from './translate'
import { preset } from './preset'
import { task } from './task'
// Custom APIs for renderer

View File

@ -50,16 +50,19 @@ const setting = {
await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_REMOTE_MJ_SETTINGS),
// 添加代理模式的MJ账号
AddRemoteMJSetting: async (value) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.ADD_REMOTE_MJ_SETTING, value),
AddRemoteMJSetting: async (value, isRemote) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.ADD_REMOTE_MJ_SETTING, value, isRemote),
// 修改并重连MJ的账号
UpdateRemoteMJSetting: async (value) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_REMOTE_MJ_SETTING, value),
// 删除指定的MJ账号
DeleteRemoteMJSetting: async (value) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.DELETE_REMOTE_MJ_SETTING, value),
DeleteRemoteMJSetting: async (value: string, isRemote: boolean) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.DELETE_REMOTE_MJ_SETTING, value, isRemote),
/** 同步代理服务器的账号信息 */
GetRemoteMJSettingsFromService: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_REMOTE_MJ_SETTINGS_FROM_SERVICE),
//#endregion

View File

@ -12,8 +12,9 @@ const system = {
/** 获取系统的机器码 */
GetMachineId: () => ipcRenderer.invoke(DEFINE_STRING.SYSTEM.GET_MACHINE_ID),
/** 检查机器码状态 */
CheckMachineStatus: (value: string) => ipcRenderer.invoke(DEFINE_STRING.SYSTEM.CHECK_MACHINE_STATUS, value)
CheckMachineStatus: (value: string) => ipcRenderer.invoke(DEFINE_STRING.SYSTEM.CHECK_MACHINE_STATUS, value),
/** 获取软件版本信息,更新信息,首页内容,公告等 */
GetRemoteSystemInformation : () => ipcRenderer.invoke(DEFINE_STRING.SYSTEM.GET_REMOTE_SYSTEM_INFORMATION)
}
export { system }

View File

@ -20,6 +20,9 @@ const tts = {
// 获取生成音频的历史记录
GetTTSHistoryData: async (queryCondition) =>
await ipcRenderer.invoke(DEFINE_STRING.TTS.GET_TTS_HISTORY_DATA, queryCondition)
await ipcRenderer.invoke(DEFINE_STRING.TTS.GET_TTS_HISTORY_DATA, queryCondition),
GetTTSOptions: async (key: string) => await ipcRenderer.invoke(DEFINE_STRING.TTS.GET_TTS_OPTIONS, key)
}
export { tts }

View File

@ -90,7 +90,8 @@ let creatObj = ref({
selectBookTask: undefined,
selectTaskDataCategory: [],
prefixPrompt: '',
suffixPrompt: ''
suffixPrompt: '',
selectBookId: reverseManageStore.selectBook.id
})
let bookTaskOptions = ref([])
let groupData = ref([

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,77 @@
<template>
<div style="width: 100%; height: auto;">
<!-- <div style="display: flex; justify-content: center;">
<n-image width="200" height="250" src="http://qiniuyun.upsurging.xyz/LAI/1280X1280.PNG" preview-disabled />
<n-image width="250" style="margin-left: 100px;"
src="http://qiniuyun.upsurging.xyz/LAI/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20240427225845.png"
preview-disabled />
</div> -->
<div style="font-size: 15px ;display: flex; justify-content: center;">
<div id="showmessage"></div>
</div>
</div>
<div style="width: 100%; height: 100%">
<div
id="showmessage"
style="font-size: 15px; display: flex; justify-content: center; width: 100%; height: 100%"
></div>
</div>
</template>
<script>
import { ref, h, onMounted, defineComponent, onUnmounted, toRaw } from "vue"
import { NImage, useMessage } from "naive-ui";
import { DEFINE_STRING } from "../../../../define/define_string";
<script setup>
import { onMounted } from 'vue'
import { useMessage, useNotification } from 'naive-ui'
import { version } from '../../../../../package.json'
import { isEmpty } from 'lodash'
export default defineComponent({
components: {
NImage
},
setup() {
onMounted(async () => {
await window.api.GetShowMessage((value) => {
if (value.code == 0) {
return;
}
let parser = new DOMParser();
let html = parser.parseFromString(value.data, 'text/html');
let div = document.getElementById("showmessage");
let message = useMessage()
const notification = useNotification()
div.innerHTML = value.data.shareInfo.note_list[0].html_content
})
})
async function GetRemoteSystemInformation() {
let res = await window.system.GetRemoteSystemInformation()
if (res.code == 0) {
message.error(res.message)
return
}
return {
}
if (!isEmpty(res.data.remoteHomePage)) {
const showMessageDiv = document.getElementById('showmessage')
const remoteHomePage = res.data.remoteHomePage
if (remoteHomePage.startsWith('http://') || remoteHomePage.startsWith('https://')) {
const iframe = document.createElement('iframe')
iframe.src = remoteHomePage
iframe.style.width = '100%'
iframe.style.border = 'none'
iframe.style.padding = '0'
iframe.style.height = '98vh' // Adjust the height as needed
showMessageDiv.innerHTML = ''
showMessageDiv.appendChild(iframe)
} else {
showMessageDiv.innerHTML = remoteHomePage
}
}
//
if (res.data.remoteVersion > version) {
notification.warning({
title: '更新提醒!',
content: `当前版本为 ${version} ,最新版本为 ${res.data.remoteVersion} ,请及时更新!`,
keepAliveOnHover: true
})
}
//
if (res.data.remoteVersion > version && !isEmpty(res.data.remoteUpdateContent)) {
notification.info({
title: '更新内容!',
content: res.data.remoteUpdateContent,
keepAliveOnHover: true
})
}
}
onMounted(async () => {
//
await GetRemoteSystemInformation()
// await window.api.GetShowMessage((value) => {
// if (value.code == 0) {
// return
// }
// let parser = new DOMParser()
// let html = parser.parseFromString(value.data, 'text/html')
// let div = document.getElementById('showmessage')
// div.innerHTML = value.data.shareInfo.note_list[0].html_content
// })
})
</script>
</script>

View File

@ -1,194 +1,229 @@
<template>
<div id="AddMultiRemoteMj" style="overflow-y: auto">
<div style="margin-bottom: 5px">
<n-button type="info" @click="ManageAccount(null)">新增账号</n-button>
<n-spin :show="spinning">
<div id="AddMultiRemoteMj" style="overflow-y: auto">
<div style="margin-bottom: 5px">
<n-button type="info" @click="ManageAccount(null)">新增账号</n-button>
<n-button type="info" style="margin-left: 10px" @click="GetRemoteMJSettingsFromService()"
>同步服务器帐号信息</n-button
>
</div>
<n-data-table :data="remoteMjSetting" :columns="columns" :max-height="maxHeight">
</n-data-table>
</div>
<n-data-table :data="remoteMjSetting" :columns="columns" :max-height="maxHeight">
</n-data-table>
</div>
<template #description> 同步数据中 </template>
</n-spin>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
import {
useMessage,
NDataTable,
NButton,
NInput,
NInputNumber,
NForm,
NFormItem,
useDialog,
NTag
} from 'naive-ui'
<script setup>
import { ref, onMounted, h } from 'vue'
import { useMessage, NDataTable, NButton, useDialog, NTag, NSpin } from 'naive-ui'
import { useSettingStore } from '../../../../../stores/setting'
import ManageRemoteMjAccount from './ManageRemoteMjAccount.vue'
import { isEmpty } from 'lodash'
export default defineComponent({
components: {
NDataTable,
NButton,
NInput,
NInputNumber,
NForm,
NFormItem,
NTag
},
props: ['height'],
setup(props) {
let message = useMessage()
let dialog = useDialog()
let maxHeight = ref(props.height - 150)
let remoteMjSetting = ref([])
let settingStore = useSettingStore()
let props = defineProps({
height: {
type: Number,
default: 500
}
})
let message = useMessage()
let dialog = useDialog()
let maxHeight = ref(props.height - 150)
let remoteMjSetting = ref([])
let settingStore = useSettingStore()
let spinning = ref(false)
onMounted(async () => {
document.getElementById('AddMultiRemoteMj').style.height = props.height - 60 + 'px'
async function GetRemoteMJSettingsFromService() {
spinning.value = true
try {
let remoteMjSettingRes = await window.setting.GetRemoteMJSettingsFromService()
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
return
}
message.success('同步服务器帐号信息成功')
//
let res = await window.setting.GetRemoteMJSettings()
if (res.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = res.data
}
remoteMjSetting.value = res.data
spinning.value = false
} catch (error) {
} finally {
spinning.value = false
}
}
let columns = [
{
title: '服务器ID',
key: 'guildId'
},
{
title: '频道ID',
key: 'channelId'
},
{
title: '状态',
key: 'enable',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px'
},
type: (() => (row.enable ? 'success' : 'error'))(),
bordered: false
},
{
default: () => (row.enable ? '启用' : '禁用')
}
)
}
},
{
title: 'MJ私信ID',
key: 'mjBotChannelId'
},
{
title: 'NIJI私信ID',
key: 'nijiBotChannelId'
},
{
title: '禁用原因',
key: 'blockMessage'
},
{
title: '操作',
key: 'action',
render(row) {
return h('div', {}, [
h(
NButton,
{
size: 'tiny',
type: 'info',
style: 'margin-left: 5px;margin-bottom: 5px',
onClick: () => ManageAccount(row)
},
{ default: () => '编辑并同步' }
),
h(
NButton,
{
size: 'tiny',
type: 'error',
style: 'margin-left: 5px;margin-bottom: 5px',
onClick: () => DeleteAccount(row, false)
},
{ default: () => '删除账号(本地)' }
),
h(
NButton,
{
size: 'tiny',
type: 'error',
style: 'margin-left: 5px;margin-bottom: 5px',
onClick: () => DeleteAccount(row, true)
},
{ default: () => '删除账号(服务器)' }
)
])
}
}
]
onMounted(async () => {
document.getElementById('AddMultiRemoteMj').style.height = props.height - 60 + 'px'
spinning.value = true
try {
let res = await window.setting.GetRemoteMJSettings()
console.log(res)
if (res.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = res.data
}
} catch (error) {
message.error('获取代理MJ配置失败: ' + error.toString())
} finally {
spinning.value = false
}
})
/**
* 添加和编辑账号
*/
async function ManageAccount(remote = null) {
if (remote == null) {
settingStore.ResetActionRemoteMJ()
} else {
//
settingStore.actionRemoteMJ = remote
}
//
let dW = 800
let dH = 600
dialog.create({
showIcon: false,
title: '添加MJ账号',
content: () => h(ManageRemoteMjAccount, {}),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false,
onClose: async () => {
//
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = remoteMjSettingRes.data
}
})
settingStore.ResetActionRemoteMJ()
}
})
}
/**
* 添加和编辑账号
*/
async function ManageAccount(remote = null) {
if (remote == null) {
settingStore.ResetActionRemoteMJ()
} else {
//
settingStore.actionRemoteMJ = remote
/**
* 删除指定的账号
* @param row 数据
*/
async function DeleteAccount(row, isRemote) {
dialog.warning({
title: '删除账号',
content: isRemote
? '确定删除该账号吗?会将代理模式的服务器的数据一起删除,请确认操作!'
: '确定删除账号信息?该操作只会删除本地的,并不会对代理服务器数据产生影响!',
positiveText: '确认',
negativeText: '取消',
onPositiveClick: async () => {
if (isEmpty(row.accountId)) {
message.error('删除账号失败,错误消息如下:' + '账号ID为空')
return
}
let deleteRes = await window.setting.DeleteRemoteMJSetting(row.id, isRemote)
if (deleteRes.code == 0) {
message.error('删除账号失败,错误消息如下:' + deleteRes.message)
return
}
message.success('删除账号成功')
//
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = remoteMjSettingRes.data
}
//
let dW = 800
let dH = 600
dialog.create({
showIcon: false,
title: '添加MJ账号',
content: () => h(ManageRemoteMjAccount, {}),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false,
onClose: async () => {
//
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = remoteMjSettingRes.data
}
settingStore.ResetActionRemoteMJ()
}
})
}
/**
* 删除指定的账号
* @param row 数据
*/
async function DeleteAccount(row) {
dialog.warning({
title: '删除账号',
content: '确定删除该账号吗?',
positiveText: '确认',
negativeText: '取消',
onPositiveClick: async () => {
if (isEmpty(row.accountId)) {
message.error('删除账号失败,错误消息如下:' + '账号ID为空')
return
}
let deleteRes = await window.setting.DeleteRemoteMJSetting(row.id)
if (deleteRes.code == 0) {
message.error('删除账号失败,错误消息如下:' + deleteRes.message)
return
}
message.success('删除账号成功')
//
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
remoteMjSetting.value = remoteMjSettingRes.data
}
}
})
}
return {
remoteMjSetting,
maxHeight,
ManageAccount,
settingStore,
columns: [
{
title: '服务器ID',
key: 'guildId'
},
{
title: '频道ID',
key: 'channelId'
},
{
title: '状态',
key: 'enable',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px'
},
type: (() => (row.enable ? 'success' : 'error'))(),
bordered: false
},
{
default: () => (row.enable ? '启用' : '禁用')
}
)
}
},
{
title: 'MJ私信ID',
key: 'mjBotChannelId'
},
{
title: 'NIJI私信ID',
key: 'nijiBotChannelId'
},
{
title: '操作',
key: 'action',
render(row) {
return h('div', {}, [
h(
NButton,
{
size: 'small',
type: 'info',
style: 'margin-left: 5px',
onClick: () => ManageAccount(row)
},
{ default: () => '编辑并同步' }
),
h(
NButton,
{
size: 'small',
type: 'error',
style: 'margin-left: 5px',
onClick: () => DeleteAccount(row)
},
{ default: () => '删除账号' }
)
])
}
}
]
}
}
})
})
}
</script>

View File

@ -158,7 +158,7 @@ export default defineComponent({
message.success('更新账号成功')
} else {
//
let res = await window.setting.AddRemoteMJSetting(toRaw(settingStore.actionRemoteMJ))
let res = await window.setting.AddRemoteMJSetting(toRaw(settingStore.actionRemoteMJ),true)
loading.value = false
if (res.code == 0) {
message.error('创建账号失败,错误消息如下:' + res.message)

View File

@ -100,7 +100,7 @@
</n-card>
<n-card title="代理模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-button type="info" @click="AddMultiMjAccount">账号管理</n-button>
<n-button type="info" @click="AddMultiMjAccount()">账号管理</n-button>
</n-card>
<n-card title="浏览器模式设置" hoverable style="margin-top: 10px; min-width: 850px">
@ -154,7 +154,7 @@
</div>
</template>
<script>
<script setup>
import { defineComponent, ref, onMounted, computed, toRaw, h } from 'vue'
import {
NButton,
@ -178,384 +178,346 @@ import { Reload } from '@vicons/ionicons5'
import { isEmpty, max, min } from 'lodash'
import { MJImageType } from '../../../../define/enum/mjEnum'
import AddMultiRemoteMj from './Components/AddMultiRemoteMj.vue'
export default defineComponent({
components: {
NButton,
NDataTable,
NForm,
NFormItem,
NInput,
NDivider,
NCheckbox,
NSelect,
NTooltip,
NIcon,
Reload,
NInputNumber,
NCard,
NSpin
let message = useMessage()
let dialog = useDialog()
let sampleRef = ref(null)
let select_robot_options = ref([
{
label: 'MJ',
value: 'mj'
},
setup() {
let message = useMessage()
let dialog = useDialog()
let sampleRef = ref(null)
let select_robot_options = ref([
{
label: 'MJ',
value: 'mj'
},
{
label: 'NIJI',
value: 'niji'
}
])
{
label: 'NIJI',
value: 'niji'
}
])
let mj_speed_options = ref([
{
label: 'RELAXED',
value: 'relaxed'
},
{
label: 'FAST',
value: 'fast'
}
])
let mj_speed_options = ref([
{
label: 'RELAXED',
value: 'relaxed'
},
{
label: 'FAST',
value: 'fast'
}
])
let mjSetting = ref({
id: null,
imageModel: null,
imageScale: null,
imageSuffix: null,
requestModel: null,
type: null,
selectRobot: null,
spaceTime: 6,
taskCount: 3,
createTime: null,
updateTime: null,
version: null,
remoteSetting: {
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 6,
remark: null, //
remixAutoSubmit: false,
timeoutMinutes: 6,
userAgent: null,
userToken: null
},
apiSetting: {
id: null,
mjApiUrl: null,
mjSpeed: null,
apiKey: null
},
browserSetting: {
id: null,
serviceId: null,
channelId: null,
mjBotId: null,
nijBotId: null,
token: null,
userAgent: null,
userAgentCustom: false
}
})
let image_scale_options = ref([])
let image_model_options = ref([])
let tmp_image_model_options = []
let request_model_options = ref([])
let mj_api_options = ref([])
let computedSuffix = () => {
let text = image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageModel
})
if (text == -1) {
return
}
let sc = image_scale_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageScale
})
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
mjSetting.value.imageSuffix = dd
return dd
}
//
async function InitData() {
//
let res = await window.setting.GetMJSettingTreeData()
if (res.code == 0) {
message.error(res.message)
return
}
if (!res.data.apiSetting) {
delete res.data.apiSetting
}
if (!res.data.remoteSetting) {
delete res.data.remoteSetting
}
if (!res.data.browserSetting) {
delete res.data.browserSetting
}
mjSetting.value = Object.assign(mjSetting.value, res.data)
console.log(res)
await window.mj.GetMJImageScale((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
image_scale_options.value = value.data
if (image_scale_options.value.length > 0 && mjSetting.value.imageScale == null) {
mjSetting.value.imageScale = image_scale_options.value[0].value
}
})
await window.mj.GetMJImageRobotModel((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
image_model_options.value = value.data
tmp_image_model_options = value.data
if (image_model_options.value.length > 0 && mjSetting.value.imageModel == null) {
mjSetting.value.imageModel = image_model_options.value[0].value
}
})
await window.mj.GetMJGenerateCategory((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
request_model_options.value = value.data.filter((item) => !item.disable)
if (request_model_options.value.length > 0 && mjSetting.value.requestModel == null) {
mjSetting.value.requestModel = request_model_options.value[0].value
}
})
await window.api.getGptBusinessOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
mj_api_options.value = value.data.filter((item) => item.mj_url)
if (mj_api_options.value.length > 0 && mjSetting.value.apiSetting.mjApiUrl == null) {
mjSetting.value.apiSetting.mjApiUrl = mj_api_options.value[0].value
}
})
}
onMounted(async () => {
//
window.api.setEventListen([DEFINE_STRING.DISCORD.OPERATE_REFRASH_DISCORD_URL], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
//
console.log(value)
if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.URL) {
mjSetting.value.browserSetting.serviceId = value.data.serviceID
mjSetting.value.browserSetting.channelId = value.data.channelID
} else if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.TOKEN) {
mjSetting.value.browserSetting.token = value.data.authorization
if (!mjSetting.value.browserSetting.userAgentCustom) {
mjSetting.value.browserSetting.userAgent = value.data.userAgent
}
} else {
message.error('未知的数据类型')
}
})
await InitData()
if (mjSetting.value.apiSetting.mjSpeed == null) {
mjSetting.value.apiSetting.mjSpeed = mj_speed_options.value[0].value
}
})
/**
* 打开discord窗口
*/
async function OpenDiscordWindow() {
await window.api.OpenDiscordWindow((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
})
}
//
let sampleRules = {
imageModel: [{ required: true, message: '请选择机器人模型', trigger: 'blur' }],
imageScale: [{ required: true, message: '请选择生图尺寸', trigger: 'blur' }],
requestModel: [{ required: true, message: '请选择出图模式', trigger: 'blur' }],
selectRobot: [{ required: true, message: '请选择生图机器人', trigger: 'blur' }]
}
/**
* 保存MJ配置
*/
async function SaveMjSetting(e) {
//
e.preventDefault()
sampleRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
// mjSetting.value.imageSuffix = image_suffix.value
//
let request_model = mjSetting.value.requestModel
if (request_model == MJImageType.API_MJ) {
// API
if (
mjSetting.value.apiSetting == null ||
mjSetting.value.apiSetting.mjApiUrl == null ||
mjSetting.value.apiSetting.mjSpeed == null ||
mjSetting.value.apiSetting.apiKey == null
) {
message.error('请检查API模式设置的必填字段')
return
}
}
if (request_model == MJImageType.REMOTE_MJ) {
//
let remoteMjRes = await window.setting.GetRemoteMJSettings()
if (remoteMjRes.code == 0) {
message.error('获取代理MJ配置失败')
return
}
if (remoteMjRes.data.length <= 0) {
message.error('请先添加代理模式的配置')
return
}
}
if (request_model == MJImageType.BROWSER_MJ) {
//
if (
mjSetting.value.browserSetting == null ||
mjSetting.value.browserSetting.serviceId == null ||
mjSetting.value.browserSetting.channelId == null ||
mjSetting.value.browserSetting.token == null ||
mjSetting.value.browserSetting.userAgent == null
) {
message.error('请检查浏览器模式设置的必填字段')
return
}
}
//
let res = await window.setting.SaveMJSettingTreeData(toRaw(mjSetting.value))
if (res.code == 0) {
window.api.showGlobalMessageDialog({ code: 0, message: res.message })
return
}
mjSetting.value = res.data
//
if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) {
window.api.showGlobalMessageDialog({
code: 1,
message: `数据保存成功,当前模式为代理模式`
})
} else {
window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' })
}
})
}
/**
* 更新选择的机器人时触发的方法
*/
async function UpdateSelectRobot(value) {
//
image_model_options.value = tmp_image_model_options.filter((item) => {
return item.type == value
})
//
if (
image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageModel
}) == -1
) {
mjSetting.value.imageModel =
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
}
//
mjSetting.value.imageSuffix = computedSuffix()
}
/**
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = mj_api_options.value.filter(
(item) => item.value == mjSetting.value.apiSetting.mjApiUrl
)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
}
let buy_url = tmp_gb[0].buy_url
if (isEmpty(buy_url)) {
message.error('当前选择的服务商没有购买地址!')
} else {
window.api.openGptBuyUrl(buy_url)
}
}
/**
* 添加多个账号这样可以同时跑多个账号
*/
async function AddMultiMjAccount() {
//
let dW = window.innerWidth * 0.9
let dH = window.innerHeight * 0.9
dialog.create({
showIcon: false,
title: '管理代理模式MJ账号',
content: () => h(AddMultiRemoteMj, { height: dH }),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false
})
}
return {
OpenDiscordWindow,
mjSetting,
select_robot_options,
SaveMjSetting,
sampleRef,
image_scale_options,
image_model_options,
UpdateSelectRobot,
request_model_options,
mj_api_options,
mj_speed_options,
openGptBuyUrl,
sampleRules,
AddMultiMjAccount
}
let mjSetting = ref({
id: null,
imageModel: null,
imageScale: null,
imageSuffix: null,
requestModel: null,
type: null,
selectRobot: null,
spaceTime: 6,
taskCount: 3,
createTime: null,
updateTime: null,
version: null,
remoteSetting: {
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 6,
remark: null, //
remixAutoSubmit: false,
timeoutMinutes: 6,
userAgent: null,
userToken: null
},
apiSetting: {
id: null,
mjApiUrl: null,
mjSpeed: null,
apiKey: null
},
browserSetting: {
id: null,
serviceId: null,
channelId: null,
mjBotId: null,
nijBotId: null,
token: null,
userAgent: null,
userAgentCustom: false
}
})
let image_scale_options = ref([])
let image_model_options = ref([])
let tmp_image_model_options = []
let request_model_options = ref([])
let mj_api_options = ref([])
let computedSuffix = () => {
let text = image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageModel
})
if (text == -1) {
return
}
let sc = image_scale_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageScale
})
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
mjSetting.value.imageSuffix = dd
return dd
}
//
async function InitData() {
//
let res = await window.setting.GetMJSettingTreeData()
if (res.code == 0) {
message.error(res.message)
return
}
if (!res.data.apiSetting) {
delete res.data.apiSetting
}
if (!res.data.remoteSetting) {
delete res.data.remoteSetting
}
if (!res.data.browserSetting) {
delete res.data.browserSetting
}
mjSetting.value = Object.assign(mjSetting.value, res.data)
console.log(res)
await window.mj.GetMJImageScale((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
image_scale_options.value = value.data
if (image_scale_options.value.length > 0 && mjSetting.value.imageScale == null) {
mjSetting.value.imageScale = image_scale_options.value[0].value
}
})
await window.mj.GetMJImageRobotModel((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
image_model_options.value = value.data
tmp_image_model_options = value.data
if (image_model_options.value.length > 0 && mjSetting.value.imageModel == null) {
mjSetting.value.imageModel = image_model_options.value[0].value
}
})
await window.mj.GetMJGenerateCategory((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
request_model_options.value = value.data.filter((item) => !item.disable)
if (request_model_options.value.length > 0 && mjSetting.value.requestModel == null) {
mjSetting.value.requestModel = request_model_options.value[0].value
}
})
await window.api.getGptBusinessOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
mj_api_options.value = value.data.filter((item) => item.mj_url)
if (mj_api_options.value.length > 0 && mjSetting.value.apiSetting.mjApiUrl == null) {
mjSetting.value.apiSetting.mjApiUrl = mj_api_options.value[0].value
}
})
}
onMounted(async () => {
//
window.api.setEventListen([DEFINE_STRING.DISCORD.OPERATE_REFRASH_DISCORD_URL], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
//
console.log(value)
if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.URL) {
mjSetting.value.browserSetting.serviceId = value.data.serviceID
mjSetting.value.browserSetting.channelId = value.data.channelID
} else if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.TOKEN) {
mjSetting.value.browserSetting.token = value.data.authorization
if (!mjSetting.value.browserSetting.userAgentCustom) {
mjSetting.value.browserSetting.userAgent = value.data.userAgent
}
} else {
message.error('未知的数据类型')
}
})
await InitData()
if (mjSetting.value.apiSetting.mjSpeed == null) {
mjSetting.value.apiSetting.mjSpeed = mj_speed_options.value[0].value
}
})
/**
* 打开discord窗口
*/
async function OpenDiscordWindow() {
await window.api.OpenDiscordWindow((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
})
}
//
let sampleRules = {
imageModel: [{ required: true, message: '请选择机器人模型', trigger: 'blur' }],
imageScale: [{ required: true, message: '请选择生图尺寸', trigger: 'blur' }],
requestModel: [{ required: true, message: '请选择出图模式', trigger: 'blur' }],
selectRobot: [{ required: true, message: '请选择生图机器人', trigger: 'blur' }]
}
/**
* 保存MJ配置
*/
async function SaveMjSetting(e) {
//
e.preventDefault()
sampleRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
// mjSetting.value.imageSuffix = image_suffix.value
//
let request_model = mjSetting.value.requestModel
if (request_model == MJImageType.API_MJ) {
// API
if (
mjSetting.value.apiSetting == null ||
mjSetting.value.apiSetting.mjApiUrl == null ||
mjSetting.value.apiSetting.mjSpeed == null ||
mjSetting.value.apiSetting.apiKey == null
) {
message.error('请检查API模式设置的必填字段')
return
}
}
if (request_model == MJImageType.REMOTE_MJ) {
//
let remoteMjRes = await window.setting.GetRemoteMJSettings()
if (remoteMjRes.code == 0) {
message.error('获取代理MJ配置失败')
return
}
if (remoteMjRes.data.length <= 0) {
message.error('请先添加代理模式的配置')
return
}
}
if (request_model == MJImageType.BROWSER_MJ) {
//
if (
mjSetting.value.browserSetting == null ||
mjSetting.value.browserSetting.serviceId == null ||
mjSetting.value.browserSetting.channelId == null ||
mjSetting.value.browserSetting.token == null ||
mjSetting.value.browserSetting.userAgent == null
) {
message.error('请检查浏览器模式设置的必填字段')
return
}
}
//
let res = await window.setting.SaveMJSettingTreeData(toRaw(mjSetting.value))
if (res.code == 0) {
window.api.showGlobalMessageDialog({ code: 0, message: res.message })
return
}
mjSetting.value = res.data
//
if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) {
window.api.showGlobalMessageDialog({
code: 1,
message: `数据保存成功,当前模式为代理模式`
})
} else {
window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' })
}
})
}
/**
* 更新选择的机器人时触发的方法
*/
async function UpdateSelectRobot(value) {
//
image_model_options.value = tmp_image_model_options.filter((item) => {
return item.type == value
})
//
if (
image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageModel
}) == -1
) {
mjSetting.value.imageModel =
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
}
//
mjSetting.value.imageSuffix = computedSuffix()
}
/**
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = mj_api_options.value.filter(
(item) => item.value == mjSetting.value.apiSetting.mjApiUrl
)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
}
let buy_url = tmp_gb[0].buy_url
if (isEmpty(buy_url)) {
message.error('当前选择的服务商没有购买地址!')
} else {
window.api.openGptBuyUrl(buy_url)
}
}
/**
* 添加多个账号这样可以同时跑多个账号
*/
async function AddMultiMjAccount() {
//
let dW = window.innerWidth * 0.9
let dH = window.innerHeight * 0.9
dialog.create({
showIcon: false,
title: '管理代理模式MJ账号',
content: () => h(AddMultiRemoteMj, { height: dH }),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false
})
}
</script>

View File

@ -30,7 +30,7 @@
</div>
</template>
<script>
<script setup>
import { ref, onMounted, defineComponent, watch, inject } from 'vue'
import {
useMessage,
@ -47,42 +47,35 @@ import { GetEdgeTTSRole } from '../../../../define/tts/ttsDefine'
import { ReaderOutline } from '@vicons/ionicons5'
import { useSettingStore } from '../../../../stores/setting'
export default defineComponent({
components: {
NForm,
NCheckbox,
NFormItem,
NInputNumber,
NSelect,
NButton,
NIcon,
ReaderOutline,
NPopover
},
setup(props) {
let message = useMessage()
let settingStore = useSettingStore()
let message = useMessage()
let settingStore = useSettingStore()
let roleOptions = ref([])
onMounted(async () => {
//
roleOptions.value = GetEdgeTTSRole()
})
/**
* 切换角色的时候修改角色的配置
*/
function ChangeCharacter(value) {
let role = roleOptions.value.find(
(item) => item.value === value
)
settingStore.ttsSetting.edgeTTS.value = role.value
settingStore.ttsSetting.edgeTTS.label = role.label
settingStore.ttsSetting.edgeTTS.lang = role.lang
settingStore.ttsSetting.edgeTTS.gender = role.gender
}
return { roleOptions, settingStore, ChangeCharacter }
async function SwitchTTSOptions(key) {
console.log('SwitchTTSOptions', key)
let ttsOptionsRes = await window.tts.GetTTSOptions(key)
console.log('SwitchTTSOptions', ttsOptionsRes)
if (ttsOptionsRes.code == 0) {
message.error(ttsOptionsRes.message)
} else {
roleOptions.value = ttsOptionsRes.data
}
console.log('SwitchTTSOptions', roleOptions.value)
}
let roleOptions = ref([])
onMounted(async () => {
//
await SwitchTTSOptions('edge-tts')
})
/**
* 切换角色的时候修改角色的配置
*/
function ChangeCharacter(value) {
let role = roleOptions.value.find((item) => item.value === value)
settingStore.ttsSetting.edgeTTS.value = role.value
settingStore.ttsSetting.edgeTTS.label = role.label
settingStore.ttsSetting.edgeTTS.lang = role.lang
settingStore.ttsSetting.edgeTTS.gender = role.gender
}
</script>

View File

@ -12,7 +12,11 @@
show-count
></n-input>
<div class="tts-options">
<n-button :color="softwareStore.SoftColor.BROWN_YELLOW" size="small" @click="FormatWord">
<n-button
:color="softwareStore.SoftColor.BROWN_YELLOW"
size="small"
@click="FormatWordString"
>
格式化文档
</n-button>
<n-popover trigger="hover">
@ -46,10 +50,9 @@
></n-select>
</n-form-item>
</n-form>
<EdgeTTS :ref="edgettsRef" v-if="settingStore.ttsSetting.selectModel == 'edge-tts'" />
<EdgeTTS v-if="settingStore.ttsSetting.selectModel == 'edge-tts'" />
<AzureTTS
:azureTTS="settingStore.ttsSetting.azureTTS"
:ref="azurettsRef"
v-else-if="settingStore.ttsSetting.selectModel == 'azure-tts'"
/>
</div>
@ -83,7 +86,7 @@
</div>
</template>
<script>
<script setup>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, reactive, h } from 'vue'
import {
useMessage,
@ -104,216 +107,164 @@ import { AddCircleOutline } from '@vicons/ionicons5'
import InputDialogContent from '../Original/Components/InputDialogContent.vue'
import { useSettingStore } from '../../../../stores/setting'
import TTSHistory from './TTSHistory.vue'
import { FormatWord } from '../../../../define/Tools/write'
export default defineComponent({
components: {
NInput,
NSelect,
NFormItem,
NForm,
EdgeTTS,
AzureTTS,
NButton,
NPopover,
AddCircleOutline,
NIcon,
InputDialogContent,
TTSHistory
},
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let text = ref('你好,我是你的智能语音助手')
let ttsOptions = ref([
{
label: 'EdgeTTS免费',
value: 'edge-tts'
}
])
let splitRef = ref(null)
let settingStore = useSettingStore()
let writeSetting = ref({
split_char: '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;',
merge_count: 3,
merge_char: '',
end_char: '。'
})
let audioUrl = ref(null)
setup() {
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let text = ref('你好,我是你的智能语音助手')
let ttsOptions = ref([])
let edgettsRef = ref(null)
let azurettsRef = ref(null)
let splitRef = ref(null)
let settingStore = useSettingStore()
let writeSetting = ref({
split_char: '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;',
merge_count: 3,
merge_char: '',
end_char: '。'
})
let audioUrl = ref(null)
onMounted(async () => {
ttsOptions.value = GetTTSSelect()
// TTSTTS
let res = await window.tts.GetTTSCOnfig()
if (res.code == 0) {
message.error(res.message)
} else {
settingStore.ttsSetting = res.data
}
//
let writeSettingRes = await window.write.GetWriteCOnfig()
if (writeSettingRes.code == 0) {
message.error(writeSettingRes.message)
} else {
writeSetting.value = writeSettingRes.data
}
})
/**
* 修改分割符
*/
async function ModifySplitChar() {
//
//
let dialogWidth = 400
let dialogHeight = 150
dialog.create({
title: '添加分割符',
showIcon: false,
closeOnEsc: false,
content: () =>
h(InputDialogContent, {
ref: splitRef,
initData: writeSetting.value.split_char,
placeholder: '请输入分割符'
}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
writeSetting.value.split_char = splitRef.value.data
//
let saveRes = await window.write.SaveWriteConfig(toRaw(writeSetting.value))
if (saveRes.code == 0) {
message.error(saveRes.message)
return
}
message.success('分隔符保存成功')
}
})
onMounted(async () => {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在加载,请稍等...'
try {
// TTSTTS
let res = await window.tts.GetTTSCOnfig()
if (res.code == 0) {
message.error(res.message)
} else {
settingStore.ttsSetting = res.data
}
/**
* 解析/格式化文档
*/
async function FormatWord() {
let split_arr = Array.from(writeSetting.value.split_char)
split_arr.forEach((item) => {
let specialCharacters = [
'.',
'*',
'?',
'+',
'^',
'$',
'[',
']',
'(',
')',
'{',
'}',
'|',
'\\'
]
let regex
if (specialCharacters.includes(item)) {
regex = new RegExp('\\' + item, 'g')
} else {
regex = new RegExp(item, 'g')
}
text.value = text.value.replace(regex, '\n')
})
//
let word_arr = text.value.split('\n')
word_arr = word_arr.filter((item) => item != '' && item != null)
text.value = word_arr.join('\n')
}
/**
* 删除文本内容
*/
async function ClearText() {
text.value = ''
}
/**
* 保存TTS配置信息
*/
async function SaveTTSConfig() {
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
if (saveRes.code == 0) {
message.error(saveRes.message)
return
}
message.success('TTS配置保存成功')
}
/**
* 开始合成音频
*/
async function GenerateAudio() {
if (text.value == '') {
message.error('文本内容不能为空')
return
}
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在合成音频,请稍等...'
//
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
if (saveRes.code == 0) {
softwareStore.spin.spinning = false
message.error(saveRes.message)
return
}
//
let generateRes = await window.tts.GenerateAudio(text.value)
if (generateRes.code == 0) {
softwareStore.spin.spinning = false
message.error(generateRes.message)
return
}
audioUrl.value = generateRes.mp3Path
softwareStore.spin.spinning = false
}
//
function ShowHistory() {
let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9
dialog.create({
title: '配音历史记录',
showIcon: false,
closeOnEsc: false,
content: () => h(TTSHistory, { height: dialogHeight }),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px;matgin-right: 0px`,
maskClosable: false
})
}
return {
text,
azurettsRef,
edgettsRef,
settingStore,
writeSetting,
softwareStore,
ModifySplitChar,
ShowHistory,
SaveTTSConfig,
FormatWord,
ClearText,
splitRef,
audioUrl,
GenerateAudio,
ttsOptions: [{ label: 'Edge TTS免费', value: 'edge-tts' }]
//
let writeSettingRes = await window.write.GetWriteCOnfig()
if (writeSettingRes.code == 0) {
message.error(writeSettingRes.message)
} else {
writeSetting.value = writeSettingRes.data
}
} catch (error) {
message.error('加载失败,失败原因:' + error.toString())
} finally {
softwareStore.spin.spinning = false
}
})
/**
* 修改分割符
*/
async function ModifySplitChar() {
//
//
let dialogWidth = 400
let dialogHeight = 150
dialog.create({
title: '添加分割符',
showIcon: false,
closeOnEsc: false,
content: () =>
h(InputDialogContent, {
ref: splitRef,
initData: writeSetting.value.split_char,
placeholder: '请输入分割符'
}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
writeSetting.value.split_char = splitRef.value.data
//
let saveRes = await window.write.SaveWriteConfig(toRaw(writeSetting.value))
if (saveRes.code == 0) {
message.error(saveRes.message)
return
}
message.success('分隔符保存成功')
}
})
}
/**
* 解析/格式化文档
*/
async function FormatWordString() {
try {
let wordSrr = FormatWord(text.value)
text.value = wordSrr.join('\n')
message.success('文本格式化成功')
} catch (error) {
message.error('文本格式化失败,失败原因:' + error.toString())
}
}
/**
* 删除文本内容
*/
async function ClearText() {
text.value = ''
}
/**
* 保存TTS配置信息
*/
async function SaveTTSConfig() {
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
if (saveRes.code == 0) {
message.error(saveRes.message)
return
}
message.success('TTS配置保存成功')
}
/**
* 开始合成音频
*/
async function GenerateAudio() {
if (text.value == '') {
message.error('文本内容不能为空')
return
}
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在合成音频,请稍等...'
//
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
if (saveRes.code == 0) {
softwareStore.spin.spinning = false
message.error(saveRes.message)
return
}
//
let generateRes = await window.tts.GenerateAudio(text.value)
if (generateRes.code == 0) {
softwareStore.spin.spinning = false
message.error(generateRes.message)
return
}
audioUrl.value = generateRes.mp3Path
softwareStore.spin.spinning = false
}
//
function ShowHistory() {
let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9
dialog.create({
title: '配音历史记录',
showIcon: false,
closeOnEsc: false,
content: () => h(TTSHistory, { height: dialogHeight }),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px;matgin-right: 0px`,
maskClosable: false
})
}
</script>
<style scoped>

View File

@ -1,7 +1,6 @@
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App.vue'
import { Home } from '@vicons/ionicons5'
const app = createApp(App)
import { createPinia } from 'pinia'
const pinia = createPinia()

View File

@ -34,8 +34,10 @@ export const useSettingStore = defineStore('setting', {
pitch: 0, // 语调
rate: 10, // 倍速
volumn: 0 // 音量
}
},
} as TTSSettingModel.TTSSetting
,
ttsRoles: []
}),
getters: {},
actions: {