From 669e57824d1860ae59f5165c99fbb11a215ba9c0 Mon Sep 17 00:00:00 2001 From: lq1405 <2769838458@qq.com> Date: Thu, 27 Jun 2024 16:24:41 +0800 Subject: [PATCH] =?UTF-8?q?V=202.2.11=20=E4=BC=98=E5=8C=96MJ=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- .vscode/settings.json | 2 +- package-lock.json | 30 +- package.json | 9 +- resources/scripts/Lai.py | 8 +- resources/scripts/clip.py | 4 +- resources/scripts/db/book.realm.lock | Bin 1416 -> 1416 bytes resources/scripts/db/software.realm.lock | Bin 1416 -> 1416 bytes resources/scripts/getgrame.py | 2 +- resources/scripts/iamge_to_video.py | 8 +- src/api/discordApi.js | 191 +-- src/define/Tools/common.js | 1 - src/define/Tools/time.js | 40 + .../db/model/Book/BookBackTaskListModel.ts | 2 +- src/define/db/model/Book/bookTaskDetail.ts | 4 +- src/define/db/model/SoftWare/mjSetting.ts | 12 +- .../service/Book/bookBackTaskListService.ts | 17 +- src/define/db/service/Book/bookBasic.ts | 9 +- src/define/db/service/Book/bookService.ts | 59 +- .../db/service/Book/bookTaskDetailService.ts | 196 ++- src/define/db/service/Book/bookTaskService.ts | 64 +- .../db/service/SoftWare/mjSettingService.ts | 40 +- .../db/service/SoftWare/softwareBasic.ts | 29 +- src/define/define_string.js | 445 +++--- src/main/IPCEvent/settingIpc.js | 194 ++- src/main/Original/MJOriginalImageGenerate.js | 1326 +++++++++-------- src/main/ReverseManage/Book/BooKBasic.js | 81 +- src/main/ReverseManage/Book/ReverseBook.js | 81 +- src/main/Task/basicReverse.js | 544 ++++++- src/main/Task/taskManage.js | 214 +++ src/main/setting/ffmpegSetting.js | 21 + src/main/setting/mjSetting.js | 342 +++-- src/preload/book.js | 3 + src/preload/setting.js | 81 +- src/renderer/src/App.vue | 1 - src/renderer/src/components/Home/Home.vue | 30 +- .../Setting/Components/AddMultiRemoteMj.vue | 196 +++ .../Components/ManageRemoteMjAccount.vue | 175 +++ .../src/components/Setting/MJSetting.vue | 492 +++--- src/stores/setting.js | 51 + 40 files changed, 3364 insertions(+), 1644 deletions(-) create mode 100644 src/define/Tools/time.js create mode 100644 src/main/Task/taskManage.js create mode 100644 src/main/setting/ffmpegSetting.js create mode 100644 src/renderer/src/components/Setting/Components/AddMultiRemoteMj.vue create mode 100644 src/renderer/src/components/Setting/Components/ManageRemoteMjAccount.vue create mode 100644 src/stores/setting.js diff --git a/.gitignore b/.gitignore index 7d823c7..afe9833 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,11 @@ resources/scripts/virtual py resources/scripts/_internal resources/logger resources/scripts/Temp +*scripts/db* resources/image/Temp* -resources/package/ffmpeg-2023* +resources/package/ffmpeg/w* resources/config* +*ffmpeg.exe* *Lai.exe* *Lai_1.exe* .DS_Store diff --git a/.vscode/settings.json b/.vscode/settings.json index 4b90404..f9a9510 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { - "editor.defaultFormatter": "vscode.typescript-language-features" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "vscode.json-language-features" diff --git a/package-lock.json b/package-lock.json index b1cec8c..6b3e7e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "laitool", - "version": "2.2.9", + "version": "2.2.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "laitool", - "version": "2.2.9", + "version": "2.2.10", "hasInstallScript": true, "dependencies": { "@alicloud/alimt20181012": "^1.2.0", @@ -25,7 +25,7 @@ "crypto-js": "^4.2.0", "electron-store": "^9.0.0", "electron-updater": "^6.1.7", - "fluent-ffmpeg": "^2.1.2", + "fluent-ffmpeg": "^2.1.3", "highlight.js": "^11.9.0", "install": "^0.13.0", "jimp": "^0.22.10", @@ -51,6 +51,7 @@ "devDependencies": { "@electron-toolkit/eslint-config": "^1.0.1", "@rushstack/eslint-patch": "^1.6.1", + "@types/fluent-ffmpeg": "^2.1.24", "@vitejs/plugin-vue": "^5.0.2", "@vue/eslint-config-prettier": "^9.0.0", "electron": "^28.1.1", @@ -2177,6 +2178,15 @@ "version": "1.0.5", "license": "MIT" }, + "node_modules/@types/fluent-ffmpeg": { + "version": "2.1.24", + "resolved": "https://registry.npmmirror.com/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.24.tgz", + "integrity": "sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/fs-extra": { "version": "9.0.13", "dev": true, @@ -5049,16 +5059,22 @@ "license": "ISC" }, "node_modules/fluent-ffmpeg": { - "version": "2.1.2", - "license": "MIT", + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz", + "integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==", "dependencies": { - "async": ">=0.2.9", + "async": "^0.2.9", "which": "^1.1.1" }, "engines": { - "node": ">=0.8.0" + "node": ">=18" } }, + "node_modules/fluent-ffmpeg/node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmmirror.com/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, "node_modules/fluent-ffmpeg/node_modules/which": { "version": "1.3.1", "license": "ISC", diff --git a/package.json b/package.json index 54c643d..ae8b3a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "2.2.10", + "version": "2.2.11", "description": "An AI tool for image processing, video processing, and other functions.", "main": "./out/main/index.js", "author": "laitool.cn", @@ -33,7 +33,7 @@ "crypto-js": "^4.2.0", "electron-store": "^9.0.0", "electron-updater": "^6.1.7", - "fluent-ffmpeg": "^2.1.2", + "fluent-ffmpeg": "^2.1.3", "highlight.js": "^11.9.0", "install": "^0.13.0", "jimp": "^0.22.10", @@ -59,6 +59,7 @@ "devDependencies": { "@electron-toolkit/eslint-config": "^1.0.1", "@rushstack/eslint-patch": "^1.6.1", + "@types/fluent-ffmpeg": "^2.1.24", "@vitejs/plugin-vue": "^5.0.2", "@vue/eslint-config-prettier": "^9.0.0", "electron": "^28.1.1", @@ -81,7 +82,7 @@ ], "extraResources": [ "resources/package/exittool/**", - "resources/package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/**", + "resources/package/ffmpeg/**", "resources/package/Improve/**", "resources/image/style/**", "resources/image/zhanwei.png", @@ -94,4 +95,4 @@ "icon": "./resources/icon.ico" } } -} \ No newline at end of file +} diff --git a/resources/scripts/Lai.py b/resources/scripts/Lai.py index a9da896..44b4a6e 100644 --- a/resources/scripts/Lai.py +++ b/resources/scripts/Lai.py @@ -17,8 +17,8 @@ if len(sys.argv) < 2: "C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe", "-ka", "C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.mp4", - "C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.json", - 30 + "C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.json", + 30, ] print(sys.argv) @@ -35,9 +35,7 @@ elif __file__: def set_ffmpeg_env(): # 根据你的ffmpeg路径替换这个 - ffmpeg_path = os.path.join( - cript_directory, "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin" - ) + ffmpeg_path = os.path.join(cript_directory, "../package/ffmpeg/win") if sys.platform == "win32": ffmpeg_path = ffmpeg_path.replace("/", "\\") diff --git a/resources/scripts/clip.py b/resources/scripts/clip.py index 249861c..25deac8 100644 --- a/resources/scripts/clip.py +++ b/resources/scripts/clip.py @@ -33,10 +33,10 @@ class Clip: self.config_path = config_path self.gpu_type = gpu_type self.ffmpeg_path = ( - "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" + "../package/ffmpeg/win/ffmpeg" ) self.ffprobe_path = ( - "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffprobe" + "../package/ffmpeg/win/ffprobe" ) self.getInitData() pass diff --git a/resources/scripts/db/book.realm.lock b/resources/scripts/db/book.realm.lock index 6ffb57db91f11edc8c4e798dbb860b7165e447e0..977611813bf0969fca859307328afa4790828a88 100644 GIT binary patch literal 1416 zcmZQ%Y B0iXZ? literal 1416 zcmZQ%eLKINbPBbe=xuYR48Umvs IFepL*03kR5F#rGn diff --git a/resources/scripts/db/software.realm.lock b/resources/scripts/db/software.realm.lock index 1b3c816efe353a0c9d89ab3f9c073dc5311a6937..ca5f0530e0a8e3b92cae55847bd34efb946a247f 100644 GIT binary patch literal 1416 zcmZQ%F0YtY$ z05T6M1*B%enGkh5{2&4#vyj1TI0vHcL?T20UELfsbrLBM0f;WRBvQCQWCXIXt6K!u X0#V124i^|@jE2By2#kgR)(`*ynlA|s literal 1416 zcmZQ% 0 ? parseInt(res.data.progress.slice(0, -1)) : 0; - let status = res.data.status.toLowerCase(); - // let code = (status == "success" || status == "in_progress" || status == "not_start") ? 1 : 0; - let code = (status == "failure" || status == "cancel") ? 0 : 1; - // 返回前端 - let res_data = { - type: "updated", - progress: progress, - category: "api_mj", - image_click: res.data.imageUrl, - image_show: res.data.imageUrl, - message_id: res.data.id, - action: res.data.action, - status: status, - code: code, - } - - // 判断当前的API是哪个 - if (url.includes("mjapi.deepwl.net")) { - if (res_data.code == 0) { - res_data["message"] = res.data.failReason - } - } else if (url.includes("api.ephone.ai")) { - // ePhoneAPI - if (res_data.code == 0) { - res_data["message"] = res.data.failReason - } - } - return res_data; - } catch (error) { - throw error + /** + * 通过设置的ID获取MJ API的任务 + * @param {*} id + */ + async GetMJAPITaskByID(id, url, key) { + try { + let res + url = url.replace('${id}', id) + let headers = { + Authorization: key + } + if (url.includes(define.remotemj_api)) { + headers = { + 'mj-api-secret': define.API } + } + res = await basicApi.get(url, headers) - } + let progress = + res.data.progress && res.data.progress.length > 0 + ? parseInt(res.data.progress.slice(0, -1)) + : 0 + let status = res.data.status.toLowerCase() + // let code = (status == "success" || status == "in_progress" || status == "not_start") ? 1 : 0; + let code = status == 'failure' || status == 'cancel' ? 0 : 1 + // 返回前端 + let res_data = { + type: 'updated', + progress: progress, + category: 'api_mj', + image_click: res.data.imageUrl, + image_show: res.data.imageUrl, + message_id: res.data.id, + action: res.data.action, + status: status, + code: code + } - /** - * MJ使用API进行生图 - */ - async mjApiImagine(url, data, headers) { - try { - // 判断是不是需要垫图,将指定的图片转换为base64 - for (let i = 0; data.base64Array && i < data.base64Array.length; i++) { - const element = data.base64Array[i]; - // 将指定的图片转换为base64 - // 判断图片是本地图片还是网络图片 - if (element.indexOf("http") == -1) { - // 本地图片 - let base64 = await this.tools.readFileBase64(element); - data.base64Array[i] = `data:image/png;base64,${base64}` - } else { - // 网络图片 - // 请求对应的图片 - let image_buffer = await basicApi.get(element); - // 将返回来的数据转为base64 - let base64 = image_buffer.data.toString('base64'); - data.base64Array[i] = `data:image/png;base64,${base64}` - } - } - - let res = await basicApi.post(url, data, headers); - console.log(res) - let res_data = res.data; - // 判断res_data 是不是json格式的字符串,是就序列化为json对象 - if (typeof res_data == "string") { - res_data = JSON.parse(res_data); - } - // 直接返回,错误信息外面判断 - return res_data; - } catch (error) { - throw error; + // 判断当前的API是哪个 + if (url.includes('mjapi.deepwl.net')) { + if (res_data.code == 0) { + res_data['message'] = res.data.failReason } + } else if (url.includes('api.ephone.ai')) { + // ePhoneAPI + if (res_data.code == 0) { + res_data['message'] = res.data.failReason + } + } else if (url.includes('laitool')) { + // laitool + if (res_data.code == 0) { + res_data['message'] = res.data.failReason + } + } + return res_data + } catch (error) { + throw error } + } + + /** + * MJ使用API进行生图 + */ + async mjApiImagine(url, data, headers) { + try { + // 判断是不是需要垫图,将指定的图片转换为base64 + for (let i = 0; data.base64Array && i < data.base64Array.length; i++) { + const element = data.base64Array[i] + // 将指定的图片转换为base64 + // 判断图片是本地图片还是网络图片 + if (element.indexOf('http') == -1) { + // 本地图片 + let base64 = await this.tools.readFileBase64(element) + data.base64Array[i] = `data:image/png;base64,${base64}` + } else { + // 网络图片 + // 请求对应的图片 + let image_buffer = await basicApi.get(element) + // 将返回来的数据转为base64 + let base64 = image_buffer.data.toString('base64') + data.base64Array[i] = `data:image/png;base64,${base64}` + } + } + + let res = await basicApi.post(url, data, headers) + console.log(res) + let res_data = res.data + // 判断res_data 是不是json格式的字符串,是就序列化为json对象 + if (typeof res_data == 'string') { + res_data = JSON.parse(res_data) + } + // 直接返回,错误信息外面判断 + return res_data + } catch (error) { + throw error + } + } } diff --git a/src/define/Tools/common.js b/src/define/Tools/common.js index 37777e7..6772cea 100644 --- a/src/define/Tools/common.js +++ b/src/define/Tools/common.js @@ -1,4 +1,3 @@ import fs from 'node:fs'; const fspromises = fs.promises; - diff --git a/src/define/Tools/time.js b/src/define/Tools/time.js new file mode 100644 index 0000000..2056b0e --- /dev/null +++ b/src/define/Tools/time.js @@ -0,0 +1,40 @@ +/** + * 将时间字符串转换为毫秒(number) + * 00:00:03.867 --》3867 + * @param {*} timeString 时间字符串 + * @returns + */ +export function TimeStringToMilliseconds(timeString) { + // 分割字符串获取小时、分钟、秒和毫秒 + const parts = timeString.split(/[:.]/) + const hours = parseInt(parts[0], 10) + const minutes = parseInt(parts[1], 10) + const seconds = parseInt(parts[2], 10) + const milliseconds = parseInt(parts[3], 10) + + // 将小时、分钟、秒转换为毫秒并计算总和 + return hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds +} + +/** + * 将毫秒转换为时间字符串 + * 85233 --》 '00:01:25.233' + * @param {*} milliseconds + * @returns + */ +export function MillisecondsToTimeString(milliseconds) { + let totalSeconds = milliseconds / 1000 + const hours = Math.floor(totalSeconds / 3600) + totalSeconds %= 3600 + const minutes = Math.floor(totalSeconds / 60) + const seconds = Math.floor(totalSeconds % 60) + const ms = milliseconds % 1000 + + // 将小时、分钟、秒格式化为两位数,毫秒格式化为三位数 + const hoursFormatted = hours.toString().padStart(2, '0') + const minutesFormatted = minutes.toString().padStart(2, '0') + const secondsFormatted = seconds.toString().padStart(2, '0') + const msFormatted = ms.toString().padStart(3, '0') + + return `${hoursFormatted}:${minutesFormatted}:${secondsFormatted}.${msFormatted}` +} diff --git a/src/define/db/model/Book/BookBackTaskListModel.ts b/src/define/db/model/Book/BookBackTaskListModel.ts index fcb7548..e32bb1d 100644 --- a/src/define/db/model/Book/BookBackTaskListModel.ts +++ b/src/define/db/model/Book/BookBackTaskListModel.ts @@ -5,7 +5,7 @@ export class BookBackTaskList extends Realm.Object { id: string bookId: string bookTaskId: string - name: string + name: string // 任务名称,小说名+批次名+分镜名 type: BookBackTaskType status: BookBackTaskStatus createTime: Date diff --git a/src/define/db/model/Book/bookTaskDetail.ts b/src/define/db/model/Book/bookTaskDetail.ts index 0165f1a..a886e59 100644 --- a/src/define/db/model/Book/bookTaskDetail.ts +++ b/src/define/db/model/Book/bookTaskDetail.ts @@ -112,6 +112,7 @@ export class BookTaskDetailModel extends Realm.Object { bookId: string bookTaskId: string videoPath: string | null // 视频地址 + audioPath: string | null // 音频地址 word: string | null // 文案 oldImage: string | null // 旧图片(用于SD的图生图) afterGpt: string | null // GPT生成的文案 @@ -123,7 +124,7 @@ export class BookTaskDetailModel extends Realm.Object { gptPrompt: string | null // GPT提示词 mjMessage: MJMessage | null // MJ消息 outImagePath: string | null // 输出图片地址 - subImagePath: string[] | null // 字幕图片地址 + subImagePath: string[] | null // 子图片地址 prompt: string | null // 提示 adetailer: boolean // 是否开启修脸 sdConifg: SDConfig | null // SD配置 @@ -139,6 +140,7 @@ export class BookTaskDetailModel extends Realm.Object { bookId: { type: 'string', indexed: true }, bookTaskId: { type: 'string', indexed: true }, videoPath: 'string?', + audioPath: 'string?', word: 'string?', oldImage: 'string?', afterGpt: 'string?', diff --git a/src/define/db/model/SoftWare/mjSetting.ts b/src/define/db/model/SoftWare/mjSetting.ts index 0b11be2..62c83ee 100644 --- a/src/define/db/model/SoftWare/mjSetting.ts +++ b/src/define/db/model/SoftWare/mjSetting.ts @@ -39,9 +39,10 @@ export class RemoteMJModel extends Realm.Object { accountId: string | null channelId: string coreSize: number - guildId: string - mjBotChannelId: string - nijiBotChannelId: string + guildId: string + enable: boolean // 是否启用 + mjBotChannelId: string | null + nijiBotChannelId: string | null queueSize: number remark: string remixAutoSubmit: boolean @@ -59,8 +60,9 @@ export class RemoteMJModel extends Realm.Object { channelId: 'string', coreSize: 'int', guildId: 'string', - mjBotChannelId: 'string', - nijiBotChannelId: 'string', + enable: 'bool', + mjBotChannelId: 'string?', + nijiBotChannelId: 'string?', queueSize: 'int', remark: 'string', remixAutoSubmit: 'bool', diff --git a/src/define/db/service/Book/bookBackTaskListService.ts b/src/define/db/service/Book/bookBackTaskListService.ts index 72226e1..4e4f71a 100644 --- a/src/define/db/service/Book/bookBackTaskListService.ts +++ b/src/define/db/service/Book/bookBackTaskListService.ts @@ -26,14 +26,29 @@ export class BookBackTaskListService extends BaseRealmService { BookBackTaskListService.instance = new BookBackTaskListService() await super.getInstance() } + await BookBackTaskListService.instance.open() return BookBackTaskListService.instance } + /** + * 获取指定条件的后台任务队列 + * bookId 必填 + * @param query bookId,bookTaskId,name,type,status + */ + getBookBackTaskList(query) { + try { + // if() + + } catch (error) { + throw error + } + } + /** * 新增一个小说相关的后台任务队列 * @param bookBackTask 要添加的小说数据 */ - async AddBookBackTaskList(bookBackTask) { + AddBookBackTaskList(bookBackTask) { try { // 判断数据是不是存在 if ( diff --git a/src/define/db/service/Book/bookBasic.ts b/src/define/db/service/Book/bookBasic.ts index 88ecf4d..0ee1c5b 100644 --- a/src/define/db/service/Book/bookBasic.ts +++ b/src/define/db/service/Book/bookBasic.ts @@ -32,6 +32,13 @@ const migration = (oldRealm: Realm, newRealm: Realm) => { newBookTask[i].isAuto = false // 为新属性设置默认值 } } + if (oldRealm.schemaVersion < 3) { + const oldBookTask = oldRealm.objects('BookTask') + const newBookTask = newRealm.objects('BookTask') + for (let i = 0; i < oldBookTask.length; i++) { + newBookTask[i].audioPath = null // 为新属性设置默认值 + } + } } export class BaseRealmService extends BaseService { @@ -72,7 +79,7 @@ export class BaseRealmService extends BaseService { BookTaskDetailModel ], path: this.dbpath, - schemaVersion: 2, + schemaVersion: 3, migration: migration } this.realm = await Realm.open(config) diff --git a/src/define/db/service/Book/bookService.ts b/src/define/db/service/Book/bookService.ts index 1b6d468..9ab9660 100644 --- a/src/define/db/service/Book/bookService.ts +++ b/src/define/db/service/Book/bookService.ts @@ -11,8 +11,8 @@ import { BookTaskService } from './bookTaskService' import { BaseRealmService } from './bookBasic.js' import { isEmpty } from 'lodash' -class BooKService extends BaseRealmService { - static instance: BooKService | null = null +export class BookService extends BaseRealmService { + static instance: BookService | null = null realm: Realm private constructor() { @@ -24,20 +24,59 @@ class BooKService extends BaseRealmService { * @returns */ public static async getInstance() { - if (BooKService.instance === null) { - BooKService.instance = new BooKService() + if (BookService.instance === null) { + BookService.instance = new BookService() await super.getInstance() } - return BooKService.instance + await BookService.instance.open() + return BookService.instance + } + + /** + * 获取小说信息,没有找到返回null + * @param bookId + */ + GetBookDataById(bookId) { + try { + if (isEmpty(bookId)) { + throw new Error('获取小说信息失败,缺少小说ID') + } + let books = this.realm.objects('Book').filtered('id = $0', bookId) + if (books.length <= 0) { + return successMessage(null, '通过ID获取小说数据成功', 'ReverseBook_GetBookDataById') + } else { + // 对返回的数据进行处理 + let resBooks = Array.from(books).map((book) => { + // 这里可以直接操作普通对象 + let bookObj = { + ...book, + bookFolderPath: path.resolve( + define.project_path, + book.bookFolderPath.replace(/\\/g, '/') + ), + oldVideoPath: book.oldVideoPath + ? path.resolve(define.project_path, book.oldVideoPath.replace(/\\/g, '/')) + : '', + imageFolder: book.imageFolder + ? path.resolve(define.project_path, book.imageFolder.replace(/\\/g, '/')) + : '' + } + return bookObj + }) + + return successMessage(resBooks[0], '通过ID获取小说数据成功', 'ReverseBook_GetBookDataById') + } + } catch (error) { + throw error + } } /** * 获取小说信息,通过参数查询 * @returns */ - async GetBookData(bookQuery) { + GetBookData(bookQuery) { try { - await this.open() // 获取所有的小说数据,并进行时间降序排序 let books = this.realm.objects('Book') let book_length = books.length @@ -106,7 +145,6 @@ class BooKService extends BaseRealmService { */ async AddOrModifyBook(book) { try { - await this.open() if (book == null) { throw new Error('小说数据为空,无法修改') } @@ -141,6 +179,7 @@ class BooKService extends BaseRealmService { let bookFolderPath = path.resolve(define.project_path, book.id) let imageFolder = path.resolve(define.project_path, `${book.id}/tmp`) let oldVideoPath = path.resolve(define.project_path, `${book.id}/data/${book.id}.mp4`) + let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001') // 将视频拷贝一个到项目文件下面 if (book.oldVideoPath) { @@ -150,11 +189,11 @@ class BooKService extends BaseRealmService { // 创建对应的文件夹 await CheckFolderExistsOrCreate(bookFolderPath) await CheckFolderExistsOrCreate(imageFolder) + await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹 // 修改数据 book.oldVideoPath = path.relative(define.project_path, oldVideoPath) this.realm.write(() => { this.realm.create('Book', book) - let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001') // 添加一个任务 let bookTask = { id: uuidv4(), @@ -210,5 +249,3 @@ class BooKService extends BaseRealmService { } } } - -export default BooKService diff --git a/src/define/db/service/Book/bookTaskDetailService.ts b/src/define/db/service/Book/bookTaskDetailService.ts index adb09ec..50cab9c 100644 --- a/src/define/db/service/Book/bookTaskDetailService.ts +++ b/src/define/db/service/Book/bookTaskDetailService.ts @@ -6,6 +6,10 @@ import { BookTaskModel } from '../../model/Book/bookTask.js' import { BookTaskStatus } from '../../../enum/bookEnum.js' import { successMessage } from '../../../../main/generalTools.js' import { BaseRealmService } from './bookBasic' +import { endsWith, isEmpty } from 'lodash' +import { book } from '../../../../preload/book.js' +import { DefaultObject } from 'realm/dist/public-types/schema.js' +import { JoinPath } from '../../../Tools/file.js' const { v4: uuidv4 } = require('uuid') let dbPath = path.resolve(define.db_path, 'book.realm') @@ -30,16 +34,202 @@ export class BookTaskDetailService extends BaseRealmService { BookTaskDetailService.instance = new BookTaskDetailService() await super.getInstance() } + await BookTaskDetailService.instance.open() return BookTaskDetailService.instance } /** - * 添加一条小说人物对应的详细数据 + * 更具条件查询执行的小说的分镜信息 + * @param condition 查询的条件,id,name,bookId,bookTaskId + */ + GetBookTaskData(condition) { + try { + if (condition == null) { + throw new Error('查询小说分镜信息,查询条件不能为空') + } + let query = [] as string[] + if (condition.id) { + query.push(`id = ${condition.id}`) + } + if (condition.bookId) { + query.push(`bookId = ${condition.bookId}`) + } + if (condition.bookTaskId) { + query.push(`bookTaskId = ${condition.bookTaskId}`) + } + if (condition.name) { + query.push(`name = ${condition.name}`) + } + const queryString = query.join(' && ') + let tasksToDelete: Realm.Results & DefaultObject> + // 获取指定的数据 + if (queryString) { + tasksToDelete = this.realm.objects('BookTaskDetail').filtered(queryString) + } else { + // 返回全部 + tasksToDelete = this.realm.objects('BookTaskDetail') + } + let resData = Array.from(tasksToDelete).map((item) => { + let resObj = { + ...item, + videoPath: JoinPath(define.project_path, item.videoPath), + audioPath: JoinPath(define.project_path, item.audioPath), + oldImage: JoinPath(define.project_path, item.oldImage), + outImagePath: JoinPath(define.project_path, item.outImagePath), + subImagePath: (item.subImagePath as string[])?.map((subImage) => { + return JoinPath(define.project_path, subImage) + }) + } + return resObj + }) + return successMessage( + resData, + '获取小说的分镜信息成功', + 'BookTaskDetailService_GetBookTaskData' + ) + } catch (error) { + throw error + } + } + + /** + * 通过ID获取指定的小说任务分镜详细数据 + * @param bookTaskDetailId + */ + public GetBookTaskDetailDataById(bookTaskDetailId: string) { + try { + if (bookTaskDetailId == null) { + throw new Error('获取小说任务详细信息失败,缺少ID') + } + + let bookTaskDetails = this.GetBookTaskData({ id: bookTaskDetailId }) + if (bookTaskDetails.data.length <= 0) { + return successMessage( + null, + '未找到对应的小说任务详细信息', + 'BookTaskDetailService_GetBookTaskDetailDataById' + ) + } else { + return successMessage( + bookTaskDetails.data[0], + '获取小说任务详细信息成功', + 'BookTaskDetailService_GetBookTaskDetailDataById' + ) + } + } catch (error) { + throw error + } + } + + /** + * 添加一条小说任务对应的详细数据 * @param BookTaskDetail */ - public async AddBookTaskDetail(BookTaskDetail) { + public AddBookTaskDetail(bookTaskDetail) { try { - // 判断是不是又小说的ID + // 判断是不是又小说ID + if (isEmpty(bookTaskDetail.bookId) || isEmpty(bookTaskDetail.bookTaskId)) { + throw new Error( + '新增小说任务详细信息到数据库失败,数据不完整,缺少小说ID或者小说批次任务ID' + ) + } + + // 开始初始化数据(获取指定的bookId和bookTaskId)中最大的no + let bookTaskDetails = this.realm + .objects('BookTaskDetail') + .filtered( + 'bookId = $0 AND bookTaskId = $1', + bookTaskDetail.bookId, + bookTaskDetail.bookTaskId + ) + + let maxNo = bookTaskDetails.max('no') + bookTaskDetail.no = maxNo ? Number(maxNo) + 1 : 1 + let name = bookTaskDetail.no.tosString().padStart(5, '0') + + bookTaskDetail.name = name + bookTaskDetail.id = uuidv4() + bookTaskDetail.createTime = new Date() + bookTaskDetail.updateTime = new Date() + // 开始添加 + this.transaction(() => { + this.realm.create('BookTaskDetail', bookTaskDetail) + }) + //创建成功,返回 + return successMessage( + bookTaskDetail, + '新增小说任务详细信息成功', + 'BookTaskDetailService_AddBookTaskDetail' + ) + } catch (error) { + throw error + } + } + + /** + * 更新指定ID的指定数据 + * @param bookTaskDetailId + * @param updateData + */ + UpdateBookTaskDetail(bookTaskDetailId: string, updateData) { + try { + this.transaction(() => { + let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId) + if (bookTaskDetail == null) { + throw new Error('未找到对应的小说任务详细信息') + } + // 开始修改 + for (let key in updateData) { + bookTaskDetail[key] = updateData[key] + } + bookTaskDetail.updateTime = new Date() + }) + return successMessage( + null, + '修改小说任务详细信息成功', + 'BookTaskDetailService_UpdateBookTaskDetail' + ) + } catch (error) { + throw error + } + } + + /** + * 删除满足条件的对象吗,必传小说ID和小说任务ID + * @param condition bookId,bookTaskId,name,id + */ + DeleteBookTaskDetail(condition) { + try { + if (isEmpty(condition.id) && isEmpty(condition.bookTaskId) && isEmpty(condition.bookId)) { + throw new Error('删除小说分镜信息失败,没有必要参数') + } + let query = [] as string[] + if (condition.id) { + query.push(`id = ${condition.id}`) + } + if (condition.bookId) { + query.push(`bookId = ${condition.bookId}`) + } + if (condition.bookTaskId) { + query.push(`bookTaskId = ${condition.bookTaskId}`) + } + if (condition.name) { + query.push(`name = ${condition.name}`) + } + + if (query.length <= 0) { + throw new Error('删除小说分镜任务失败,没有查询条件') + } + const queryString = query.join(' && ') + let tasksToDelete = this.realm.objects('BookTaskDetail').filtered(queryString) + this.transaction(() => { + this.realm.delete(tasksToDelete) + }) + return successMessage( + null, + '删除指定的分镜任务成功', + 'BookTaskDetailService_DeleteBookTaskDetail' + ) } catch (error) { throw error } diff --git a/src/define/db/service/Book/bookTaskService.ts b/src/define/db/service/Book/bookTaskService.ts index 6c9323a..4766f52 100644 --- a/src/define/db/service/Book/bookTaskService.ts +++ b/src/define/db/service/Book/bookTaskService.ts @@ -29,6 +29,7 @@ export class BookTaskService extends BaseRealmService { BookTaskService.instance = new BookTaskService() await super.getInstance() } + await BookTaskService.instance.open() return BookTaskService.instance } @@ -36,9 +37,8 @@ export class BookTaskService extends BaseRealmService { * 查询满足条件的小说子任务信息 * @param bookTaskCondition 查询条件 id,bookId,name,no,page, pageSize */ - async GetBookTaskData(bookTaskCondition) { + GetBookTaskData(bookTaskCondition) { try { - await this.open() // 获取所有的小说数据,并进行时间降序排序 let bookTasks = this.realm.objects('BookTask') @@ -98,10 +98,64 @@ export class BookTaskService extends BaseRealmService { } } - // 添加一条数据 - async AddOrModifyBookTask(bookTask) { + /** + * 通过ID获取小说批次任务的数据 + * @param bookTaskId + */ + GetBookTaskDataById(bookTaskId: string) { + try { + if (bookTaskId == null) { + throw new Error('小说任务ID不能为空') + } + + let bookTasks = this.GetBookTaskData({ id: bookTaskId }) + if (bookTasks.data.bookTasks.length <= 0) { + return successMessage(null, '未找到对应的小说任务', 'BookTaskService_GetBookTaskDataById') + } else { + return successMessage( + bookTasks.data.bookTasks[0], + '查询小说任务成功', + 'BookTaskService_GetBookTaskDataById' + ) + } + } catch (error) { + throw error + } + } + + /** + * 修改小说批次任务的状态 + * @param bookTaskId 小说批次任务Id + * @param status 目标状态 + */ + UpdateBookTaskStatus(bookTaskId: string, status: BookTaskStatus, errorMsg: string | null = null) { + try { + this.transaction(() => { + // 修改对应小说批次任务的状态 + let bookTask = this.realm.objectForPrimaryKey('BookTask', bookTaskId) + if (bookTask == null) { + throw new Error('未找到对应的小说任务') + } + bookTask.status = status + bookTask.updateTime = new Date() + if (errorMsg != null) { + bookTask.errorMsg = errorMsg + } + }) + + return successMessage( + null, + `修改小说任务状态成功,修改后的状态为${status}`, + 'BookTaskService_UpdateBookTaskStatus' + ) + } catch (error) { + throw error + } + } + + // 添加一条数据 + AddOrModifyBookTask(bookTask) { try { - await this.open() if (bookTask == null) { throw new Error('添加的小说任务不能为空') } diff --git a/src/define/db/service/SoftWare/mjSettingService.ts b/src/define/db/service/SoftWare/mjSettingService.ts index 8a682c8..5510f5a 100644 --- a/src/define/db/service/SoftWare/mjSettingService.ts +++ b/src/define/db/service/SoftWare/mjSettingService.ts @@ -249,7 +249,6 @@ export class MJSettingService extends BaseSoftWareService { if (remoteMjQuery?.id) { remoteMjSettings = this.realm.objects('RemoteMJ').filtered('id = $0', remoteMjQuery.id) } - let resRemoteMj = Array.from(remoteMjSettings).map((remoteMj) => { return { ...remoteMj @@ -298,6 +297,7 @@ export class MJSettingService extends BaseSoftWareService { remoteMjSetting.createTime = new Date() remoteMjSetting.updateTime = new Date() remoteMjSetting.version = version + remoteMjSetting.enable = true remoteMjSetting.remark = global.machineId // 判断当前this.relam 是不是已经处于一个事务中 @@ -374,6 +374,28 @@ export class MJSettingService extends BaseSoftWareService { } } + /** + * 删除指定ID的数据 + * @param id + */ + DeleteRemoteMJSetting(id: string) { + try { + if (isEmpty(id)) { + throw new Error('删除代理模式配置,ID不能为空') + } + let remoteMjSettingRes = this.realm.objects('RemoteMJ').filtered('id = $0', id) + if (remoteMjSettingRes.length <= 0) { + throw new Error('没有找到对应的代理模式配置信息') + } + this.transaction(() => { + this.realm.delete(remoteMjSettingRes) + }) + return successMessage(null, '删除代理API配置成功', 'MJSettingService_DeleteRemoteMjSetting') + } catch (error) { + throw error + } + } + //#endregion //#region MJ设置的基础设置 @@ -540,22 +562,6 @@ export class MJSettingService extends BaseSoftWareService { } // 组合添加数据 this.realm.write(() => { - // 先添加RemoteMJ的数据 - let remoteSetting = mjSetting.remoteSetting ? mjSetting.remoteSetting : null - if (remoteSetting != null) { - let remoteSettingRes: { code: number; data: any; message: any } - if (isEmpty(remoteSetting.id)) { - // 新增 - remoteSettingRes = this.AddRemoteMjSetting(remoteSetting) - } else { - // 修改 - remoteSettingRes = this.UpdateRemoteMjSetting(remoteSetting) - } - if (remoteSettingRes && remoteSettingRes.code == 1) { - mjSetting.remoteSetting = remoteSettingRes.data - } - } - // 判断API设置的数据是不是存在 let apiSetting = mjSetting.apiSetting ? mjSetting.apiSetting : null if (apiSetting != null) { diff --git a/src/define/db/service/SoftWare/softwareBasic.ts b/src/define/db/service/SoftWare/softwareBasic.ts index c23c29e..b3be029 100644 --- a/src/define/db/service/SoftWare/softwareBasic.ts +++ b/src/define/db/service/SoftWare/softwareBasic.ts @@ -60,7 +60,7 @@ const migration = (oldRealm: Realm, newRealm: Realm) => { } if (oldRealm.schemaVersion < 9) { newRealm.write(() => { - const newSoftwares = newRealm.objects('MjSetting') + const newSoftwares = newRealm.objects('RemoteMJ') for (let software of newSoftwares) { software.accountId = null } @@ -74,6 +74,31 @@ const migration = (oldRealm: Realm, newRealm: Realm) => { } }) } + if (oldRealm.schemaVersion < 11) { + newRealm.write(() => { + const newSoftwares = newRealm.objects('MjSetting') + for (let software of newSoftwares) { + software.enable = true + } + }) + } + if (oldRealm.schemaVersion < 12) { + newRealm.write(() => { + const newSoftwares = newRealm.objects('RemoteMJ') + for (let software of newSoftwares) { + software.nijiBotChannelId = null + software.mjBotChannelId = null + } + }) + } + if (oldRealm.schemaVersion < 13) { + newRealm.write(() => { + const newSoftwares = newRealm.objects('RemoteMJ') + for (let software of newSoftwares) { + software.enable = true // 默认都是启用的 + } + }) + } } export class BaseSoftWareService extends BaseService { @@ -112,7 +137,7 @@ export class BaseSoftWareService extends BaseService { MjSettingModel ], path: dbPath, - schemaVersion: 10, // 当前版本号 + schemaVersion: 13, // 当前版本号 migration: migration } // 判断当前全局是不是又当前这个 diff --git a/src/define/define_string.js b/src/define/define_string.js index 1b38441..03d2208 100644 --- a/src/define/define_string.js +++ b/src/define/define_string.js @@ -1,222 +1,227 @@ export const DEFINE_STRING = { - OPEN_DEV_TOOLS_PASSWORD: "OPEN_DEV_TOOLS_PASSWORD", - OPEN_DEV_TOOLS: "OPEN_DEV_TOOLS", - GET_FILE_BASE64: "GET_FILE_BASE64", - SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY: "SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY", - GET_DEFINE_CONFIG_JSON_BY_PROPERTY: "GET_DEFINE_CONFIG_JSON_BY_PROPERTY", - GET_IMAGE_GENERATE_CATEGORY: "GET_IMAGE_GENERATE_CATEGORY", - SHOW_MAIN_NOTIFICATION: "SHOW_MAIN_NOTIFICATION", - SHOW_GLOABAL_MESSAGE: "SHOW_GLOABAL_MESSAGE", - CHECK_MACHINE_ID: "CHECK_MACHINE_ID", - GET_CUSTOMIZE_GPT_PROMPT: "GET_CUSTOMIZE_GPT_PROMPT", - GENERATE_GPT_EXAMPLE_OUT: "GENERATE_GPT_EXAMPLE_OUT", - GET_PERMISSION: "GET_PERMISSION", - SAVE_IMAGE_TO_OTHER_FOLDER: "SAVE_IMAGE_TO_OTHER_FOLDER", - GET_IMAGE_AUTO_SAVE_SETTING: "GET_IMAGE_AUTO_SAVE_SETTING", - SAVE_IMAGE_AUTO_SAVE_SETTING: "SAVE_IMAGE_AUTO_SAVE_SETTING", - GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS: "GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS", - MODIFY_GENERATE_TASK_STATUS: "MODIFY_GENERATE_TASK_STATUS", - DELETE_BACK_TASK: "DELETE_BACK_TASK", - SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE: "SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE", - SAVE_KEY_FRAME_SETTING: "SAVE_KEY_FRAME_SETTING", - MODIFY_SAMPLE_SETTING: "MODIFY_SAMPLE_SETTING", - GET_SETTING_Dafault_DATA: "GET_SETTING_Dafault_DATA", - GET_DRAFT_FILE_LIST: "GET_DRAFT_FILE_LIST", - GET_FRAME: "GET_FRAME", - PYTHON_ERROR: "PYTHON_ERROR", - PYTHON_CLOSE: "PYTHON_CLOSE", - PYTHON_OUTPUT: "PYTHON_OUTPUT", - RESTART_GENERATE: "RESTART_GENERATE", - ALIGN_DRAFT_IMG: "ALIGN_DRAFT_IMG", - ALIGN_DRAFT_IMG_TO_TEXT: "ALIGN_DRAFT_IMG_TO_TEXT", - REGENERATE_IMAGE_RETUN: "REGENERATE_IMAGE_RETUN", - GET_SUBFOLDER_LIST: "GET_SUBFOLDER_LIST", - REFRASH_IMAGWE_DATA: "REFRASH_IMAGWE_DATA", - GET_IMAGE_PROMPTLIST: "GET_IMAGE_PROMPTLIST", - SELECT_FILE: "SELECT_FILE", - IMPROVE_IMAGE_RESOULTION: "IMPROVE_IMAGE_RESOULTION", - GET_BACKGROUND_MUSIC_CONFIG_LIST: "GET_BACKGROUND_MUSIC_CONFIG_LIST", - ADD_BACKGROUND_MUSIC_FOLDER: "ADD_BACKGROUND_MUSIC_FOLDER", - DELETE_CLIP_SETTING: "DELETE_CLIP_SETTING", - DELETE_FRIENDLY_REMINDER: "DELETE_FRIENDLY_REMINDER", - MODIFY_INPUT_CROP_JSON: "MODIFY_INPUT_CROP_JSON", - PUSH_BACK_PROMPT: "PUSH_BACK_PROMPT", - GET_FRIENDLY_REMINDER_DRAFT: "GET_FRIENDLY_REMINDER_DRAFT", - GET_FRIENDLY_REMINDER_LIST: "GET_FRIENDLY_REMINDER_LIST", - AUTO_GENERATION_VIDEO: "AUTO_GENERATION_VIDEO", - GET_PROJECT_WORD: "GET_PROJECT_WORD", - AIMODIFY_ONE_WORD: "AIMODIFY_ONE_WORD", - IMPORT_SRT_AND_GET_TIME: "IMPORT_SRT_AND_GET_TIME", - SAVE_NEW_WORD: "SAVE_NEW_WORD", - SAVE_COPYWRITING_INFOMATION: "SAVE_COPYWRITING_INFOMATION", - SAVE_SD_CONFIG: "SAVE_SD_CONFIG", - SAVE_GENERAL_SETTING: "SAVE_GENERAL_SETTING", - GET_VIDEO_CONFIG_MESSAGE: "GET_VIDEO_CONFIG_MESSAGE", - GET_SYSTEM_INSTALL_FONTNAME: "GET_SYSTEM_INSTALL_FONTNAME", - SAVE_ASS_CONFIG: "SAVE_ASS_CONFIG", - DELETE_VIDEO_CONFIG: "DELETE_VIDEO_CONFIG", - SHOW_NEW_WINDOW: "SHOW_NEW_WINDOW", - GET_DRAFT_FILE_LIST: "GET_DRAFT_FILE_LIST", - SELECT_FOLDER: "SELECT_FOLDER", - GET_DRAFT_TEXT_STYLE: "GET_DRAFT_TEXT_STYLE", - GET_TEXT_STYLE_LIST: "GET_TEXT_STYLE_LIST", - DELETE_DRAFT_TEXT_STYLE: "DELETE_DRAFT_TEXT_STYLE", - ADD_DRAFT: "ADD_DRAFT", - RETURN_IMAGE_PROMPT: "RETURN_IMAGE_PROMPT", - RE_GENERATE_IAMGE_ONE: "RE_GENERATE_IAMGE_ONE", - INIT_SD_CONFIG: "INIT_SD_CONFIG", - ADD_IMAGE_TASK_LIST: "ADD_IMAGE_TASK_LIST", - GET_GENERATE_TASK_LIST: "GET_GENERATE_TASK_LIST", - DELETE_IMAGE_TASK_LIST: "DELETE_IMAGE_TASK_LIST", - GENERATE_IMAGWE_IN_SELECT_TASK: "GENERATE_IMAGWE_IN_SELECT_TASK", - GET_MACHINE_ID: "GET_MACHINE_ID", - QUIT_APP: "QUIT_APP", - GET_BAD_PROMPT: "GET_BAD_PROMPT", - SAVE_BAD_PROMPT: "SAVE_BAD_PROMPT", - DELETE_BAD_PROMPT: "DELETE_BAD_PROMPT", - ADD_WEBUI_JSON: "ADD_WEBUI_JSON", - OPEN_GPT_BUY_URL: "OPEN_GPT_BUY_URL", - GET_IAMGE_PROMPT_LIST: "GET_IAMGE_PROMPT_LIST", - GET_ADETAILER_LIST: "GET_ADETAILER_LIST", - SAVE_DETAILER_CONFIG: "SAVE_DETAILER_CONFIG", - OPEN_URL: "OPEN_URL", - GET_VERSION: "GET_VERSION", - GET_FRAME_RETUN: "GET_FRAME_RETUN", - DOWNLOAD_MODEL: "DOWNLOAD_MODEL", - START_STORY_BOARDING: "START_STORY_BOARDING", - SHOW_MESSAGE_DIALOG: "SHOW_MESSAGE_DIALOG", - SHOW_GLOABAL_MESSAGE_DIALOG: "SHOW_GLOABAL_MESSAGE_DIALOG", - IMAGE_TASK_STATUS_REFRESH: "IMAGE_TASK_STATUS_REFRESH", - SAVE_TRIAL_END_TIME: "SAVE_TRIAL_END_TIME", - DOWNLOAD_IMAGE_FILE: "DOWNLOAD_IMAGE_FILE", - OPEN_FOLDER: "OPEN_FOLDER", - VIDEO_GENERATE_STATUS_REFRESH: "VIDEO_GENERATE_STATUS_REFRESH", - AUTO_CONDITION_CHECK: "AUTO_CONDITION_CHECK", - MODIFY_IMAGE_TASK_LIST: "MODIFY_IMAGE_TASK_LIST", - ACTION_AUTO_VIDEO_TASK: "ACTION_AUTO_VIDEO_TASK", - GET_VIDEO_GENERATE_CONFIG: "GET_VIDEO_GENERATE_CONFIG", - TRANSLATE_PROMPT: "TRANSLATE_PROMPT", - TRANSLATE_RETURN_NOW: "TRANSLATE_RETURN_NOW", - TRANSLATE_RETURN_REFRESH: "TRANSLATE_RETURN_REFRESH", - GET_SHOW_MESSAGE: "GET_SHOW_MESSAGE", - AUTO_ANALYZE_CHARACTER: "AUTO_ANALYZE_CHARACTER", - GET_CONFIG_JSON: "GET_CONFIG_JSON", - ORIGINAL_ADD_WEBUI_JSON: "ORIGINAL_ADD_WEBUI_JSON", - GET_PROMPT_JSON: "GET_PROMPT_JSON", - GPT_PROMPT: "GPT_PROMPT", - GPT_GENERATE_PROMPT_RETURN: "GPT_GENERATE_PROMPT_RETURN", - AUTO_SAVE_DATA_JSON: "AUTO_SAVE_DATA_JSON", - ORIGINAL_SD_SINGLE_IMAGE_GENERATE: "ORIGINAL_SD_SINGLE_IMAGE_GENERATE", - SD_ORIGINAL_GENERATE_IMAGE_RETURN: "SD_ORIGINAL_GENERATE_IMAGE_RETURN", - GET_STYLE_IMAGE_SUB_LIST: "GET_STYLE_IMAGE_SUB_LIST", - GET_IMAGE_STYLE_INFOMATION: "GET_IMAGE_STYLE_INFOMATION", - GET_IMAGE_STYLE_MENU: "GET_IMAGE_STYLE_MENU", - GET_GPT_BUSINESS_OPTION: "GET_GPT_BUSINESS_OPTION", - GET_GPT_MODEL_OPTION: "GET_GPT_MODEL_OPTION", - GET_GPT_AUTO_INFERENCE_OPTIONS: "GET_GPT_AUTO_INFERENCE_OPTIONS", - SAVE_DYNAMIC_GPT_OPTION: "SAVE_DYNAMIC_GPT_OPTION", - DELETE_DYNAMIC_GPT_OPTION: "DELETE_DYNAMIC_GPT_OPTION", - TEST_GPT_CONNECTION: "TEST_GPT_CONNECTION", - SAVE_WORD_TXT: "SAVE_WORD_TXT", - GET_KEY_FRAME_CONFIG_DATA: "GET_KEY_FRAME_CONFIG_DATA", - GET_KEYFRAME_OPTIONS: "GET_KEYFRAME_OPTIONS", + OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD', + OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS', + GET_FILE_BASE64: 'GET_FILE_BASE64', + SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY: 'SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY', + GET_DEFINE_CONFIG_JSON_BY_PROPERTY: 'GET_DEFINE_CONFIG_JSON_BY_PROPERTY', + GET_IMAGE_GENERATE_CATEGORY: 'GET_IMAGE_GENERATE_CATEGORY', + SHOW_MAIN_NOTIFICATION: 'SHOW_MAIN_NOTIFICATION', + SHOW_GLOABAL_MESSAGE: 'SHOW_GLOABAL_MESSAGE', + CHECK_MACHINE_ID: 'CHECK_MACHINE_ID', + GET_CUSTOMIZE_GPT_PROMPT: 'GET_CUSTOMIZE_GPT_PROMPT', + GENERATE_GPT_EXAMPLE_OUT: 'GENERATE_GPT_EXAMPLE_OUT', + GET_PERMISSION: 'GET_PERMISSION', + SAVE_IMAGE_TO_OTHER_FOLDER: 'SAVE_IMAGE_TO_OTHER_FOLDER', + GET_IMAGE_AUTO_SAVE_SETTING: 'GET_IMAGE_AUTO_SAVE_SETTING', + SAVE_IMAGE_AUTO_SAVE_SETTING: 'SAVE_IMAGE_AUTO_SAVE_SETTING', + GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS: 'GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS', + MODIFY_GENERATE_TASK_STATUS: 'MODIFY_GENERATE_TASK_STATUS', + DELETE_BACK_TASK: 'DELETE_BACK_TASK', + SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE: 'SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE', + SAVE_KEY_FRAME_SETTING: 'SAVE_KEY_FRAME_SETTING', + MODIFY_SAMPLE_SETTING: 'MODIFY_SAMPLE_SETTING', + GET_SETTING_Dafault_DATA: 'GET_SETTING_Dafault_DATA', + GET_DRAFT_FILE_LIST: 'GET_DRAFT_FILE_LIST', + GET_FRAME: 'GET_FRAME', + PYTHON_ERROR: 'PYTHON_ERROR', + PYTHON_CLOSE: 'PYTHON_CLOSE', + PYTHON_OUTPUT: 'PYTHON_OUTPUT', + RESTART_GENERATE: 'RESTART_GENERATE', + ALIGN_DRAFT_IMG: 'ALIGN_DRAFT_IMG', + ALIGN_DRAFT_IMG_TO_TEXT: 'ALIGN_DRAFT_IMG_TO_TEXT', + REGENERATE_IMAGE_RETUN: 'REGENERATE_IMAGE_RETUN', + GET_SUBFOLDER_LIST: 'GET_SUBFOLDER_LIST', + REFRASH_IMAGWE_DATA: 'REFRASH_IMAGWE_DATA', + GET_IMAGE_PROMPTLIST: 'GET_IMAGE_PROMPTLIST', + SELECT_FILE: 'SELECT_FILE', + IMPROVE_IMAGE_RESOULTION: 'IMPROVE_IMAGE_RESOULTION', + GET_BACKGROUND_MUSIC_CONFIG_LIST: 'GET_BACKGROUND_MUSIC_CONFIG_LIST', + ADD_BACKGROUND_MUSIC_FOLDER: 'ADD_BACKGROUND_MUSIC_FOLDER', + DELETE_CLIP_SETTING: 'DELETE_CLIP_SETTING', + DELETE_FRIENDLY_REMINDER: 'DELETE_FRIENDLY_REMINDER', + MODIFY_INPUT_CROP_JSON: 'MODIFY_INPUT_CROP_JSON', + PUSH_BACK_PROMPT: 'PUSH_BACK_PROMPT', + GET_FRIENDLY_REMINDER_DRAFT: 'GET_FRIENDLY_REMINDER_DRAFT', + GET_FRIENDLY_REMINDER_LIST: 'GET_FRIENDLY_REMINDER_LIST', + AUTO_GENERATION_VIDEO: 'AUTO_GENERATION_VIDEO', + GET_PROJECT_WORD: 'GET_PROJECT_WORD', + AIMODIFY_ONE_WORD: 'AIMODIFY_ONE_WORD', + IMPORT_SRT_AND_GET_TIME: 'IMPORT_SRT_AND_GET_TIME', + SAVE_NEW_WORD: 'SAVE_NEW_WORD', + SAVE_COPYWRITING_INFOMATION: 'SAVE_COPYWRITING_INFOMATION', + SAVE_SD_CONFIG: 'SAVE_SD_CONFIG', + SAVE_GENERAL_SETTING: 'SAVE_GENERAL_SETTING', + GET_VIDEO_CONFIG_MESSAGE: 'GET_VIDEO_CONFIG_MESSAGE', + GET_SYSTEM_INSTALL_FONTNAME: 'GET_SYSTEM_INSTALL_FONTNAME', + SAVE_ASS_CONFIG: 'SAVE_ASS_CONFIG', + DELETE_VIDEO_CONFIG: 'DELETE_VIDEO_CONFIG', + SHOW_NEW_WINDOW: 'SHOW_NEW_WINDOW', + GET_DRAFT_FILE_LIST: 'GET_DRAFT_FILE_LIST', + SELECT_FOLDER: 'SELECT_FOLDER', + GET_DRAFT_TEXT_STYLE: 'GET_DRAFT_TEXT_STYLE', + GET_TEXT_STYLE_LIST: 'GET_TEXT_STYLE_LIST', + DELETE_DRAFT_TEXT_STYLE: 'DELETE_DRAFT_TEXT_STYLE', + ADD_DRAFT: 'ADD_DRAFT', + RETURN_IMAGE_PROMPT: 'RETURN_IMAGE_PROMPT', + RE_GENERATE_IAMGE_ONE: 'RE_GENERATE_IAMGE_ONE', + INIT_SD_CONFIG: 'INIT_SD_CONFIG', + ADD_IMAGE_TASK_LIST: 'ADD_IMAGE_TASK_LIST', + GET_GENERATE_TASK_LIST: 'GET_GENERATE_TASK_LIST', + DELETE_IMAGE_TASK_LIST: 'DELETE_IMAGE_TASK_LIST', + GENERATE_IMAGWE_IN_SELECT_TASK: 'GENERATE_IMAGWE_IN_SELECT_TASK', + GET_MACHINE_ID: 'GET_MACHINE_ID', + QUIT_APP: 'QUIT_APP', + GET_BAD_PROMPT: 'GET_BAD_PROMPT', + SAVE_BAD_PROMPT: 'SAVE_BAD_PROMPT', + DELETE_BAD_PROMPT: 'DELETE_BAD_PROMPT', + ADD_WEBUI_JSON: 'ADD_WEBUI_JSON', + OPEN_GPT_BUY_URL: 'OPEN_GPT_BUY_URL', + GET_IAMGE_PROMPT_LIST: 'GET_IAMGE_PROMPT_LIST', + GET_ADETAILER_LIST: 'GET_ADETAILER_LIST', + SAVE_DETAILER_CONFIG: 'SAVE_DETAILER_CONFIG', + OPEN_URL: 'OPEN_URL', + GET_VERSION: 'GET_VERSION', + GET_FRAME_RETUN: 'GET_FRAME_RETUN', + DOWNLOAD_MODEL: 'DOWNLOAD_MODEL', + START_STORY_BOARDING: 'START_STORY_BOARDING', + SHOW_MESSAGE_DIALOG: 'SHOW_MESSAGE_DIALOG', + SHOW_GLOABAL_MESSAGE_DIALOG: 'SHOW_GLOABAL_MESSAGE_DIALOG', + IMAGE_TASK_STATUS_REFRESH: 'IMAGE_TASK_STATUS_REFRESH', + SAVE_TRIAL_END_TIME: 'SAVE_TRIAL_END_TIME', + DOWNLOAD_IMAGE_FILE: 'DOWNLOAD_IMAGE_FILE', + OPEN_FOLDER: 'OPEN_FOLDER', + VIDEO_GENERATE_STATUS_REFRESH: 'VIDEO_GENERATE_STATUS_REFRESH', + AUTO_CONDITION_CHECK: 'AUTO_CONDITION_CHECK', + MODIFY_IMAGE_TASK_LIST: 'MODIFY_IMAGE_TASK_LIST', + ACTION_AUTO_VIDEO_TASK: 'ACTION_AUTO_VIDEO_TASK', + GET_VIDEO_GENERATE_CONFIG: 'GET_VIDEO_GENERATE_CONFIG', + TRANSLATE_PROMPT: 'TRANSLATE_PROMPT', + TRANSLATE_RETURN_NOW: 'TRANSLATE_RETURN_NOW', + TRANSLATE_RETURN_REFRESH: 'TRANSLATE_RETURN_REFRESH', + GET_SHOW_MESSAGE: 'GET_SHOW_MESSAGE', + AUTO_ANALYZE_CHARACTER: 'AUTO_ANALYZE_CHARACTER', + GET_CONFIG_JSON: 'GET_CONFIG_JSON', + ORIGINAL_ADD_WEBUI_JSON: 'ORIGINAL_ADD_WEBUI_JSON', + GET_PROMPT_JSON: 'GET_PROMPT_JSON', + GPT_PROMPT: 'GPT_PROMPT', + GPT_GENERATE_PROMPT_RETURN: 'GPT_GENERATE_PROMPT_RETURN', + AUTO_SAVE_DATA_JSON: 'AUTO_SAVE_DATA_JSON', + ORIGINAL_SD_SINGLE_IMAGE_GENERATE: 'ORIGINAL_SD_SINGLE_IMAGE_GENERATE', + SD_ORIGINAL_GENERATE_IMAGE_RETURN: 'SD_ORIGINAL_GENERATE_IMAGE_RETURN', + GET_STYLE_IMAGE_SUB_LIST: 'GET_STYLE_IMAGE_SUB_LIST', + GET_IMAGE_STYLE_INFOMATION: 'GET_IMAGE_STYLE_INFOMATION', + GET_IMAGE_STYLE_MENU: 'GET_IMAGE_STYLE_MENU', + GET_GPT_BUSINESS_OPTION: 'GET_GPT_BUSINESS_OPTION', + GET_GPT_MODEL_OPTION: 'GET_GPT_MODEL_OPTION', + GET_GPT_AUTO_INFERENCE_OPTIONS: 'GET_GPT_AUTO_INFERENCE_OPTIONS', + SAVE_DYNAMIC_GPT_OPTION: 'SAVE_DYNAMIC_GPT_OPTION', + DELETE_DYNAMIC_GPT_OPTION: 'DELETE_DYNAMIC_GPT_OPTION', + TEST_GPT_CONNECTION: 'TEST_GPT_CONNECTION', + SAVE_WORD_TXT: 'SAVE_WORD_TXT', + GET_KEY_FRAME_CONFIG_DATA: 'GET_KEY_FRAME_CONFIG_DATA', + GET_KEYFRAME_OPTIONS: 'GET_KEYFRAME_OPTIONS', - QUEUE_BATCH: { - SD_ORIGINAL_GENERATE_IMAGE: "SD_ORIGINAL_GENERATE_IMAGE", - SD_ORIGINAL_GPT_PROMPT: "SD_ORIGINAL_GPT_PROMPT", - SD_BACKSTEP_GENERATE_IMAGE: "SD_BACKSTEP_GENERATE_IMAGE", - MJ_ORIGINAL_GENERATE_IMAGE: "MJ_ORIGINAL_GENERATE_IMAGE", - LOCAL_IMAGE_IMPROVE: "LOCAL_IMAGE_IMPROVE", - AUTO_VIDEO_GENERATE: "AUTO_VIDEO_GENERATE", - AUTO_VIDEO_GENERATE_SINGLE: "AUTO_VIDEO_GENERATE_SINGLE", - TRANSLATE_PROMPT: "TRANSLATE_PROMPT", - TRANSLATE_RETURN_NOW_TASK: "TRANSLATE_RETURN_NOW_TASK", - IMAGE_SAVE_TO_OTHER_FOLDER: "IMAGE_SAVE_TO_OTHER_FOLDER", - SAVE_FILE_QUEUE: "SAVE_FILE_QUEUE", - AUTO_SAVE_DATA_JSON: "AUTO_SAVE_DATA_JSON" - }, - PERMISSIONS: { - NORMAL_PERMISSION: "NORMAL_PERMISSION", - AUTO_SAVE_IMAGE_PERMISSION: "AUTO_SAVE_IMAGE_PERMISSION", - }, - SD: { - LOAD_SD_SERVICE_DATA: "LOAD_SD_SERVICE_DATA", - TXT2IMG: "TXT2IMG", - }, - MJ: { - SAVE_WORD_SRT: "SAVE_WORD_SRT", - GET_MJ_CONFIG_SRT_INFORMATION: "GET_MJ_CONFIG_SRT_INFORMATION", - GET_TAG_DATA_BY_TYPE_AND_PROPERTY: "GET_TAG_DATA_BY_TYPE_AND_PROPERTY", - SAVE_TAG_PROPERTY_DATA: "SAVE_TAG_PROPERTY_DATA", - DELETE_TAG_PROPERTY_DATA: "DELETE_TAG_PROPERTY_DATA", - GET_TAG_SELECT_MODEL: "GET_TAG_SELECT_MODEL", - TRANSLATE_RETURN_NOW_TASK: "TRANSLATE_RETURN_NOW_TASK", - ORIGINAL_MJ_IMAGE_GENERATE: "ORIGINAL_MJ_IMAGE_GENERATE", - GET_CHANNEL_ROBOTS: "GET_CHANNEL_ROBOTS", - GET_MJ_GENERATE_CATEGORY: "GET_MJ_GENERATE_CATEGORY", - IMAGE_SPLIT: "IMAGE_SPLIT", - ADD_MJ_BAD_PROMPT: "ADD_MJ_BAD_PROMPT", - MJ_BAD_PROMPT_CHECK: "MJ_BAD_PROMPT_CHECK", - GET_GENERATED_MJ_IMAGE_AND_SPLIT: "GET_GENERATED_MJ_IMAGE_AND_SPLIT", - DOWNLOAD_IMAGE_URL_AND_SPLIT: "DOWNLOAD_IMAGE_URL_AND_SPLIT", - GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE', - GET_MJ_IMAGE_ROBOT_MODEL: "GET_MJ_IMAGE_ROBOT_MODEL", - MACTH_USER_RETURN: "MACTH_USER_RETURN", - AUTO_MATCH_USER: "AUTO_MATCH_USER", - }, - DISCORD: { - OPERATE_REFRASH_DISCORD_URL: "OPERATE_REFRASH_DISCORD_URL", - GET_DISCORD_WINDOW_URL: "GET_DISCORD_WINDOW_URL", - CREATE_MESSAGE: "CREATE_MESSAGE", - UPDATE_MESSAGE: "UPDATE_MESSAGE", - DELETE_MESSAGE: "DELETE_MESSAGE", - MAIN_DISCORD_MESSAGE_CHANGE: "MAIN_DISCORD_MESSAGE_CHANGE", - }, - DISCORD_REQUEST_LISTENER_TYPE: { - INPUT_MODEL_IMAGINE_REQUEST: "INPUT_MODEL_IMAGINE_REQUEST", - }, - DISCORD_SIMPLE_DATA_TYPE: { - URL: "URL", - TOKEN: "TOKEN", - }, - MAIN: { - OPEN_DISCORD_WINDOW: "OPEN_DISCORD_WINDOW" - }, - IMG: { - ONE_SPLIT_FOUR: "ONE_SPLIT_FOUR", - BASE64_TO_FILE: "BASE64_TO_FILE", - PROCESS_IMAGE: "PROCESS_IMAGE", - BATCH_PROCESS_IMAGE: "BATCH_PROCESS_IMAGE", - BATCH_PROCESS_IMAGE_RESULT: "BATCH_PROCESS_IMAGE_RESULT" - }, - BOOK: { - GET_BOOK_TYPE: "GET_BOOK_TYPE", - ADD_OR_MODIFY_BOOK: "ADD_OR_MODIFY_BOOK", - GET_BOOK_DATA: "GET_BOOK_DATA", - GET_FRAME_DATA: "GET_FRAME_DATA", - GET_BOOK_TASK_DATA: "GET_BOOK_TASK_DATA" - }, - SYSTEM: { - OPEN_FILE: "OPEN_FILE", - RETURN_LOGGER: "RETURN_LOGGER", - }, - 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" - }, - PROMPT: { - GET_SORT_OPTIONS: "GET_SORT_OPTIONS", - SAVE_PROMPT_SORT_DATA: "SAVE_PROMPT_SORT_DATA", - GET_PROMPT_SORT_DATA: "GET_PROMPT_SORT_DATA", - OPEN_PROMPT_FILE_TXT: "OPEN_PROMPT_FILE_TXT" - } -} \ No newline at end of file + QUEUE_BATCH: { + SD_ORIGINAL_GENERATE_IMAGE: 'SD_ORIGINAL_GENERATE_IMAGE', + SD_ORIGINAL_GPT_PROMPT: 'SD_ORIGINAL_GPT_PROMPT', + SD_BACKSTEP_GENERATE_IMAGE: 'SD_BACKSTEP_GENERATE_IMAGE', + MJ_ORIGINAL_GENERATE_IMAGE: 'MJ_ORIGINAL_GENERATE_IMAGE', + LOCAL_IMAGE_IMPROVE: 'LOCAL_IMAGE_IMPROVE', + AUTO_VIDEO_GENERATE: 'AUTO_VIDEO_GENERATE', + AUTO_VIDEO_GENERATE_SINGLE: 'AUTO_VIDEO_GENERATE_SINGLE', + TRANSLATE_PROMPT: 'TRANSLATE_PROMPT', + TRANSLATE_RETURN_NOW_TASK: 'TRANSLATE_RETURN_NOW_TASK', + IMAGE_SAVE_TO_OTHER_FOLDER: 'IMAGE_SAVE_TO_OTHER_FOLDER', + SAVE_FILE_QUEUE: 'SAVE_FILE_QUEUE', + AUTO_SAVE_DATA_JSON: 'AUTO_SAVE_DATA_JSON' + }, + PERMISSIONS: { + NORMAL_PERMISSION: 'NORMAL_PERMISSION', + AUTO_SAVE_IMAGE_PERMISSION: 'AUTO_SAVE_IMAGE_PERMISSION' + }, + SD: { + LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA', + TXT2IMG: 'TXT2IMG' + }, + MJ: { + SAVE_WORD_SRT: 'SAVE_WORD_SRT', + GET_MJ_CONFIG_SRT_INFORMATION: 'GET_MJ_CONFIG_SRT_INFORMATION', + GET_TAG_DATA_BY_TYPE_AND_PROPERTY: 'GET_TAG_DATA_BY_TYPE_AND_PROPERTY', + SAVE_TAG_PROPERTY_DATA: 'SAVE_TAG_PROPERTY_DATA', + DELETE_TAG_PROPERTY_DATA: 'DELETE_TAG_PROPERTY_DATA', + GET_TAG_SELECT_MODEL: 'GET_TAG_SELECT_MODEL', + TRANSLATE_RETURN_NOW_TASK: 'TRANSLATE_RETURN_NOW_TASK', + ORIGINAL_MJ_IMAGE_GENERATE: 'ORIGINAL_MJ_IMAGE_GENERATE', + GET_CHANNEL_ROBOTS: 'GET_CHANNEL_ROBOTS', + GET_MJ_GENERATE_CATEGORY: 'GET_MJ_GENERATE_CATEGORY', + IMAGE_SPLIT: 'IMAGE_SPLIT', + ADD_MJ_BAD_PROMPT: 'ADD_MJ_BAD_PROMPT', + MJ_BAD_PROMPT_CHECK: 'MJ_BAD_PROMPT_CHECK', + GET_GENERATED_MJ_IMAGE_AND_SPLIT: 'GET_GENERATED_MJ_IMAGE_AND_SPLIT', + DOWNLOAD_IMAGE_URL_AND_SPLIT: 'DOWNLOAD_IMAGE_URL_AND_SPLIT', + GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE', + GET_MJ_IMAGE_ROBOT_MODEL: 'GET_MJ_IMAGE_ROBOT_MODEL', + MACTH_USER_RETURN: 'MACTH_USER_RETURN', + AUTO_MATCH_USER: 'AUTO_MATCH_USER' + }, + DISCORD: { + OPERATE_REFRASH_DISCORD_URL: 'OPERATE_REFRASH_DISCORD_URL', + GET_DISCORD_WINDOW_URL: 'GET_DISCORD_WINDOW_URL', + CREATE_MESSAGE: 'CREATE_MESSAGE', + UPDATE_MESSAGE: 'UPDATE_MESSAGE', + DELETE_MESSAGE: 'DELETE_MESSAGE', + MAIN_DISCORD_MESSAGE_CHANGE: 'MAIN_DISCORD_MESSAGE_CHANGE' + }, + DISCORD_REQUEST_LISTENER_TYPE: { + INPUT_MODEL_IMAGINE_REQUEST: 'INPUT_MODEL_IMAGINE_REQUEST' + }, + DISCORD_SIMPLE_DATA_TYPE: { + URL: 'URL', + TOKEN: 'TOKEN' + }, + MAIN: { + OPEN_DISCORD_WINDOW: 'OPEN_DISCORD_WINDOW' + }, + IMG: { + ONE_SPLIT_FOUR: 'ONE_SPLIT_FOUR', + BASE64_TO_FILE: 'BASE64_TO_FILE', + PROCESS_IMAGE: 'PROCESS_IMAGE', + BATCH_PROCESS_IMAGE: 'BATCH_PROCESS_IMAGE', + BATCH_PROCESS_IMAGE_RESULT: 'BATCH_PROCESS_IMAGE_RESULT' + }, + BOOK: { + GET_BOOK_TYPE: 'GET_BOOK_TYPE', + ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK', + GET_BOOK_DATA: 'GET_BOOK_DATA', + GET_FRAME_DATA: 'GET_FRAME_DATA', + GET_BOOK_TASK_DATA: 'GET_BOOK_TASK_DATA', + AUTO_ACTION: 'AUTO_ACTION' + }, + SYSTEM: { + OPEN_FILE: 'OPEN_FILE', + RETURN_LOGGER: 'RETURN_LOGGER' + }, + 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' + }, + PROMPT: { + GET_SORT_OPTIONS: 'GET_SORT_OPTIONS', + SAVE_PROMPT_SORT_DATA: 'SAVE_PROMPT_SORT_DATA', + GET_PROMPT_SORT_DATA: 'GET_PROMPT_SORT_DATA', + OPEN_PROMPT_FILE_TXT: 'OPEN_PROMPT_FILE_TXT' + } +} diff --git a/src/main/IPCEvent/settingIpc.js b/src/main/IPCEvent/settingIpc.js index 6194efd..9c20f0f 100644 --- a/src/main/IPCEvent/settingIpc.js +++ b/src/main/IPCEvent/settingIpc.js @@ -1,123 +1,217 @@ -const { - ipcMain, app -} = require("electron") +const { ipcMain, app } = require('electron') import { DEFINE_STRING } from '../../define/define_string' -import { GetDataByTypeAndProperty, SaveDataByTypeAndProperty, DeleteDataByTypeAndProperty } from '../../define/setting/dynamicSetting'; import { - Setting -} from '../setting/setting' -let setting = new Setting(global); -import { BasicSetting } from '../setting/basicSetting'; -let basicSetting = new BasicSetting(); -import { MJSetting } from '../setting/mjSetting'; -let mjSetting = new MJSetting(); - + GetDataByTypeAndProperty, + SaveDataByTypeAndProperty, + DeleteDataByTypeAndProperty +} from '../../define/setting/dynamicSetting' +import { Setting } from '../setting/setting' +let setting = new Setting(global) +import { BasicSetting } from '../setting/basicSetting' +let basicSetting = new BasicSetting() +import { MJSetting } from '../setting/mjSetting' +let mjSetting = new MJSetting() async function SettingIpc() { - // 获取背景音乐配置列表 - ipcMain.handle(DEFINE_STRING.GET_BACKGROUND_MUSIC_CONFIG_LIST, async (event) => await setting.GetBackGroundMusicConfigList()); + ipcMain.handle( + DEFINE_STRING.GET_BACKGROUND_MUSIC_CONFIG_LIST, + async (event) => await setting.GetBackGroundMusicConfigList() + ) // 获取剪映关键帧配置列表 - ipcMain.handle(DEFINE_STRING.GET_KEYFRAME_OPTIONS, async (event) => await setting.GetKeyFrameOptions()); + ipcMain.handle( + DEFINE_STRING.GET_KEYFRAME_OPTIONS, + async (event) => await setting.GetKeyFrameOptions() + ) // 保存剪映关键帧配置 - ipcMain.handle(DEFINE_STRING.SAVE_KEY_FRAME_SETTING, async (event, value) => await setting.SaveKeyFrameSetting(value)); + ipcMain.handle( + DEFINE_STRING.SAVE_KEY_FRAME_SETTING, + async (event, value) => await setting.SaveKeyFrameSetting(value) + ) // 监听添加背景音乐文件 - ipcMain.handle(DEFINE_STRING.ADD_BACKGROUND_MUSIC_FOLDER, async (event, value) => await setting.AddBackgroundMusicFolder(value)) + ipcMain.handle( + DEFINE_STRING.ADD_BACKGROUND_MUSIC_FOLDER, + async (event, value) => await setting.AddBackgroundMusicFolder(value) + ) // 删除剪映的样式设置 - ipcMain.handle(DEFINE_STRING.DELETE_DRAFT_TEXT_STYLE, async (event, value) => await setting.deleteClipSetting("text_style", value)); + ipcMain.handle( + DEFINE_STRING.DELETE_DRAFT_TEXT_STYLE, + async (event, value) => await setting.deleteClipSetting('text_style', value) + ) // 删除剪映的背景音乐设置 - ipcMain.handle(DEFINE_STRING.DELETE_CLIP_SETTING, async (event, value) => await setting.deleteClipSetting("background_music_setting", value)); + ipcMain.handle( + DEFINE_STRING.DELETE_CLIP_SETTING, + async (event, value) => await setting.deleteClipSetting('background_music_setting', value) + ) // 删除剪映的友情提示设置 - ipcMain.handle(DEFINE_STRING.DELETE_FRIENDLY_REMINDER, async (event, value) => await setting.deleteClipSetting("friendly_reminder_setting", value)); + ipcMain.handle( + DEFINE_STRING.DELETE_FRIENDLY_REMINDER, + async (event, value) => await setting.deleteClipSetting('friendly_reminder_setting', value) + ) // 监听获取SD配置任务 - ipcMain.handle(DEFINE_STRING.INIT_SD_CONFIG, async (event, value) => await setting.InitSDConfig()); + ipcMain.handle(DEFINE_STRING.INIT_SD_CONFIG, async (event, value) => await setting.InitSDConfig()) // 获取主页显示信息 ipcMain.handle(DEFINE_STRING.GET_SHOW_MESSAGE, async (event) => await setting.GetShowMessage()) // 获取关键帧的配置数据 - ipcMain.handle(DEFINE_STRING.GET_KEY_FRAME_CONFIG_DATA, async (event) => await setting.GetKeyFrameConfigData()); + ipcMain.handle( + DEFINE_STRING.GET_KEY_FRAME_CONFIG_DATA, + async (event) => await setting.GetKeyFrameConfigData() + ) // 删除后台队列任务 - ipcMain.handle(DEFINE_STRING.DELETE_BACK_TASK, async (event, value) => await setting.RemoveTask(value)); + ipcMain.handle( + DEFINE_STRING.DELETE_BACK_TASK, + async (event, value) => await setting.RemoveTask(value) + ) // 获取自动保存图片的分类方式 - ipcMain.handle(DEFINE_STRING.GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS, async (event) => await setting.GetAutoSaveImageClassifyOptions()); + ipcMain.handle( + DEFINE_STRING.GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS, + async (event) => await setting.GetAutoSaveImageClassifyOptions() + ) // 保存图片自动保存的配置 - ipcMain.handle(DEFINE_STRING.SAVE_IMAGE_AUTO_SAVE_SETTING, async (event, value) => await setting.SaveImageAutoSaveSetting(value)); + ipcMain.handle( + DEFINE_STRING.SAVE_IMAGE_AUTO_SAVE_SETTING, + async (event, value) => await setting.SaveImageAutoSaveSetting(value) + ) // 获取当前的自动保存图片的设置 - ipcMain.handle(DEFINE_STRING.GET_IMAGE_AUTO_SAVE_SETTING, async (event) => await setting.GetImageAutoSaveSetting()); + ipcMain.handle( + DEFINE_STRING.GET_IMAGE_AUTO_SAVE_SETTING, + async (event) => await setting.GetImageAutoSaveSetting() + ) // 开始手动保存图片 - ipcMain.handle(DEFINE_STRING.SAVE_IMAGE_TO_OTHER_FOLDER, async (event, value) => await setting.SaveImageToOtherFolder(value)); + ipcMain.handle( + DEFINE_STRING.SAVE_IMAGE_TO_OTHER_FOLDER, + async (event, value) => await setting.SaveImageToOtherFolder(value) + ) // 检查机器码是否存在 - ipcMain.handle(DEFINE_STRING.CHECK_MACHINE_ID, async (event, value) => await setting.CheckMachineId(value)); + ipcMain.handle( + DEFINE_STRING.CHECK_MACHINE_ID, + async (event, value) => await setting.CheckMachineId(value) + ) //修改剪映草稿配置 - ipcMain.handle(DEFINE_STRING.MODIFY_SAMPLE_SETTING, async (event, value) => await setting.ModifySampleSetting(value)); + ipcMain.handle( + DEFINE_STRING.MODIFY_SAMPLE_SETTING, + async (event, value) => await setting.ModifySampleSetting(value) + ) // 获取选择角色场景模式的options - ipcMain.handle(DEFINE_STRING.MJ.GET_TAG_SELECT_MODEL, async (event) => await setting.GetRoleSceneModeOptions()); + ipcMain.handle( + DEFINE_STRING.MJ.GET_TAG_SELECT_MODEL, + async (event) => await setting.GetRoleSceneModeOptions() + ) // 获取当前生成图片的生图方式(sd,mj,d3) - ipcMain.handle(DEFINE_STRING.GET_IMAGE_GENERATE_CATEGORY, async (event) => await setting.GetImageGenerateCategory()); + ipcMain.handle( + DEFINE_STRING.GET_IMAGE_GENERATE_CATEGORY, + async (event) => await setting.GetImageGenerateCategory() + ) // // 获取指定的配置文件里面指定的属性的数据 - ipcMain.handle(DEFINE_STRING.GET_DEFINE_CONFIG_JSON_BY_PROPERTY, async (event, value) => await setting.GetDefineConfigJsonByProperty(value)) + ipcMain.handle( + DEFINE_STRING.GET_DEFINE_CONFIG_JSON_BY_PROPERTY, + async (event, value) => await setting.GetDefineConfigJsonByProperty(value) + ) // // 保存指定的配置文件里面指定的属性的数据 - ipcMain.handle(DEFINE_STRING.SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY, async (event, value) => await setting.SaveDefineConfigJsonByProperty(value)) - + ipcMain.handle( + DEFINE_STRING.SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY, + async (event, value) => await setting.SaveDefineConfigJsonByProperty(value) + ) //#region 动态设置(只是动态设置) // 获取动态配置的的指定主分类,指定的属性的数据(只是获取动态的,type定死了dynamic) - ipcMain.handle(DEFINE_STRING.SETTING.GET_DATA_BY_TYPE_AND_PROPERTY, async (event, value) => await GetDataByTypeAndProperty(value)); + ipcMain.handle( + DEFINE_STRING.SETTING.GET_DATA_BY_TYPE_AND_PROPERTY, + async (event, value) => await GetDataByTypeAndProperty(value) + ) // 保存动态配置的的指定主分类,指定的属性的数据 - ipcMain.handle(DEFINE_STRING.SETTING.SAVE_DATA_BY_TYPE_AND_PROPERTY, async (event, value) => await SaveDataByTypeAndProperty(value)); + ipcMain.handle( + DEFINE_STRING.SETTING.SAVE_DATA_BY_TYPE_AND_PROPERTY, + async (event, value) => await SaveDataByTypeAndProperty(value) + ) // 删除动态配置的的指定主分类,指定的属性的数据 - ipcMain.handle(DEFINE_STRING.SETTING.DELETE_DATA_BY_TYPE_AND_PROPERTY, async (event, value) => await DeleteDataByTypeAndProperty(value)); + ipcMain.handle( + DEFINE_STRING.SETTING.DELETE_DATA_BY_TYPE_AND_PROPERTY, + async (event, value) => await DeleteDataByTypeAndProperty(value) + ) //#endregion //#region 基础设置 // 获取软件的基础设置(初始的时候执行一次) - ipcMain.handle(DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING, async (event) => await basicSetting.GetSoftwareSetting()); + ipcMain.handle( + DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING, + async (event) => await basicSetting.GetSoftwareSetting() + ) // 保存软件的基础设置 - ipcMain.handle(DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING, async (event, value) => await basicSetting.SaveSoftWareSetting(value)); + ipcMain.handle( + DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING, + async (event, value) => await basicSetting.SaveSoftWareSetting(value) + ) // 返回组件尺寸的大小的数据(通用) - ipcMain.handle(DEFINE_STRING.SETTING.GET_COMPONENT_SIZE, async (event) => basicSetting.GetComponentSize()); + ipcMain.handle(DEFINE_STRING.SETTING.GET_COMPONENT_SIZE, async (event) => + basicSetting.GetComponentSize() + ) //#endregion //#region MJ 设置 // 获取MJ基础设置信息 - ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING, async (event, value) => mjSetting.GetMJSetting(value)); + ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING, async (event, value) => + mjSetting.GetMJSetting(value) + ) // 保存MJ的基础设置信息 - ipcMain.handle(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, async (event, value) => mjSetting.UpdateMJSetting(value)); + ipcMain.handle(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, async (event, value) => + mjSetting.UpdateMJSetting(value) + ) // 获取MJ的所有设置 - ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA, async (event) => mjSetting.GetMJSettingTreeData()); + ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA, async (event) => + mjSetting.GetMJSettingTreeData() + ) // 保存MJ的所有设置 - ipcMain.handle(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, async (event, value) => mjSetting.SaveMJSettingTreeData(value)); + ipcMain.handle(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, async (event, value) => + mjSetting.SaveMJSettingTreeData(value) + ) + + // 获取所有的代理MJ信息 + ipcMain.handle(DEFINE_STRING.SETTING.GET_REMOTE_MJ_SETTINGS, async (event) => + mjSetting.GetRemoteMJSettings() + ) + + // 创建新的代理MJ信息 + ipcMain.handle(DEFINE_STRING.SETTING.ADD_REMOTE_MJ_SETTING, async (event, value) => + mjSetting.AddRemoteMJSetting(value) + ) + + // 修改MJ账号并重连 + ipcMain.handle(DEFINE_STRING.SETTING.UPDATE_REMOTE_MJ_SETTING, async (event, value) => + mjSetting.UpdateRemoteMJSetting(value) + ) + + // 删除指定的MJ账号 + ipcMain.handle(DEFINE_STRING.SETTING.DELETE_REMOTE_MJ_SETTING, async (event, value) => + mjSetting.DeleteRemoteMJSetting(value) + ) - // MJ代理模式账号同步 - ipcMain.handle(DEFINE_STRING.SETTING.MJ_REMOTE_ACCOUNT_SYNC, async (event) => mjSetting.MjRemoteAccountSync()); //#endregion - } -export { - SettingIpc -} \ No newline at end of file +export { SettingIpc } diff --git a/src/main/Original/MJOriginalImageGenerate.js b/src/main/Original/MJOriginalImageGenerate.js index 17c2f37..62268b5 100644 --- a/src/main/Original/MJOriginalImageGenerate.js +++ b/src/main/Original/MJOriginalImageGenerate.js @@ -1,688 +1,730 @@ -import { DEFINE_STRING } from "../../define/define_string"; +import { DEFINE_STRING } from '../../define/define_string' import { AsyncQueue } from '../quene' import { PublicMethod } from '../Public/publicMethod' import { ImageStyleDefine } from '../../define/iamgeStyleDefine' -import { DiscordSimple } from "../discord/discordSimple"; -import { DiscordWorker } from "../discord/discordWorker"; -import { Tools } from "../tools"; +import { DiscordSimple } from '../discord/discordSimple' +import { DiscordWorker } from '../discord/discordWorker' +import { Tools } from '../tools' import path from 'path' import sharp from 'sharp' -import { define } from "../../define/define"; -import { AwesomeHelp } from "awesome-js"; -import { checkStringValueAddSuffix, errorMessage, successMessage } from "../generalTools"; -import { ImageSetting } from "../../define/setting/imageSetting"; -import { DiscordAPI } from "../../api/discordApi"; -import { GPT } from "../Public/GPT"; -import { TagDefine } from "../../define/tagDefine"; -import { cloneDeep } from "lodash"; -import { LOGGER_DEFINE } from "../../define/logger_define"; -import { MJImageType } from "../../define/enum/mjEnum"; -import { MJSettingService } from "../../define/db/service/SoftWare/mjSettingService"; -const { v4: uuidv4 } = require('uuid'); +import { define } from '../../define/define' +import { AwesomeHelp } from 'awesome-js' +import { checkStringValueAddSuffix, errorMessage, successMessage } from '../generalTools' +import { ImageSetting } from '../../define/setting/imageSetting' +import { DiscordAPI } from '../../api/discordApi' +import { GPT } from '../Public/GPT' +import { TagDefine } from '../../define/tagDefine' +import { cloneDeep } from 'lodash' +import { LOGGER_DEFINE } from '../../define/logger_define' +import { MJImageType } from '../../define/enum/mjEnum' +import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService' +const { v4: uuidv4 } = require('uuid') /** * MJ原创生图的类 */ export class MJOriginalImageGenerate { - constructor(global) { - this.global = global; - this.pm = new PublicMethod(global); - this.discordWorker = new DiscordWorker(); - this.tools = new Tools(); - this.discordAPI = new DiscordAPI(); - this.gpt = new GPT(global); - this.tagDefine = new TagDefine(global); - } - /** - * 返回指定的人物到前端 - * @param {*} data - */ - sendChangeMessage(data, message_name = DEFINE_STRING.DISCORD.MAIN_DISCORD_MESSAGE_CHANGE) { - this.global.newWindow[0].win.webContents.send(message_name, data); - } + constructor(global) { + this.global = global + this.pm = new PublicMethod(global) + this.discordWorker = new DiscordWorker() + this.tools = new Tools() + this.discordAPI = new DiscordAPI() + this.gpt = new GPT(global) + this.tagDefine = new TagDefine(global) + } + /** + * 返回指定的人物到前端 + * @param {*} data + */ + sendChangeMessage(data, message_name = DEFINE_STRING.DISCORD.MAIN_DISCORD_MESSAGE_CHANGE) { + this.global.newWindow[0].win.webContents.send(message_name, data) + } - /** - * 通过文本自动匹配数据 - * @param {*} value - */ - async AutoMatchUser(value) { - try { - value = JSON.parse(value); - // 获取所有的角色数据,包括别名 - // 获取所有的角色数据 - let character_tags = await this.tagDefine.getTagDataByTypeAndProperty("dynamic", "character_tags"); - if (character_tags.code == 0) { - return errorMessage("获取角色数据错误,错误信息如下:" + character_tags.message, LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) - } - character_tags = character_tags.data; - if (character_tags.length == 0) { - return errorMessage("请先添加角色数据", LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) - } - let character_tags_data = []; - for (let i = 0; i < character_tags.length; i++) { - let item = character_tags[i]; - // 这边还要判断是不是显示(只有显示的才hi自动匹配) - if (!item.hasOwnProperty("isShow") || !item.isShow) { - continue; - } - - let temp_name = [item.label]; - // 判断当前的数是不是存在别名 - if (item.children && item.children.length > 0) { - for (let j = 0; j < item.children.length; j++) { - const element = item.children[j]; - temp_name.push(element.label); - } - } - character_tags_data.push({ - key: item.key, - value: item.value, - names: temp_name - }) - } - if (character_tags_data.length == 0) { - return errorMessage("当前没有显示的角色数据,请先选择哪些是要显示的角色数据", LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) - } - - - for (let i = 0; i < value.length; i++) { - const element = value[i]; - - let res_data = { - code: 1, - id: element.id, // 当前 data 的ID - match_character: [], - } - - // 获取当前的字幕数据 - let temp_sub = []; - for (let j = 0; element.suValue && j < element.suValue.length; j++) { - const element = array[j]; - temp_sub.push(element.srt_value); - } - let word = ""; - if (temp_sub.length == 0) { - word = element.after_gpt; - } else { - word = temp_sub.join(","); - } - - let match_keys = []; - - // 开始循环判断,只要又一个满足就跳出新婚换 - for (let j = 0; j < character_tags_data.length; j++) { - const item = character_tags_data[j]; - let names = AwesomeHelp.makeSensitiveMap(item.names); - // 开始判断 - let name_res = AwesomeHelp.checkSensitiveWord(word, false, names); - if (name_res.size > 0) { - match_keys.push(item.key); - } - } - - // 判断是不是又匹配到的数据 - if (match_keys.length > 0) { - // 进行数据的处理,通过对应的key,获取对应的数据,将所有的数进行返回 - for (let i = 0; i < match_keys.length; i++) { - const item = match_keys[i]; - let index = character_tags.findIndex(x => x.key == item); - if (index == -1) { - continue; - } - let temp_item_data = cloneDeep(character_tags[index]); - if (temp_item_data.children) { - delete temp_item_data.children - } - res_data.match_character.push(temp_item_data) - } - } - - // 开始往前端传递数据 - this.sendChangeMessage(res_data, DEFINE_STRING.MJ.MACTH_USER_RETURN); - } - return successMessage(null, "人物标签自动匹配完成", LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) - } catch (error) { - return errorMessage("通过文本自动匹配数据错误,错误信息如下:" + error.message, LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) - } - } - - - /** - * 初始化MJ设置 - */ - async InitMjSetting() { - let mjSetting_res = await ImageSetting.GetDefineConfigJsonByProperty(JSON.stringify(['img_base', 'mj_config', false, null])); - if (mjSetting_res.code == 0 || !mjSetting_res.data) { - throw new Error("请先添加MJ配置") - } - let mjSetting = mjSetting_res.data; - return mjSetting; - } - - /** - * 初始化MJ API的URL - */ - async InitMJAPIUrl(id) { - let mj_api = (await this.gpt.GetGPTBusinessOption("all", (value) => value.mj_url)).data; - let mj_api_url_index = mj_api.findIndex(item => item.value == id); - if (mj_api_url_index == -1) { - throw new Error("没有找到对应的MJ API的配置,请先检查配置") - } - return mj_api[mj_api_url_index]; - } - - /** - * 下载指定的图片地址并且分割 - * @param {*} value - */ - async DownloadImageUrlAndSplit(value) { - try { - console.log(value) - value = JSON.parse(value); - let element = value[0]; - let iamge_url = value[1]; - let image_path = ""; - if (value.length > 2) { - image_path = value[2]; - } else { - image_path = path.join(global.config.project_path, `data\\MJOriginalImage\\${element.id}.png`); - } - // 判断是不是一个链接 - const urlRegex = /^(http|https):\/\/[^ "]+$/; - if (!urlRegex.test(iamge_url)) { - throw new Error("指定的图片地址不是一个链接"); - } - - // 这边开始下载对应的图片 - await this.tools.downloadFileUrl(iamge_url, image_path); - - // 将下载的图片进行分割 - let split_res = await this.ImageSplit(JSON.stringify([image_path, element.name])); - if (split_res.code == 0) { - throw new Error(split_res.message); - } - - element.image_click = iamge_url; - element.subImagePath = split_res.data.subImagePath; - element.outImagePath = split_res.data.outImagePath; - element['image_path'] = image_path - - return { - code: 1, - data: element - } - } catch (error) { - return { - code: 0, - message: "下载指定的图片地址并且分割错误,错误信息如下:" + error.message - } - } - } - - /** - * 获取已经生图完成的数据,并获取图片 - * @param {*} value - * @returns - */ - async GetGeneratedMJImageAndSplit(value) { - try { - value = JSON.parse(value); - let mjSetting = await this.InitMjSetting(); - let request_model = mjSetting.requestModel; - let result = []; - // 浏览器生图模式 - if (request_model == "browser_mj") { - let param = []; - // 循环数据,直传需要的数据 - for (let i = 0; i < value.length; i++) { - const element = value[i]; - // 一般进度大于 50 会出现图片, - if (!element.mj_message) { - continue; - } - if (element.mj_message.progress && element.mj_message.progress == 100) { - // 判断 image_path 是不是存在。 - if (item.mj_message.image_id && !element.mj_message.image_path) { - // 通过当前的image_id获取图片 - param.push({ - id: element.id, - image_id: element.mj_message.image_id, - name: element.name, - }); - } - } - } - - // 判断窗口是不是开启 - let discordWin = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); - // 执行采集图片的脚本 - // 开始写入 - let discordSimple = new DiscordSimple(discordWin); - // 开始执行脚本 - result = await discordSimple.ExecuteScript(define.discordScript, `GetGeneratedMJImageAndSplit(${JSON.stringify(param)})`); - - } else if (request_model == "api_mj") { - let mj_api = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl); - let once_get_task = mj_api.mj_url.once_get_task; - - // 请求 - for (let i = 0; i < value.length; i++) { - const element = value[i]; - if (element.mj_message.progress == 100) { - continue - } - if (element.mj_message.progress.status == "success") { - continue - } - - let task_res = await this.discordAPI.GetMJAPITaskByID(element.mj_message.message_id, once_get_task, mjSetting.apiSetting.apiKey); - if (task_res.code == 0) { - task_res["id"] = element.id; - task_res["mj_api_url"] = mjSetting.apiSetting.mjApiUrl; - this.sendChangeMessage() - } - // 判断进度是不是百分百 - if (task_res.progress != 100) { - continue - } - - result.push({ - id: element.id, - image_id: null, - result: task_res.image_click, - name: element.name - }) - } - } - - let res = []; - // 判断返回的数据是不是一个字符串 - if (typeof result == "string") { - result = JSON.parse(result); - } - - // 将返回的数据进行分割 - for (let i = 0; i < result.length; i++) { - const element = result[i]; - let image_path = path.join(global.config.project_path, `data\\MJOriginalImage\\${uuidv4()}.png`); - let ds = await this.DownloadImageUrlAndSplit(JSON.stringify([element, element.result, image_path])); - if (ds.code == 0) { - throw new Error(ds.message); - } - // 修改数据。 - ds.data["progress"] = 100; - ds.data["status"] = "success"; - res.push(ds.data); - } - // 全部分割完毕,返回 - return successMessage(res); - } catch (error) { - return errorMessage("获取已经生图完成的数据,并获取图片错误,错误信息如下" + error.message) - } - } - - // MJ生成的图片分割 - async ImageSplit(value) { - try { - value = JSON.parse(value); - let inputPath = value[0]; - let r_name = value[1]; - let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`); - const metadata = await sharp(inputPath).metadata(); - const smallWidth = metadata.width / 2; - const smallHeight = metadata.height / 2; - let times = new Date().getTime(); - let imgs = []; - let first_p = path.join(this.global.config.project_path, `tmp\\output_crop_00001\\${r_name}`); - - for (let i = 0; i < 4; i++) { - const xOffset = i % 2 === 0 ? 0 : smallWidth; - const yOffset = Math.floor(i / 2) * smallHeight; - let out_file = path.join(outputDir, `/${r_name}_${times}_${i}.png`); - await sharp(inputPath) - .extract({ - left: xOffset, - top: yOffset, - width: smallWidth, - height: smallHeight - }) - .resize(smallWidth, smallHeight) - .toFile(out_file); - - imgs.push(out_file); - - // 将第一个图片复制一个到指定的位置 - if (i == 0) { - await this.tools.copyFileOrDirectory(out_file, first_p); - // 复制一份到input - let input_p = path.join(this.global.config.project_path, `tmp\\input_crop\\${r_name}`); - await this.tools.copyFileOrDirectory(out_file, input_p); - } - } - - return { - code: 1, - data: { - subImagePath: imgs, - outImagePath: first_p - } - } - - } catch (err) { - return { - code: 0, - message: "MJ图片切割错误,错误信息如下" + err.message - } + /** + * 通过文本自动匹配数据 + * @param {*} value + */ + async AutoMatchUser(value) { + try { + value = JSON.parse(value) + // 获取所有的角色数据,包括别名 + // 获取所有的角色数据 + let character_tags = await this.tagDefine.getTagDataByTypeAndProperty( + 'dynamic', + 'character_tags' + ) + if (character_tags.code == 0) { + return errorMessage( + '获取角色数据错误,错误信息如下:' + character_tags.message, + LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER + ) + } + character_tags = character_tags.data + if (character_tags.length == 0) { + return errorMessage('请先添加角色数据', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) + } + let character_tags_data = [] + for (let i = 0; i < character_tags.length; i++) { + let item = character_tags[i] + // 这边还要判断是不是显示(只有显示的才hi自动匹配) + if (!item.hasOwnProperty('isShow') || !item.isShow) { + continue } + let temp_name = [item.label] + // 判断当前的数是不是存在别名 + if (item.children && item.children.length > 0) { + for (let j = 0; j < item.children.length; j++) { + const element = item.children[j] + temp_name.push(element.label) + } + } + character_tags_data.push({ + key: item.key, + value: item.value, + names: temp_name + }) + } + if (character_tags_data.length == 0) { + return errorMessage( + '当前没有显示的角色数据,请先选择哪些是要显示的角色数据', + LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER + ) + } + + for (let i = 0; i < value.length; i++) { + const element = value[i] + + let res_data = { + code: 1, + id: element.id, // 当前 data 的ID + match_character: [] + } + + // 获取当前的字幕数据 + let temp_sub = [] + for (let j = 0; element.suValue && j < element.suValue.length; j++) { + const element = array[j] + temp_sub.push(element.srt_value) + } + let word = '' + if (temp_sub.length == 0) { + word = element.after_gpt + } else { + word = temp_sub.join(',') + } + + let match_keys = [] + + // 开始循环判断,只要又一个满足就跳出新婚换 + for (let j = 0; j < character_tags_data.length; j++) { + const item = character_tags_data[j] + let names = AwesomeHelp.makeSensitiveMap(item.names) + // 开始判断 + let name_res = AwesomeHelp.checkSensitiveWord(word, false, names) + if (name_res.size > 0) { + match_keys.push(item.key) + } + } + + // 判断是不是又匹配到的数据 + if (match_keys.length > 0) { + // 进行数据的处理,通过对应的key,获取对应的数据,将所有的数进行返回 + for (let i = 0; i < match_keys.length; i++) { + const item = match_keys[i] + let index = character_tags.findIndex((x) => x.key == item) + if (index == -1) { + continue + } + let temp_item_data = cloneDeep(character_tags[index]) + if (temp_item_data.children) { + delete temp_item_data.children + } + res_data.match_character.push(temp_item_data) + } + } + + // 开始往前端传递数据 + this.sendChangeMessage(res_data, DEFINE_STRING.MJ.MACTH_USER_RETURN) + } + return successMessage(null, '人物标签自动匹配完成', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) + } catch (error) { + return errorMessage( + '通过文本自动匹配数据错误,错误信息如下:' + error.message, + LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER + ) } + } - /** - * 调用API生图的方法 - * @param {*} element - * @param {*} mjSetting - */ - async MJImagineRequest(element, mjSetting, prompt, tasK_id = null, batch = null) { - try { - if (mjSetting.apiSetting == null) { - throw new Error("没有API设置,请先设置API设置"); - } - let apiUrl; - if (mjSetting.requestModel == MJImageType.API_MJ) { - // 获取当前的API url - apiUrl = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl); - } else if (mjSetting.requestModel == MJImageType.REMOTE_MJ) { - apiUrl = { - mj_url: { - imagine: define.remotemj_api + 'mj/submit/imagine', - once_get_task: define.remotemj_api + "mj/task/${id}/fetch" - } - } + /** + * 初始化MJ设置 + */ + async InitMjSetting() { + let mjSetting_res = await ImageSetting.GetDefineConfigJsonByProperty( + JSON.stringify(['img_base', 'mj_config', false, null]) + ) + if (mjSetting_res.code == 0 || !mjSetting_res.data) { + throw new Error('请先添加MJ配置') + } + let mjSetting = mjSetting_res.data + return mjSetting + } - } else { - throw new Error("未知的生图模式,请检查配置") - } - let imagine_url = apiUrl.mj_url.imagine; - let once_get_task = apiUrl.mj_url.once_get_task; + /** + * 初始化MJ API的URL + */ + async InitMJAPIUrl(id) { + let mj_api = (await this.gpt.GetGPTBusinessOption('all', (value) => value.mj_url)).data + let mj_api_url_index = mj_api.findIndex((item) => item.value == id) + if (mj_api_url_index == -1) { + throw new Error('没有找到对应的MJ API的配置,请先检查配置') + } + return mj_api[mj_api_url_index] + } - let task_count = mjSetting.taskCount ? mjSetting.taskCount : 3; - let mj_speed = mjSetting.apiSetting.mjSpeed ? mjSetting.apiSetting.mjSpeed : "relaxed"; - let res; - // 判断当前的API是哪个 - if (imagine_url.includes("mjapi.deepwl.net")) { - // DrawAPI(MJ) - let data = { - prompt: prompt, - mode: mj_speed == "fast" ? "FAST" : "RELAX", - } - let headers = { - "Authorization": mjSetting.apiSetting.apiKey - } - res = await this.discordAPI.mjApiImagine(imagine_url, data, headers); + /** + * 下载指定的图片地址并且分割 + * @param {*} value + */ + async DownloadImageUrlAndSplit(value) { + try { + console.log(value) + value = JSON.parse(value) + let element = value[0] + let iamge_url = value[1] + let image_path = '' + if (value.length > 2) { + image_path = value[2] + } else { + image_path = path.join( + global.config.project_path, + `data\\MJOriginalImage\\${element.id}.png` + ) + } + // 判断是不是一个链接 + const urlRegex = /^(http|https):\/\/[^ "]+$/ + if (!urlRegex.test(iamge_url)) { + throw new Error('指定的图片地址不是一个链接') + } - if (res.code == 24) { - throw new Error("提示词包含敏感词,请修改后重试"); - } + // 这边开始下载对应的图片 + await this.tools.downloadFileUrl(iamge_url, image_path) - } else if (imagine_url.includes("api.ephone.ai")) { - // ePhoneAPI - let headers = { - "Authorization": mjSetting.apiSetting.apiKey - } - let data = { - prompt: prompt, - botType: "MID_JOURNEY", - accountFilter: { - modes: [ - mj_speed == "fast" ? "FAST" : "RELAX" - ] - } - } - res = await this.discordAPI.mjApiImagine(imagine_url, data, headers); - } else if (imagine_url.includes(define.remotemj_api)) { - // 代理模式 - let headers = { - "mj-api-secret": define.API - } + // 将下载的图片进行分割 + let split_res = await this.ImageSplit(JSON.stringify([image_path, element.name])) + if (split_res.code == 0) { + throw new Error(split_res.message) + } - // 判断数据是不是存在 - if (!mjSetting.remoteSetting.channelId) { - throw new Error("请先设置channelId") - } - if (!mjSetting.remoteSetting.accountId) { - throw new Error("请先同步账号") - } - let data = { - prompt: prompt, - botType: "MID_JOURNEY", - accountFilter: { - channelId: mjSetting.remoteSetting.channelId, - instanceId: mjSetting.remoteSetting.accountId, - remark: this.global.machineId, - modes: [ - mj_speed == "fast" ? "FAST" : "RELAX" - ] - } - } - res = await this.discordAPI.mjApiImagine(imagine_url, data, headers); - } + element.image_click = iamge_url + element.subImagePath = split_res.data.subImagePath + element.outImagePath = split_res.data.outImagePath + element['image_path'] = image_path - this.global.mjGenerateQuene.setCurrentCreateItem(null); - // 错误检查 - if (res.code == 23) { - // 任务队列已满,及结束该任务,然后开始下一个任务,并将该任务重新排序 - this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { - return taskProgress.filter(item => item?.id != element.id) - }); - this.sendChangeMessage({ - code: 0, - status: "error", - message: "任务队列已满,任务结束会重新排序,并等待3分钟,开始后面的任务", - id: element.id - }) - await this.tools.delay(40000); - // 重新将当前任务加入队列 - this.global.mjGenerateQuene.enqueue(async () => { - this.global.mjGenerateQuene.setCurrentCreateItem(element) - await this.MJImagineRequest(element, mjSetting, prompt) - }, tasK_id, batch) + return { + code: 1, + data: element + } + } catch (error) { + return { + code: 0, + message: '下载指定的图片地址并且分割错误,错误信息如下:' + error.message + } + } + } - this.global.mjGenerateQuene.startNextTask(task_count); - return; - } - - if (res.code != 1 && res.code != 22) { - // 未知错误,将当前任务删除,开始下一个任务 - this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { - return taskProgress.filter(item => item?.id != element.id) - }); - this.global.mjGenerateQuene.startNextTask(task_count); - this.sendChangeMessage({ - code: 0, - status: "error", - message: "未知错误,可联系管理员排查," + res.description, - id: element.id - }) - return; - } - // 创建成功,开始下一个 - this.sendChangeMessage({ - code: 1, - type: "created", - category: "api_mj", - message_id: res.result, - image_click: null, - image_show: null, + /** + * 获取已经生图完成的数据,并获取图片 + * @param {*} value + * @returns + */ + async GetGeneratedMJImageAndSplit(value) { + try { + value = JSON.parse(value) + let mjSetting = await this.InitMjSetting() + let request_model = mjSetting.requestModel + let result = [] + // 浏览器生图模式 + if (request_model == 'browser_mj') { + let param = [] + // 循环数据,直传需要的数据 + for (let i = 0; i < value.length; i++) { + const element = value[i] + // 一般进度大于 50 会出现图片, + if (!element.mj_message) { + continue + } + if (element.mj_message.progress && element.mj_message.progress == 100) { + // 判断 image_path 是不是存在。 + if (item.mj_message.image_id && !element.mj_message.image_path) { + // 通过当前的image_id获取图片 + param.push({ id: element.id, - progress: 0, - mj_api_url: mjSetting.apiSetting.mjApiUrl - }); - // 开始监听当前ID是不是的生图任务完成 - // 这边设置一个循环监听,每隔一段时间去请求一次 - let timeoutId; - let startInterval = () => { - timeoutId = setTimeout(async () => { - // 执行你的操作 - let task_res = await this.discordAPI.GetMJAPITaskByID(res.result, once_get_task, mjSetting.apiSetting.apiKey) - console.log(task_res) - // 判断他的状态是不是成功 - if (task_res.code == 0) { - // 将但钱任务删除 - this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { - return taskProgress.filter(item => item?.id != element.id) - }); - // 停止当前循环 - clearTimeout(timeoutId); - } else { - if (task_res.progress == 100) { - // 将但钱任务删除 - this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { - return taskProgress.filter(item => item?.id != element.id) - }); - task_res.type = "finished"; - // 下载对应的图片 - let image_path = path.join(this.global.config.project_path, `data\\MJOriginalImage\\${task_res.message_id}.png`); - // 这边开始下载对应的图片 - await this.tools.downloadFileUrl(task_res.image_click, image_path); - task_res["image_path"] = image_path; - // 开始下一个任务 - this.global.mjGenerateQuene.startNextTask(task_count); - } else { - // 当获取的图片的进度小于100的时候,继续监听 - startInterval(); - } - } - task_res['id'] = element.id; - task_res["mj_api_url"] = mjSetting.apiSetting.mjApiUrl; - this.sendChangeMessage(task_res); - }, 5000); + image_id: element.mj_message.image_id, + name: element.name + }) } - startInterval(); - this.global.mjGenerateQuene.startNextTask(task_count); - - } catch (error) { - this.sendChangeMessage({ - code: 0, - status: "error", - message: error.message, - id: element.id - }) - throw new Error("MJ API 出图错误,错误信息如下:" + error.message) + } } + + // 判断窗口是不是开启 + let discordWin = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad() + // 执行采集图片的脚本 + // 开始写入 + let discordSimple = new DiscordSimple(discordWin) + // 开始执行脚本 + result = await discordSimple.ExecuteScript( + define.discordScript, + `GetGeneratedMJImageAndSplit(${JSON.stringify(param)})` + ) + } else if (request_model == 'api_mj') { + let mj_api = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl) + let once_get_task = mj_api.mj_url.once_get_task + + // 请求 + for (let i = 0; i < value.length; i++) { + const element = value[i] + if (element.mj_message.progress == 100) { + continue + } + if (element.mj_message.progress.status == 'success') { + continue + } + + let task_res = await this.discordAPI.GetMJAPITaskByID( + element.mj_message.message_id, + once_get_task, + mjSetting.apiSetting.apiKey + ) + if (task_res.code == 0) { + task_res['id'] = element.id + task_res['mj_api_url'] = mjSetting.apiSetting.mjApiUrl + this.sendChangeMessage() + } + // 判断进度是不是百分百 + if (task_res.progress != 100) { + continue + } + + result.push({ + id: element.id, + image_id: null, + result: task_res.image_click, + name: element.name + }) + } + } + + let res = [] + // 判断返回的数据是不是一个字符串 + if (typeof result == 'string') { + result = JSON.parse(result) + } + + // 将返回的数据进行分割 + for (let i = 0; i < result.length; i++) { + const element = result[i] + let image_path = path.join( + global.config.project_path, + `data\\MJOriginalImage\\${uuidv4()}.png` + ) + let ds = await this.DownloadImageUrlAndSplit( + JSON.stringify([element, element.result, image_path]) + ) + if (ds.code == 0) { + throw new Error(ds.message) + } + // 修改数据。 + ds.data['progress'] = 100 + ds.data['status'] = 'success' + res.push(ds.data) + } + // 全部分割完毕,返回 + return successMessage(res) + } catch (error) { + return errorMessage('获取已经生图完成的数据,并获取图片错误,错误信息如下' + error.message) } + } - /** - * MJ 原创生图 - * @param {*} value - */ - async OriginalMJImageGenerate(value) { - try { - let data = value[0]; - if (value[1]) { - data = JSON.parse(data); + // MJ生成的图片分割 + async ImageSplit(value) { + try { + value = JSON.parse(value) + let inputPath = value[0] + let r_name = value[1] + let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`) + const metadata = await sharp(inputPath).metadata() + const smallWidth = metadata.width / 2 + const smallHeight = metadata.height / 2 + let times = new Date().getTime() + let imgs = [] + let first_p = path.join(this.global.config.project_path, `tmp\\output_crop_00001\\${r_name}`) + + for (let i = 0; i < 4; i++) { + const xOffset = i % 2 === 0 ? 0 : smallWidth + const yOffset = Math.floor(i / 2) * smallHeight + let out_file = path.join(outputDir, `/${r_name}_${times}_${i}.png`) + await sharp(inputPath) + .extract({ + left: xOffset, + top: yOffset, + width: smallWidth, + height: smallHeight + }) + .resize(smallWidth, smallHeight) + .toFile(out_file) + + imgs.push(out_file) + + // 将第一个图片复制一个到指定的位置 + if (i == 0) { + await this.tools.copyFileOrDirectory(out_file, first_p) + // 复制一份到input + let input_p = path.join(this.global.config.project_path, `tmp\\input_crop\\${r_name}`) + await this.tools.copyFileOrDirectory(out_file, input_p) + } + } + + return { + code: 1, + data: { + subImagePath: imgs, + outImagePath: first_p + } + } + } catch (err) { + return { + code: 0, + message: 'MJ图片切割错误,错误信息如下' + err.message + } + } + } + + /** + * 调用API生图的方法 + * @param {*} element + * @param {*} mjSetting + */ + async MJImagineRequest(element, mjSetting, prompt, tasK_id = null, batch = null) { + try { + if (mjSetting.apiSetting == null) { + throw new Error('没有API设置,请先设置API设置') + } + let apiUrl + if (mjSetting.requestModel == MJImageType.API_MJ) { + // 获取当前的API url + apiUrl = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl) + } else if (mjSetting.requestModel == MJImageType.REMOTE_MJ) { + apiUrl = { + mj_url: { + imagine: define.remotemj_api + 'mj/submit/imagine', + once_get_task: define.remotemj_api + 'mj/task/${id}/fetch' + } + } + } else { + throw new Error('未知的生图模式,请检查配置') + } + let imagine_url = apiUrl.mj_url.imagine + let once_get_task = apiUrl.mj_url.once_get_task + + let task_count = mjSetting.taskCount ? mjSetting.taskCount : 3 + let mj_speed = mjSetting.apiSetting.mjSpeed ? mjSetting.apiSetting.mjSpeed : 'relaxed' + let res + // 判断当前的API是哪个 + if (imagine_url.includes('mjapi.deepwl.net')) { + // DrawAPI(MJ) + let data = { + prompt: prompt, + mode: mj_speed == 'fast' ? 'FAST' : 'RELAX' + } + let headers = { + Authorization: mjSetting.apiSetting.apiKey + } + res = await this.discordAPI.mjApiImagine(imagine_url, data, headers) + + if (res.code == 24) { + throw new Error('提示词包含敏感词,请修改后重试') + } + } else if (imagine_url.includes('api.ephone.ai')) { + // ePhoneAPI + let headers = { + Authorization: mjSetting.apiSetting.apiKey + } + let data = { + prompt: prompt, + botType: 'MID_JOURNEY', + accountFilter: { + modes: [mj_speed == 'fast' ? 'FAST' : 'RELAX'] + } + } + res = await this.discordAPI.mjApiImagine(imagine_url, data, headers) + } else if (imagine_url.includes(define.remotemj_api)) { + // 代理模式 + let headers = { + 'mj-api-secret': define.API + } + + // 判断数据是不是存在 + if (!mjSetting.remoteSetting.channelId) { + throw new Error('请先设置channelId') + } + if (!mjSetting.remoteSetting.accountId) { + throw new Error('请先同步账号') + } + let data = { + prompt: prompt, + botType: 'MID_JOURNEY', + accountFilter: { + remark: this.global.machineId + } + } + res = await this.discordAPI.mjApiImagine(imagine_url, data, headers) + } + + this.global.mjGenerateQuene.setCurrentCreateItem(null) + // 错误检查 + if (res.code == 23) { + // 任务队列已满,及结束该任务,然后开始下一个任务,并将该任务重新排序 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter((item) => item?.id != element.id) + }) + this.sendChangeMessage({ + code: 0, + status: 'error', + message: '任务队列已满,任务结束会重新排序,并等待3分钟,开始后面的任务', + id: element.id + }) + await this.tools.delay(40000) + // 重新将当前任务加入队列 + this.global.mjGenerateQuene.enqueue( + async () => { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + await this.MJImagineRequest(element, mjSetting, prompt) + }, + tasK_id, + batch + ) + + this.global.mjGenerateQuene.startNextTask(task_count) + return + } + + if (res.code != 1 && res.code != 22) { + // 未知错误,将当前任务删除,开始下一个任务 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter((item) => item?.id != element.id) + }) + this.global.mjGenerateQuene.startNextTask(task_count) + this.sendChangeMessage({ + code: 0, + status: 'error', + message: '未知错误,可联系管理员排查,' + res.description, + id: element.id + }) + return + } + // 创建成功,开始下一个 + this.sendChangeMessage({ + code: 1, + type: 'created', + category: 'api_mj', + message_id: res.result, + image_click: null, + image_show: null, + id: element.id, + progress: 0, + mj_api_url: mjSetting.apiSetting.mjApiUrl + }) + // 开始监听当前ID是不是的生图任务完成 + // 这边设置一个循环监听,每隔一段时间去请求一次 + let timeoutId + let startInterval = () => { + timeoutId = setTimeout(async () => { + // 执行你的操作 + let task_res = await this.discordAPI.GetMJAPITaskByID( + res.result, + once_get_task, + mjSetting.apiSetting.apiKey + ) + console.log(task_res) + // 判断他的状态是不是成功 + if (task_res.code == 0) { + // 将但钱任务删除 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter((item) => item?.id != element.id) + }) + // 停止当前循环 + clearTimeout(timeoutId) + } else { + if (task_res.progress == 100) { + // 将但钱任务删除 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter((item) => item?.id != element.id) + }) + task_res.type = 'finished' + // 下载对应的图片 + let image_path = path.join( + this.global.config.project_path, + `data\\MJOriginalImage\\${task_res.message_id}.png` + ) + // 这边开始下载对应的图片 + await this.tools.downloadFileUrl(task_res.image_click, image_path) + task_res['image_path'] = image_path + // 开始下一个任务 + this.global.mjGenerateQuene.startNextTask(task_count) + } else { + // 当获取的图片的进度小于100的时候,继续监听 + startInterval() } - let show_global_message = value[2]; - let batch = DEFINE_STRING.QUEUE_BATCH.MJ_ORIGINAL_GENERATE_IMAGE; + } + task_res['id'] = element.id + task_res['mj_api_url'] = mjSetting.apiSetting.mjApiUrl + this.sendChangeMessage(task_res) + }, 5000) + } + startInterval() + this.global.mjGenerateQuene.startNextTask(task_count) + } catch (error) { + this.sendChangeMessage({ + code: 0, + status: 'error', + message: error.message, + id: element.id + }) + throw new Error('MJ API 出图错误,错误信息如下:' + error.message) + } + } - // 判断存放的文件夹是不是存在,不存在的话创建 - let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`); - await this.tools.checkFolderExistsOrCreate(outputDir); - let fileExist = await this.tools.checkExists(outputDir); - if (!fileExist) { - await this.tools.createDirectory(outputDir); - } - // 判断该当前tmp\output_crop_00001文件夹是不是存在,不存在创建 - let output_crop_00001 = path.join(this.global.config.project_path, `tmp\\output_crop_00001`); - await this.tools.checkFolderExistsOrCreate(output_crop_00001); + /** + * MJ 原创生图 + * @param {*} value + */ + async OriginalMJImageGenerate(value) { + try { + let data = value[0] + if (value[1]) { + data = JSON.parse(data) + } + let show_global_message = value[2] + let batch = DEFINE_STRING.QUEUE_BATCH.MJ_ORIGINAL_GENERATE_IMAGE - // 获取MJ配置,从数据库中 - let _mjSettingService = await MJSettingService.getInstance() - let mjSettings = _mjSettingService.GetMJSettingTreeData(); - if (mjSettings.code == 0) { - throw new Error(mjSettings.message) - } - let mjSetting = mjSettings.data; + // 判断存放的文件夹是不是存在,不存在的话创建 + let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`) + await this.tools.checkFolderExistsOrCreate(outputDir) + let fileExist = await this.tools.checkExists(outputDir) + if (!fileExist) { + await this.tools.createDirectory(outputDir) + } + // 判断该当前tmp\output_crop_00001文件夹是不是存在,不存在创建 + let output_crop_00001 = path.join(this.global.config.project_path, `tmp\\output_crop_00001`) + await this.tools.checkFolderExistsOrCreate(output_crop_00001) - // 检查this.global中是不是又mj队列,没有的话创建一个 - if (!this.global.mjGenerateQuene) { - this.global.mjGenerateQuene = new AsyncQueue(this.global, 1, true); - } + // 获取MJ配置,从数据库中 + let _mjSettingService = await MJSettingService.getInstance() + let mjSettings = _mjSettingService.GetMJSettingTreeData() + if (mjSettings.code == 0) { + throw new Error(mjSettings.message) + } + let mjSetting = mjSettings.data - // 替换风格的逻辑 - let current_task = null; + // 检查this.global中是不是又mj队列,没有的话创建一个 + if (!this.global.mjGenerateQuene) { + this.global.mjGenerateQuene = new AsyncQueue(this.global, 1, true) + } - for (let i = 0; i < data.length; i++) { - const element = data[i]; - let tasK_id = `${batch}_${element.name}_${element.id}`; + // 替换风格的逻辑 + let current_task = null - let old_prompt = element.prompt; - // 拼接提示词 - // 图生图的链接 - // 获取风格词 + 命令后缀 - let prompt = old_prompt + (mjSetting.imageSuffix ? mjSetting.imageSuffix : ""); + for (let i = 0; i < data.length; i++) { + const element = data[i] + let tasK_id = `${batch}_${element.name}_${element.id}` - // 判断当前生图模式 - let request_model = mjSetting.requestModel - switch (request_model) { - case "api_mj": - this.global.mjGenerateQuene.enqueue(async () => { - this.global.mjGenerateQuene.setCurrentCreateItem(element) - await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch) - }, tasK_id, batch) - break; + let old_prompt = element.prompt + // 拼接提示词 + // 图生图的链接 + // 获取风格词 + 命令后缀 + let prompt = old_prompt + (mjSetting.imageSuffix ? mjSetting.imageSuffix : '') - case MJImageType.REMOTE_MJ: - this.global.mjGenerateQuene.enqueue(async () => { - this.global.mjGenerateQuene.setCurrentCreateItem(element) - await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch) - }, tasK_id, batch) - break; + // 判断当前生图模式 + let request_model = mjSetting.requestModel + switch (request_model) { + case 'api_mj': + this.global.mjGenerateQuene.enqueue( + async () => { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch) + }, + tasK_id, + batch + ) + break - case "browser_mj": - this.global.mjGenerateQuene.enqueue(async () => { - try { - this.global.mjGenerateQuene.setCurrentCreateItem(element) - // 开始进行mj生图 - current_task = element.name; - // 判断窗口是不是开启 - let discordW = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); - // 开始写入 - let discordSimple = new DiscordSimple(discordW, mjSetting); - await discordSimple.WritePromptToInput(prompt); - // 发送命令完成(删除当前正在执行。开始下一个任务) - } catch (error) { - throw error; - } - }, tasK_id, batch); - default: - break; + case MJImageType.REMOTE_MJ: + this.global.mjGenerateQuene.enqueue( + async () => { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch) + }, + tasK_id, + batch + ) + break + + case 'browser_mj': + this.global.mjGenerateQuene.enqueue( + async () => { + try { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + // 开始进行mj生图 + current_task = element.name + // 判断窗口是不是开启 + let discordW = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad() + // 开始写入 + let discordSimple = new DiscordSimple(discordW, mjSetting) + await discordSimple.WritePromptToInput(prompt) + // 发送命令完成(删除当前正在执行。开始下一个任务) + } catch (error) { + throw error } - } + }, + tasK_id, + batch + ) + default: + break + } + } - // 判断该当前正在执行的人物队列数(小于设置的数量,开始一个任务) - this.global.mjGenerateQuene.startNextTask(mjSetting.taskCount ? mjSetting.taskCount : 3); + // 判断该当前正在执行的人物队列数(小于设置的数量,开始一个任务) + this.global.mjGenerateQuene.startNextTask(mjSetting.taskCount ? mjSetting.taskCount : 3) - this.global.requestQuene.setBatchCompletionCallback(batch, (failedTasks) => { - if (failedTasks.length > 0) { - let message = ` + this.global.requestQuene.setBatchCompletionCallback(batch, (failedTasks) => { + if (failedTasks.length > 0) { + let message = ` MJ生图任务都已完成。 但是以下任务执行失败: ` - failedTasks.forEach(({ taskId, error }) => { - message += `${taskId}-, \n 错误信息: ${error}` + '\n'; - }); + failedTasks.forEach(({ taskId, error }) => { + message += `${taskId}-, \n 错误信息: ${error}` + '\n' + }) - this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, errorMessage(message)) - } else { - if (show_global_message) { - this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, successMessage(null, '所有MJ生图任务完成')) - } - } - }); - return successMessage(null) - } catch (error) { - return errorMessage("MJ生图错误,错误信息如下" + error.message) + this.global.newWindow[0].win.webContents.send( + DEFINE_STRING.SHOW_MESSAGE_DIALOG, + errorMessage(message) + ) + } else { + if (show_global_message) { + this.global.newWindow[0].win.webContents.send( + DEFINE_STRING.SHOW_MESSAGE_DIALOG, + successMessage(null, '所有MJ生图任务完成') + ) + } } + }) + return successMessage(null) + } catch (error) { + return errorMessage('MJ生图错误,错误信息如下' + error.message) } - -} \ No newline at end of file + } +} diff --git a/src/main/ReverseManage/Book/BooKBasic.js b/src/main/ReverseManage/Book/BooKBasic.js index f35bc4e..01fd020 100644 --- a/src/main/ReverseManage/Book/BooKBasic.js +++ b/src/main/ReverseManage/Book/BooKBasic.js @@ -1,63 +1,56 @@ -import { BookType } from "../../../define/enum/bookEnum"; -import { errorMessage, successMessage } from "../../generalTools"; -import BooKService from "../../../define/db/service/Book/bookService"; -import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; -const { v4: uuidv4 } = require('uuid'); +import { BookType } from '../../../define/enum/bookEnum' +import { errorMessage, successMessage } from '../../generalTools' +import { BookService } from '../../../define/db/service/Book/bookService' +import { BookTaskService } from '../../../define/db/service/Book/bookTaskService' +const { v4: uuidv4 } = require('uuid') import { define } from '../../../define/define' import path from 'path' -import { CheckFolderExistsOrCreate } from "../../../define/Tools/file"; +import { CheckFolderExistsOrCreate } from '../../../define/Tools/file' export class BookBasic { - constructor() { - } + constructor() {} /** - * 获取路径中的最后一层或两层目录 - * @param {string} path 文件或目录的完整路径 - * @param {number} level 需要获取的层级数(1表示最后一层,2表示最后两层) - * @returns {string} 最后的一层或两层目录 - */ - getLastPathLevels(path, level = 1) { - // 根据操作系统的不同,路径分隔符可能不同 - const separator = path.includes('/') ? '/' : '\\'; - const parts = path.split(separator); - // 获取最后的一层或两层目录 - const lastLevels = parts.slice(-level); - // 重新组合成路径字符串 - return lastLevels.join(separator); - } - - /** - * 新增或者是修小说数据 - * @param {*} book 小说信息 - * @returns - */ + * 新增或者是修小说数据 + * @param {*} book 小说信息 + * @returns + */ async AddOrModifyBook(book) { try { if (book == null) { - return errorMessage('小说数据为空,无法修改'); + return errorMessage('小说数据为空,无法修改') } // 处理一下数据,处理文件地址(删除前缀,转换为默认地址) // 当前的小说的名字是不是在数据库中以存在 - let _bookService = await BooKService.getInstance(); - let res = await _bookService.AddOrModifyBook(book); - return res; + let _bookService = await BookService.getInstance() + let res = await _bookService.AddOrModifyBook(book) + return res } catch (error) { - return errorMessage('修改数据错误,错误信息如下:' + error.message, 'BookBasic_AddOrModifyBook'); + return errorMessage( + '修改数据错误,错误信息如下:' + error.message, + 'BookBasic_AddOrModifyBook' + ) } } // 小说类型返回 GetBookType() { - return successMessage([{ - label: 'SD反推', - value: BookType.SD_REVERSE - }, { - label: 'MJ反推', - value: BookType.MJ_REVERSE - }, { - label: "原创", - value: BookType.ORIGINAL - }], '获取小说类型成功'); + return successMessage( + [ + { + label: 'SD反推', + value: BookType.SD_REVERSE + }, + { + label: 'MJ反推', + value: BookType.MJ_REVERSE + }, + { + label: '原创', + value: BookType.ORIGINAL + } + ], + '获取小说类型成功' + ) } -} \ No newline at end of file +} diff --git a/src/main/ReverseManage/Book/ReverseBook.js b/src/main/ReverseManage/Book/ReverseBook.js index cf0e2a0..6c278c7 100644 --- a/src/main/ReverseManage/Book/ReverseBook.js +++ b/src/main/ReverseManage/Book/ReverseBook.js @@ -1,49 +1,104 @@ -import { successMessage, errorMessage } from "../../generalTools.js"; -import { BookBasic } from "./BooKBasic.js"; -import BooKService from "../../../define/db/service/Book/bookService"; -import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; +import { successMessage, errorMessage } from '../../generalTools.js' +import { BookBasic } from './BooKBasic.js' +import { BookService } from '../../../define/db/service/Book/bookService' +import { BookTaskService } from '../../../define/db/service/Book/bookTaskService' import { define } from '../../../define/define.js' import path from 'path' +import { BasicReverse } from '../../Task/basicReverse.js' +/** + * 一键反推的相关操作 + */ export class ReverseBook extends BookBasic { constructor() { super() - + this.basicReverse = new BasicReverse() } + //#region 小说相关操作 + /** * 获取当前的小说数据 - * @param {*} bookQuery + * @param {*} bookQuery */ async GetBookData(bookQuery) { try { - let _bookService = await BooKService.getInstance(); + let _bookService = await BookService.getInstance() // 添加小说 - let res = await _bookService.GetBookData(bookQuery) + let res = _bookService.GetBookData(bookQuery) if (res.code == 0) { throw new Error(res.message) } return res } catch (error) { - return errorMessage(error.message, 'ReverseBook_GetBookData'); + return errorMessage(error.message, 'ReverseBook_GetBookData') } } + //#endregion + + //#region 小说批次任务相关操作 + /** * 获取小说的任务列表 * @param {*} bookTaskCondition 查询任务列表的条件 */ async GetBookTaskData(bookTaskCondition) { try { - let _bookTaskService = await BookTaskService.getInstance(); + let _bookTaskService = await BookTaskService.getInstance() let res = await _bookTaskService.GetBookTaskData(bookTaskCondition) if (res.code == 0) { throw new Error(res.message) } - return res; + return res } catch (error) { - return errorMessage("获取小说对应批次错误,错误信息入校:" + error.message, 'ReverseBook_GetBookTaskData'); + return errorMessage( + '获取小说对应批次错误,错误信息入校:' + error.message, + 'ReverseBook_GetBookTaskData' + ) } } -} \ No newline at end of file + //#endregion + + //#region 一键全自动 + + /** + * 全自动任务(这边是任务入口,都是在这边调用) + * @param {*} value + * @returns + */ + async AutoAction(bookId) { + try { + if (bookId == null || bookId == '') { + throw new Error('bookId不能为空') + } + // 1 分镜,开始调用 + let getFramRes = await this.basicReverse.GetFrameData(bookId) + if (getFramRes.code == 0) { + throw new Error(getFramRes.message) + } + + // 2 截取视频 + let cutVideoRes = await this.basicReverse.CutVideoData(bookId) + if (cutVideoRes.code == 0) { + throw new Error(cutVideoRes.message) + } + + // 3 分离音频 + let splitAudioRes = await this.basicReverse.SplitAudioData(bookId) + if (splitAudioRes.code == 0) { + throw new Error(splitAudioRes.message) + } + + // 4 开始提取字幕 + let extractSubtitlesRes = await this.basicReverse.ExtractSubtitlesData(bookId) + + // + } catch (error) { + return errorMessage(error.message, 'ReverseBook_AutoAction') + } + } + + //#endregion +} diff --git a/src/main/Task/basicReverse.js b/src/main/Task/basicReverse.js index b93108d..5cd0e28 100644 --- a/src/main/Task/basicReverse.js +++ b/src/main/Task/basicReverse.js @@ -1,95 +1,567 @@ -import path from 'path'; -import fs from 'fs'; -const util = require('util'); -const { exec } = require('child_process'); -const execAsync = util.promisify(exec); -import { define } from '../../define/define'; -import BooKService from '../../define/db/service/Book/bookService'; -import { TaskScheduler } from './taskScheduler'; -import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum'; -import { errorMessage } from '../generalTools'; -import { CheckFileOrDirExist } from '../../define/Tools/file'; -import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService'; +import path from 'path' +import fs from 'fs' +const util = require('util') +const { exec } = require('child_process') +const execAsync = util.promisify(exec) +import { define } from '../../define/define' +import { BookService } from '../../define/db/service/Book/bookService' +import { TaskScheduler } from './taskScheduler' +import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum' +import { errorMessage, successMessage } from '../generalTools' +import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from '../../define/Tools/file' +import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService' +import { BookTaskService } from '../../define/db/service/Book/bookTaskService' +import { isEmpty, set } from 'lodash' +import ffmpeg from 'fluent-ffmpeg' +import { SetFfmpegPath } from '../setting/ffmpegSetting' +import { TimeStringToMilliseconds, MillisecondsToTimeString } from '../../define/Tools/time' +import { BookTaskStatus } from '../../define/enum/bookEnum' +SetFfmpegPath() -const fspromises = fs.promises; +const fspromises = fs.promises -// 基础的反推(抽帧,分镜,提取字幕等) +/** + * 后台执行的任务函数,直接调用改函数即可,抽帧,分镜,提取字幕等 + */ export class BasicReverse { constructor() { this.taskScheduler = new TaskScheduler() } + //#region ffmpeg的一些操作 + + /** + * FFmpeg裁剪视频,将一个视频将裁剪指定的时间内的片段 + * @param {*} book 小说对象类 + * @param {*} bookTask 小说批次任务对象类 + * @param {*} startTime 开始时间 + * @param {*} endTime 结束时间 + * @param {*} videoPath 视频地址 + * @param {*} outVideoFile 输出地址 + * @returns + */ + async FfmpegCutVideo(book, bookTask, startTime, endTime, videoPath, outVideoFile) { + try { + // 判断视频地址是不是存在 + let videoIsExist = CheckFileOrDirExist(videoPath) + if (!videoIsExist) { + throw new Error('视频地址对应的文件不存在') + } + + // 判断开始时间和结束时间是不是合法 + if (isEmpty(startTime) || isEmpty(endTime)) { + throw new Error('开始时间和结束时间不能为空') + } + // 判断输出文件夹是不是存在 + let outputFolder = path.dirname(outVideoFile) + await CheckFolderExistsOrCreate(outputFolder) + + // 将时间转换为字符串 + startTimeString = MillisecondsToTimeString(startTime) + endTimeString = MillisecondsToTimeString(endTime) + + // 设置视频编码器 + let videoCodec = 'libx264' // 默认编码器 + if (global.gpu.type === 'NVIDIA') { + videoCodec = 'h264_nvenc' + } else if (global.gpu.type === 'AMD') { + videoCodec = 'h264_amf' + } + + // 判断分镜是不是和数据库中的数据匹配的上 + return new Promise((resolve, reject) => { + ffmpeg(videoPath) + .setStartTime(startTimeString) + .setEndTime(endTimeString) + .videoCodec(videoCodec) + .addOption('-preset', 'fast') + .audioCodec('copy') + .output(outVideoFile) + .on('end', async function () { + let res_msg = `视频裁剪完成,输出地址:${outVideoFile}` + // 修改数据库中的输出地址 + await this.taskScheduler.AddLogToDB( + book.id, + book.type, + res_msg, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) + return successMessage(null, res_msg, 'BasicReverse_FfmpegCutVideo') + }) + .on('error', async function (err) { + let res_msg = `视频裁剪失败,错误信息如下:${err.toString()}` + await this.taskScheduler.AddLogToDB( + book.id, + book.type, + res_msg, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + return errorMessage(res_msg, 'BasicReverse_FfmpegCutVideo') + }) + .run() + }) + + // 开始裁剪视频 + } catch (error) { + return errorMessage( + '裁剪视频失败,错误信息如下: ' + error.message, + 'BasicReverse_FfmpegCutVideo' + ) + } + } + + /** + * + * @param {*} videoPath + * @param {*} audioPath + */ + async FfmpegExtractAudio(videoPath, outAudioPath) { + try { + // 判断视频地址是不是存在 + let videoIsExist = CheckFileOrDirExist(videoPath) + if (!videoIsExist) { + throw new Error('视频地址对应的文件不存在') + } + // 开始提取音频 + return new Promise((resolve, reject) => { + ffmpeg(videoPath) + .output(outAudioPath) + .audioCodec('libmp3lame') + .audioBitrate('128k') + .on('end', async function () { + let res_msg = `音频提取完成,输出地址:${outAudioPath}` + return successMessage(outAudioPath, res_msg, 'BasicReverse_FfmpegExtractAudio') + }) + .on('error', async function (err) { + let res_msg = `音频提取失败,错误信息如下:${err.toString()}` + return errorMessage(res_msg, 'BasicReverse_FfmpegExtractAudio') + }) + }) + } catch (error) { + return errorMessage( + '提取音频失败,错误信息如下: ' + error.message, + 'BasicReverse_FfmpegExtractAudio' + ) + } + } + + //#endregion + /** * 分镜(通过传入的bookId) * @param {*} bookId 传入的bookId - * @returns + * @returns */ async GetFrameData(bookId) { try { - let _bookService = await BooKService.getInstance(); - let _bookTaskDetailService = await BookTaskDetailService.getInstance(); + let _bookService = await BookService.getInstance() + let _bookTaskDetailService = await BookTaskDetailService.getInstance() + let _bookTaskService = await BookTaskService.getInstance() + // 获取对应的小说小说数据,找到对应的小说视频地址 let bookQuery = { bookId: bookId } - let bookData = await _bookService.GetBookData(bookQuery) + let bookData = _bookService.GetBookData(bookQuery) if (bookData.code == 0) { return bookData } if (bookData.data.book_length <= 0 || bookData.data.res_book.length <= 0) { - throw new Error("没有找到对应的小说数据,请检查bookId是否正确") + throw new Error('没有找到对应的小说数据,请检查bookId是否正确') + } + + // 获取小说对应的批次任务数据,默认初始化为第一个 + let bookTaskRes = await _bookTaskService.GetBookTaskData({ + bookId: bookId, + name: 'output_00001' + }) + if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { + throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } // 获取小说的视频地址 let book = bookData.data.res_book[0] + let bookTask = bookTaskRes.data.bookTasks[0] + + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.STORYBOARD) + + // 分镜之前,删除之前的老数据 + let deleteBookTaskRes = _bookTaskDetailService.DeleteBookTaskDetail({ + bookId: bookId, + bookTaskId: bookTask.id + }) + let oldVideoPath = book.oldVideoPath let frameJson = oldVideoPath + '.json' let sensitivity = 30 // 开始之前,推送日志 let log_content = `开始进行分镜操作,视频地址:${oldVideoPath},敏感度:${sensitivity},正在调用程序进行处理` - await this.taskScheduler.AddLogToDB(bookId, book.type, log_content, OtherData.DEFAULT, LoggerStatus.DOING) + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + log_content, + OtherData.DEFAULT, + LoggerStatus.DOING + ) // 小说进行分镜(python进行,将结果写道一个json里面) // 使用异步的方法调用一个python程序,然后写入到指定的json文件中k - let command = `"${path.join(define.scripts_path, "Lai.exe")}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"` - const output = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }); + let command = `"${path.join( + define.scripts_path, + 'Lai.exe' + )}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"` + const output = await execAsync(command, { + maxBuffer: 1024 * 1024 * 10, + encoding: 'utf-8' + }) // 有错误输出 if (output.stderr != '') { - await this.taskScheduler.AddLogToDB(bookId, book.type, `分镜失败,错误信息如下:${output.stderr}`, OtherData.DEFAULT, LoggerStatus.FAIL) - throw new Error(output.stderr); + let error_msg = `分镜失败,错误信息如下:${output.stderr}` + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.STORYBOARD_FAIL, + error_msg + ) + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + error_msg, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + throw new Error(output.stderr) } // 分镜成功,处理输出 let josnIsExist = CheckFileOrDirExist(frameJson) if (!josnIsExist) { let error_message = `分镜失败,没有找到对应的分镜输出文件:${frameJson}` - await this.taskScheduler.AddLogToDB(bookId, book.type, error_message, OtherData.DEFAULT, LoggerStatus.FAIL) + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.STORYBOARD_FAIL, + error_message + ) + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + error_message, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) throw new Error(error_message) } let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8')) if (frameJsonData.length <= 0) { - await this.taskScheduler.AddLogToDB(bookId, book.type, `分镜失败,没有找到对应的分镜数据`, OtherData.DEFAULT, LoggerStatus.FAIL) - throw new Error("分镜失败,没有找到对应的分镜数据") + let error_msg = `分镜失败,没有找到对应的分镜数据` + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.STORYBOARD_FAIL, + error_msg + ) + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + error_msg, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + throw new Error(error_msg) } // 循环写入小说人物详细数据 for (let i = 0; i < frameJsonData.length; i++) { - let frameData = frameJsonData[i] + let dataArray = frameJsonData[i] let bookTaskDetail = { bookId: bookId, + bookTaskId: bookTask.id + } + + // 将字符串转换为number + bookTaskDetail.startTime = TimeStringToMilliseconds(dataArray[0]) + bookTaskDetail.endTime = TimeStringToMilliseconds(dataArray[1]) + + let res = _bookTaskDetailService.AddBookTaskDetail(bookTaskDetail) + if (res.code == 0) { + throw new Error(res.message) } - await _bookTaskDetailService.AddBookTaskDetail(frameDataQuery) } + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.STORYBOARD_DONE) + // 分镜成功,推送日志 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `分镜成功,分镜数据如下:${frameJsonData}`, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) - console.log() - - console.log(output.stdout) - - + return successMessage(null, `分镜成功,分镜信息在 ${frameJson}`, 'BasicReverse_GetFrameData') } catch (error) { - return errorMessage(error.message, 'BasicReverse_GetFrameData'); + return errorMessage(error.message, 'BasicReverse_GetFrameData') } } -} \ No newline at end of file + + /** + * 裁剪视频 + * @param {*} bookId 小说ID + * @param {*} frameJson 存放分镜数据的json文件地址 + */ + async CutVideoData(bookId) { + try { + if (isEmpty(bookId)) { + throw new Error('bookId不能为空') + } + + // 判断小说是不是存在 + let _bookService = await BookService.getInstance() + let _bookTaskService = await BookTaskService.getInstance() + let _bookTaskDetailService = await BookTaskDetailService.getInstance() + let book = _bookService.GetBookDataById(bookId) + + if (book == null) { + throw new Error('没有找到对应的小说数据') + } + + // 找到对应的小说ID和对应的小说批次任务ID,判断是不是有分镜数据 + let bookTaskRes = await _bookTaskService.GetBookTaskData({ + bookId: bookId, + name: 'output_00001' + }) + if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { + throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') + } + + let bookTask = bookTaskRes.data.bookTasks[0] + + let bookTaskDetail = _bookTaskDetailService.GetBookTaskData({ + bookId: bookId, + bookTaskId: bookTask.id + }) + + if (bookTaskDetail.data.length <= 0) { + // 传入的分镜数据为空,需要重新获取 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `没有传入分镜数据,开始调用分镜方法`, + OtherData.DEFAULT, + LoggerStatus.DOING + ) + let frameRes = this.GetFrameData(bookId) + if (frameRes.code == 0) { + throw new Error((await frameRes).message) + } + } + + bookTaskDetail = _bookTaskDetailService.GetBookTaskData({ + bookId: bookId, + bookTaskId: bookTask.id + }) + + if (bookTaskDetail.data.length <= 0) { + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.SPLIT_FAIL, + '重新调用分镜方法还是没有分镜数据,请检查' + ) + throw new Error('重新调用分镜方法还是没有分镜数据,请检查') + } + + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT) + // 有分镜数据,开始处理 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `成功获取分镜数据,开始裁剪视频`, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) + for (let i = 0; i < bookTaskDetail.length; i++) { + const element = bookTaskDetail[i] + let startTime = element.startTime + let endTime = element.endTime + if (startTime == null || endTime == null) { + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.SPLIT_FAIL, + '开始时间和结束时间不能为空' + ) + throw new Error('开始时间和结束时间不能为空') + } + let outVideoFile = path.join(book.bookFolderPath, `data/frame/${element.name}.mp4`) + + let res = await this.FfmpegCutVideo( + book, + startTime, + endTime, + book.oldVideoPath, + outVideoFile + ) + if (res.code == 0) { + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT_FAIL, res.message) + throw new Error(res.message) + } + + // 视频裁剪完成,要将裁剪后的视频地址写入到数据库中 + _bookTaskDetailService.UpdateBookTaskDetail(element.id, { + videoPath: path.relative(define.project_path, outVideoFile) + }) + } + + // 小改小说批次的状态 + + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT_DONE) + + // 结束,分镜完毕,推送日志,返回成功 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `全部视频裁剪完成`, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) + return successMessage(null, '全部视频裁剪完成', 'BasicReverse_CutVideoData') + } catch (error) { + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + error.message, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + return errorMessage( + '裁剪视频失败,错误信息如下: ' + error.message, + 'BasicReverse_CutVideoData' + ) + } + } + + /** + * 分离视频片段的音频, + * 当没有传入bookTaskId,分离默认的第一个, + * 有传入的时候,分离对应的bookTaskId的数据 + * @param {*} bookId + * @param {*} bookTaskId + */ + async SplitAudioData(bookId, bookTaskId = null) { + try { + let _bookService = await BookService.getInstance() + let _bookTaskService = await BookTaskService.getInstance() + let _bookTaskDetailService = await BookTaskDetailService.getInstance() + let book = _bookService.GetBookDataById(bookId) + if (book == null) { + throw new Error('没有找到对应的小说数据') + } + let bookTask + if (bookTaskId != null) { + bookTaskId = _bookTaskService.GetBookTaskData({ id: bookTaskId }) + } else { + bookTask = _bookTaskService.GetBookTaskData({ + bookId: bookId, + name: 'output_00001' + }) + } + if (bookTask.data.bookTasks.length <= 0 || bookTask.data.total <= 0) { + throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') + } + bookTask = bookTask.data.bookTasks[0] + + // 获取对应小说批次任务的分镜信息 + let bookTaskDetails = _bookTaskDetailService.GetBookTaskData({ + bookId: bookId, + bookTaskId: bookTask.id + }) + if (bookTaskDetails.data.length <= 0) { + throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行') + } + + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `开始分离音频`, + OtherData.DEFAULT, + LoggerStatus.DOING + ) + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.AUDIO) + + for (let i = 0; i < bookTaskDetails.length; i++) { + const element = bookTaskDetails[i] + let videoPath = element.videoPath + let audioPath = path.join(book.bookFolderPath, `data/audio/${element.name}.mp3`) + await CheckFolderExistsOrCreate(path.dirname(audioPath)) + + // 开始分离音频 + let audioRes = await this.FfmpegExtractAudio(videoPath, audioPath) + if (audioRes.code == 0) { + let errorMessage = `分离音频失败,错误信息如下:${audioRes.message}` + _bookTaskService.UpdateBookTaskStatus( + bookTask.id, + BookTaskStatus.AUDIO_FAIL, + errorMessage + ) + throw new Error(audioRes.message) + } + + _bookTaskDetailService.UpdateBookTaskDetail(element.id, { + audioPath: path.relative(define.project_path, audioPath) + }) + + // 推送成功消息 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `${element.name}分离音频成功,输出地址:${audioPath}`, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) + } + // 修改状态为分离音频成功 + _bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.AUDIO_DONE) + // 所有音频分离成功,推送日志 + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + `${element.name}分离音频成功,输出地址:${audioPath}`, + OtherData.DEFAULT, + LoggerStatus.SUCCESS + ) + return successMessage(null, '所有音频分离成功', 'BasicReverse_SplitAudioData') + } catch (error) { + let errorMessage = `分离音频失败,错误信息如下:${error.message}` + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + errorMessage, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + return errorMessage(errorMessage, 'BasicReverse_SplitAudioData') + } + } + + /** + * 提取字幕 + * @param {*} bookId + * @param {*} bookTaskId + * @returns + */ + async ExtractSubtitlesData(bookId, bookTaskId = null) { + try { + } catch (error) { + let errorMessage = `提取字幕失败,错误信息如下:${error.message}` + await this.taskScheduler.AddLogToDB( + bookId, + book.type, + errorMessage, + OtherData.DEFAULT, + LoggerStatus.FAIL + ) + + return errorMessage(errorMessage, 'BasicReverse_ExtractSubtitlesData') + } + } +} diff --git a/src/main/Task/taskManage.js b/src/main/Task/taskManage.js new file mode 100644 index 0000000..c7c8c98 --- /dev/null +++ b/src/main/Task/taskManage.js @@ -0,0 +1,214 @@ +import { BookBackTaskListService } from '../../define/db/service/Book/bookBackTaskListService' +import { BookService } from '../../define/db/service/Book/bookService' +import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService' +import { BookTaskService } from '../../define/db/service/Book/bookTaskService' +import { OtherData } from '../../define/enum/softwareEnum' +import { BookBackTaskStatus } from '../../define/enum/bookEnum' + +class TaskManager { + constructor() {} + + /** + * 创建新任务到数据库 + * 需要传递 小说ID,小说任务ID,小说任务分镜ID + * 判断是不是有相同的任务在执行,如果有则不创建新任务 + * 小说任务ID为null,所有相关的数据就是default + * 小说任务分镜ID为null,所有相关的数据就是default + * @param {*} bookId 小说ID 必传 + * @param {*} taskType 任务类型 必传 + * @param {*} bookTaskId 小说任务ID 可为null + * @param {*} bookTaskDetailId 小说任务分镜ID 可为null + * @returns + */ + async AddTask(bookId, taskType, bookTaskId = null, bookTaskDetailId = null) { + try { + // 开始创建任务 + let _bookBackTaskListService = await BookBackTaskListService.getInstance() + let _bookService = await BookService.getInstance() + let _bookTaskService = await BookTaskService.getInstance() + let _bookTaskDetailService = await BookTaskDetailService.getInstance() + + // 获取小说信息 + let book = _bookService.GetBookDataById(bookId) + if (book == null) { + throw new Error('小说信息不存在,添加任务失败') + } + + // 有传入小说批次任务ID,要检查数据是不是存在 + let bookTask = null + if (bookTaskId != null) { + let bookTaskRes = _bookTaskService.GetBookTaskDataById(bookTaskId) + if (bookTaskRes.data == null) { + throw new Error('小说批次任务信息不存在,添加任务失败') + } + bookTask = bookTaskRes.data + } + + let bookTaskDetail = null + if (bookTaskDetailId != null) { + let bookTaskDetailRes = _bookTaskDetailService.GetBookTaskDetailDataById(bookTaskDetailId) + if (bookTaskDetailRes.data == null) { + throw new Error('小说任务分镜信息不存在,添加任务失败') + } + bookTaskDetail = bookTaskDetailRes.data + } + + // 开始往数据库中添加任务 + let name = `${book.name}-${bookTask ? bookTask.name : 'default'}-${ + bookTaskDetail ? bookTaskDetail.name : 'default' + }-${taskType}` + let addBookBackTaskListRes = _bookBackTaskListService.AddBookBackTaskList({ + bookId: bookId, + bookTaskId: bookTaskId ? bookTaskId : OtherData.DEFAULT, + name: name, + type: taskType, + status: BookBackTaskStatus.WAIT + }) + + if (addBookBackTaskListRes.code == 1) { + return addBookBackTaskListRes + } else { + throw new Error('添加任务失败') + } + } catch (error) { + throw error + } + } + + /** + * 获取指定小说和小说批次任务中等待中的任务 + * @param {*} bookId + * @param {*} bookTaskId + */ + async GetWaitTask(bookId, bookTaskId = null) { + try { + if (bookId == null) { + throw new Error('bookId不能为空') + } + let query = { + bookId: bookId, + status: BookBackTaskStatus.WAIT + } + + if (bookTaskId != null) { + query.bookTaskId = bookTaskId + } + + let _bookBackTaskListService = await BookBackTaskListService.getInstance() + + } catch (error) { + throw error + } + } + + updateTaskStatus(taskId, batchId, subBatchId, status) { + return new Promise((resolve, reject) => { + this.db.run( + `UPDATE tasks SET status = ?, updatedAt = datetime('now') + WHERE taskId = ? AND batchId = ? AND subBatchId = ?`, + [status, taskId, batchId, subBatchId], + function (err) { + if (err) { + reject(err) + } else { + resolve() + } + } + ) + }) + } + + deleteTask(taskId, batchId, subBatchId) { + return new Promise((resolve, reject) => { + this.db.run( + `DELETE FROM tasks WHERE taskId = ? AND batchId = ? AND subBatchId = ?`, + [taskId, batchId, subBatchId], + function (err) { + if (err) { + reject(err) + } else { + resolve() + } + } + ) + }) + } + + getAllTasks() { + return new Promise((resolve, reject) => { + this.db.all(`SELECT * FROM tasks`, [], (err, rows) => { + if (err) { + reject(err) + } else { + resolve(rows) + } + }) + }) + } +} + +class TaskExecutor { + constructor(taskManager) { + this.taskManager = taskManager + this.isExecuting = false + } + + async executePendingTasks() { + if (this.isExecuting) { + console.log('任务正在执行,跳过此次执行') + return + } + + this.isExecuting = true + + try { + const tasks = await this.taskManager.getAllTasks() + for (const task of tasks) { + if (task.status === 'pending') { + console.log(`Executing task: ${task.taskId}`) + await this.handleTask(task) + await this.taskManager.updateTaskStatus( + task.taskId, + task.batchId, + task.subBatchId, + 'completed' + ) + } + } + } catch (err) { + console.error('Error executing tasks:', err) + } finally { + this.isExecuting = false + } + } + + async handleTask(task) { + if (task.taskId === 'specificTask') { + console.log(`Handling specific task: ${task.taskId}`) + // 执行任务的具体逻辑 + } else { + console.log(`Handling general task: ${task.taskId}`) + // 执行任务的具体逻辑 + } + } +} + +const taskManager = new TaskManager() +const taskExecutor = new TaskExecutor(taskManager) + +// 每分钟检查并执行一次任务 +setInterval(() => { + taskExecutor.executePendingTasks().catch(console.error) +}, 60 * 1000) + +// 示例:创建任务并触发执行 +taskManager + .createTask('task1', 'batch1', 'subBatch1') + .then((taskId) => { + if (taskId) { + console.log('Task created with ID:', taskId) + } else { + console.log('没有创建新任务') + } + }) + .catch((err) => console.error(err)) diff --git a/src/main/setting/ffmpegSetting.js b/src/main/setting/ffmpegSetting.js new file mode 100644 index 0000000..4d36777 --- /dev/null +++ b/src/main/setting/ffmpegSetting.js @@ -0,0 +1,21 @@ +import path from 'path' +import os from 'os' +import ffmpeg from 'fluent-ffmpeg' +import { define } from '../../define/define' + +export function SetFfmpegPath() { + let ffmpegPath + let ffprobePath + + switch (os.platform()) { + case 'win32': + // Windows + ffmpegPath = path.join(define.package_path, 'ffmpeg/win/ffmpeg.exe') + ffprobePath = path.join(define.package_path, 'ffmpeg/win/ffprobe.exe') + break + default: + throw new Error('Unsupported platform: ' + os.platform()) + } + ffmpeg.setFfmpegPath(ffmpegPath) + ffmpeg.setFfprobePath(ffprobePath) +} diff --git a/src/main/setting/mjSetting.js b/src/main/setting/mjSetting.js index 16126aa..13670f3 100644 --- a/src/main/setting/mjSetting.js +++ b/src/main/setting/mjSetting.js @@ -1,11 +1,12 @@ -import axios from 'axios'; +import axios from 'axios' import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService' -import { define } from '../../define/define'; -import { errorMessage, successMessage } from '../generalTools'; +import { define } from '../../define/define' +import { errorMessage, successMessage } from '../generalTools' +import { isEmpty } from 'lodash' +const { v4: uuidv4 } = require('uuid') export class MJSetting { - constructor() { - } + constructor() {} /** * 获取MJ的基础设置数据 @@ -13,143 +14,276 @@ export class MJSetting { async GetMJSetting(mjSettingQuery) { try { let _mjSetting = await MJSettingService.getInstance() - let res = _mjSetting.GetMjSetting(mjSettingQuery); + let res = _mjSetting.GetMjSetting(mjSettingQuery) return res } catch (error) { - return errorMessage("获取MJ的基础配置错误,错误信息如下:" + error.toString(), "MJSetting_GetMJSetting"); + return errorMessage( + '获取MJ的基础配置错误,错误信息如下:' + error.toString(), + 'MJSetting_GetMJSetting' + ) } } /** * 保存MJ的基础设置 - * @param {*} mjSetting 保存的数据 + * @param {*} mjSetting 保存的数据 */ async UpdateMJSetting(mjSetting) { try { let _mjSetting = await MJSettingService.getInstance() - let res = _mjSetting.UpdateMJSetting(mjSetting); + let res = _mjSetting.UpdateMJSetting(mjSetting) return res - } catch (error) { - return errorMessage("保存MJ的基础配置错误,错误信息如下:" + error.toString(), "MJSetting_UpdateMJSetting"); + return errorMessage( + '保存MJ的基础配置错误,错误信息如下:' + error.toString(), + 'MJSetting_UpdateMJSetting' + ) } } /** - * 获取MJ配置的所有数据 - */ + * 获取MJ配置的所有数据 + */ async GetMJSettingTreeData() { try { let _mjSetting = await MJSettingService.getInstance() - let res = _mjSetting.GetMJSettingTreeData(); + let res = _mjSetting.GetMJSettingTreeData() return res } catch (error) { - return errorMessage("获取MJ配置错误,详细错误信息如下:" + error.toString(), 'MJSetting_GetMJSettingTreeData'); + return errorMessage( + '获取MJ配置错误,详细错误信息如下:' + error.toString(), + 'MJSetting_GetMJSettingTreeData' + ) } } /** * 保存MJ设置的所有数据 - * @param {*} mjSetting + * @param {*} mjSetting */ async SaveMJSettingTreeData(mjSetting) { try { let _mjSetting = await MJSettingService.getInstance() - let res = _mjSetting.SaveMJSettingTreeData(mjSetting); + let res = _mjSetting.SaveMJSettingTreeData(mjSetting) return res } catch (error) { - return errorMessage("保存MJ配置错误,详细错误信息如下:" + error.toString(), 'MJSetting_SaveMJSettingTreeData'); + return errorMessage( + '保存MJ配置错误,详细错误信息如下:' + error.toString(), + 'MJSetting_SaveMJSettingTreeData' + ) } } + /** - * 同步MJ代理模式账号信息 - * @param {*} value - * @returns + * 获取所有的MJ代理模式账号信息 */ - async MjRemoteAccountSync() { + async GetRemoteMJSettings() { try { - // 获取账号数据 - let _mjSettingService = await MJSettingService.getInstance() - let remoteMjSettings = _mjSettingService.GetRemoteMJSettings(null); - if (remoteMjSettings.data.length <= 0) { - throw new Error("没有找到保存的数据,请先保存") - } - - let remoteMjSetting = remoteMjSettings.data[0] - // 判断是不是同步过,就是有没有accountId - // 判断有没有accountId - if (remoteMjSetting.accountId) { - // 查找是不是有 - let accountRes = await axios.get(define.remotemj_api + `mj/account/${remoteMjSetting.accountId}/fetch`, { - headers: { - "mj-api-secret": define.API - } - }); - console.log(accountRes) - // 没有找到账号信息,重新添加 - if (accountRes.status == 200 && accountRes.data == "") { - // 添加账号 - // 找不到的话,直接添加账号 - let accountRes = await axios.post(define.remotemj_api + `mj/account/create`, remoteMjSetting, { - headers: { - "mj-api-secret": define.API - } - }); - console.log(accountRes); - - if (accountRes.data.code != 1) { - throw new Error(accountRes.data.description); - } - - // 添加成功,修改数据,将数据返回 - let accountId = accountRes.data.result; - remoteMjSetting.accountId = accountId; - let save_res = _mjSettingService.UpdateRemoteMjSetting(remoteMjSetting); - if (save_res.code != 1) { - throw new Error(save_res.message) - } - return successMessage(remoteMjSetting, "MJ新增账号同步成功", "MJSetting_MjRemoteAccountSync") - } else { - // 能找到的话,要更新一下账号信息,并重连 - remoteMjSetting["weight"] = 1 - let accountRes = await axios.put(define.remotemj_api + `mj/account/${remoteMjSetting.accountId}/update-reconnect`, remoteMjSetting, { - headers: { - "mj-api-secret": define.API - } - }); - console.log(accountRes) - if (accountRes.data.code == 0) { - throw new Error(accountRes.description) - } - return successMessage(remoteMjSetting, "MJ账号同步成功", "MJSetting_MjRemoteAccountSync") - } - } else { - // 没有accountId,直接添加 - // 添加账号 - let accountRes = await axios.post(define.remotemj_api + `mj/account/create`, remoteMjSetting, { - headers: { - "mj-api-secret": define.API - } - }); - console.log(accountRes); - - if (accountRes.data.code != 1) { - throw new Error(accountRes.data.description); - } - - // 添加成功,修改数据,将数据返回 - let accountId = accountRes.data.result; - remoteMjSetting.accountId = accountId; - let save_res = _mjSettingService.UpdateRemoteMjSetting(remoteMjSetting); - if (save_res.code != 1) { - throw new Error(save_res.message) - } - return successMessage(remoteMjSetting, "MJ账号同步成功", "MJSetting_MjRemoteAccountSync") - } - - + let _mjSetting = await MJSettingService.getInstance() + let res = _mjSetting.GetRemoteMJSettings(null) + return res } catch (error) { - return errorMessage("MJ代理模式账号同步错误,详细错误信息如下:" + error.toString(), 'MJSetting_MjRemoteAccountSync'); + return errorMessage( + '获取MJ代理模式账号信息错误,详细错误信息如下:' + error.toString(), + 'MJSetting_GetRemoteMJSettings' + ) } } -} \ No newline at end of file + + /** + * 创建新的代理MJ信息 + * @param {*} value + */ + async AddRemoteMJSetting(value) { + try { + // 先检查必填字段 + console.log(value) + if (isEmpty(value.channelId) || isEmpty(value.guildId) || isEmpty(value.userToken)) { + throw new Error('必填字段服务器ID,频道ID,用户token不能为空') + } + + if (value.coreSize == null || value.queueSize == null || value.timeoutMinutes == null) { + throw new Error('必填字段核心线程数,队列大小,超时时间不能为空') + } + if (!value.userAgent) { + value.userAgent = + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' + } + + // 开始调用创建任务 + let createUrl = define.remotemj_api + 'mj/account/create' + // 上面是必传的 + let remoteData = { + channelId: value.channelId, + guildId: value.guildId, + userToken: value.userToken, + coreSize: value.coreSize, + queueSize: value.queueSize, + timeoutMinutes: value.timeoutMinutes, + userAgent: value.userAgent + ? value.userAgent + : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + remark: global.machineId, + remixAutoSubmit: false + } + + // 额外添加 + if (value.mjBotChannelId) { + remoteData.mjBotChannelId = value.mjBotChannelId + } + 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) + } + + // 添加成功,修改数据,将数据返回 (服务器添加成功,开始在本地数据库添加)s + let accountId = accountRes.data.result + remoteData.accountId = accountId + remoteData.remixAutoSubmit = false + + let _mjSettingService = await MJSettingService.getInstance() + + let save_res = _mjSettingService.AddRemoteMjSetting(remoteData) + if (save_res.code != 1) { + throw new Error(save_res.message) + } + return successMessage(remoteData, 'MJ账号同步成功', 'MJSetting_AddRemoteMJSetting') + } catch (error) { + return errorMessage( + '创建新的代理MJ信息错误,详细错误信息如下:' + error.toString(), + 'MJSetting_AddRemoteMJSetting' + ) + } + } + + /** + * 修改MJ的账号信息,并重连 + * @param {*} value + */ + async UpdateRemoteMJSetting(value) { + try { + // 先检查必填字段 + console.log(value) + + if (isEmpty(value.accountId)) { + throw new Error('修改不能没有账号实例ID') + } + + if (isEmpty(value.channelId) || isEmpty(value.guildId) || isEmpty(value.userToken)) { + throw new Error('必填字段服务器ID,频道ID,用户token不能为空') + } + + if (value.coreSize == null || value.queueSize == null || value.timeoutMinutes == null) { + throw new Error('必填字段核心线程数,队列大小,超时时间不能为空') + } + if (!value.userAgent) { + value.userAgent = + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' + } + + // 开始调用更新重连任务 + let updateUrl = define.remotemj_api + `mj/account/${value.accountId}/update-reconnect` + + // 开始修改 + let remoteData = { + channelId: value.channelId, + coreSize: value.coreSize, + enable: value.enable, + guildId: value.guildId, + id: value.accountId, + mjBotChannelId: value.mjBotChannelId ? value.mjBotChannelId : '', + nijiBotChannelId: value.nijiBotChannelId ? value.nijiBotChannelId : '', + queueSize: value.queueSize, + remark: global.machineId, + remixAutoSubmit: false, + timeoutMinutes: value.timeoutMinutes ? value.timeoutMinutes : 10, + userAgent: value.userAgent, + userToken: value.userToken, + weight: 1 + } + + let accountRes = await axios.put(updateUrl, remoteData, { + headers: { + 'mj-api-secret': define.API + } + }) + + if (accountRes.data.code != 1) { + throw new Error(accountRes.description) + } + + // 更新成功,修改数据 + remoteData.accountId = value.accountId + remoteData.id = value.id + + // 同步成功,修改数据 + let _mjSettingService = await MJSettingService.getInstance() + let save_res = _mjSettingService.UpdateRemoteMjSetting(remoteData) + + if (save_res.code == 0) { + throw new Error(save_res.message) + } + + return successMessage(remoteData, 'MJ账号修改并同步成功', 'MJSetting_UpdateRemoteMJSetting') + } catch (error) { + return errorMessage( + '修改MJ的账号信息错误,详细错误信息如下:' + error.toString(), + 'MJSetting_UpdateRemoteMJSetting' + ) + } + } + + /** + * 删除指定的MJ账号 + * @param {*} id 数据库中存放的ID + */ + async DeleteRemoteMJSetting(id) { + try { + // 先检查必填字段 + if (isEmpty(id)) { + throw new Error('无法删除没有ID的数据') + } + // 先获取数据 + let _mjSetting = await MJSettingService.getInstance() + let deleteConfig = _mjSetting.GetRemoteMJSettings({ id: id }) + if (deleteConfig.data.length <= 0) { + 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 (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') + } catch (error) { + return errorMessage( + '删除指定的MJ账号错误,详细错误信息如下:' + error.toString(), + 'MJSetting_DeleteRemoteMJSetting' + ) + } + } +} diff --git a/src/preload/book.js b/src/preload/book.js index 6055ea0..1421d77 100644 --- a/src/preload/book.js +++ b/src/preload/book.js @@ -20,6 +20,9 @@ const book = { // 获取小说的分镜 GetFrameData: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_FRAME_DATA, bookId), + // 一键全自动执行 + AutoAction: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.AUTO_ACTION, bookId), + //#endregion } diff --git a/src/preload/setting.js b/src/preload/setting.js index 7045fab..65eff7f 100644 --- a/src/preload/setting.js +++ b/src/preload/setting.js @@ -1,45 +1,66 @@ -import { ipcRenderer } from "electron" -import { DEFINE_STRING } from "../define/define_string" - +import { ipcRenderer } from 'electron' +import { DEFINE_STRING } from '../define/define_string' const setting = { - // 获取动态配置的的指定主分类,指定的属性的数据(只是获取动态的,type定死了dynamic) - GetDataByTypeAndProperty: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_DATA_BY_TYPE_AND_PROPERTY, value)), + // 获取动态配置的的指定主分类,指定的属性的数据(只是获取动态的,type定死了dynamic) + GetDataByTypeAndProperty: async (value, callback) => + callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_DATA_BY_TYPE_AND_PROPERTY, value)), - // 保存动态配置的的指定主分类,指定的属性的数据 - SaveDataByTypeAndProperty: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_DATA_BY_TYPE_AND_PROPERTY, value)), + // 保存动态配置的的指定主分类,指定的属性的数据 + SaveDataByTypeAndProperty: async (value, callback) => + callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_DATA_BY_TYPE_AND_PROPERTY, value)), - // 删除动态配置的的指定主分类,指定的属性的数据 - DeleteDataByTypeAndProperty: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.DELETE_DATA_BY_TYPE_AND_PROPERTY, value)), + // 删除动态配置的的指定主分类,指定的属性的数据 + DeleteDataByTypeAndProperty: async (value, callback) => + callback( + await ipcRenderer.invoke(DEFINE_STRING.SETTING.DELETE_DATA_BY_TYPE_AND_PROPERTY, value) + ), - // 返回组件尺寸的大小的数据(通用) - GetComponentSize: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_COMPONENT_SIZE), + // 返回组件尺寸的大小的数据(通用) + GetComponentSize: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_COMPONENT_SIZE), - // 获取软件的基础设置(初始的时候执行一次) - GetSoftwareSetting: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING), + // 获取软件的基础设置(初始的时候执行一次) + GetSoftwareSetting: async () => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING), - // 保存软件的基础设置 - SaveSoftWareSetting: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING, value), + // 保存软件的基础设置 + SaveSoftWareSetting: async (value) => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING, value), - //#region MJ的设置 + //#region MJ的设置 - // 获取MJ的基础设置数据 - GetMjSetting: async (value = null) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING, value), + // 获取MJ的基础设置数据 + GetMjSetting: async (value = null) => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING, value), - // 保存MJ的基础设置 - UpdateMJSetting: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, value), + // 保存MJ的基础设置 + UpdateMJSetting: async (value) => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, value), - // 获取MJ的所有设置 - GetMJSettingTreeData: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA), + // 获取MJ的所有设置 + GetMJSettingTreeData: async () => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA), - // 保存MJ的所有设置 - SaveMJSettingTreeData: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, value), + // 保存MJ的所有设置 + SaveMJSettingTreeData: async (value) => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, value), - // MJ代理模式账号同步 - MjRemoteAccountSync: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.MJ_REMOTE_ACCOUNT_SYNC), + // 获取所有的代理MJ的账号 + GetRemoteMJSettings: async () => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_REMOTE_MJ_SETTINGS), - //#endregion + // 添加代理模式的MJ账号 + AddRemoteMJSetting: async (value) => + await ipcRenderer.invoke(DEFINE_STRING.SETTING.ADD_REMOTE_MJ_SETTING, value), + + // 修改并重连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) + + //#endregion } -export { - setting -} \ No newline at end of file +export { setting } diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index bdfa750..110cea4 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -48,7 +48,6 @@ export default defineComponent({ if (software.data == null) { throw new Error('初始化信息错误: 未获取到数据') } - debugger if (software.data.length == 0) { throw new Error('初始化信息错误: 未获取到数据') } diff --git a/src/renderer/src/components/Home/Home.vue b/src/renderer/src/components/Home/Home.vue index 0848e87..20fc81a 100644 --- a/src/renderer/src/components/Home/Home.vue +++ b/src/renderer/src/components/Home/Home.vue @@ -316,21 +316,21 @@ export default defineComponent({ } ] }, - // { - // label: () => - // h( - // RouterLink, - // { - // to: { - // name: 'reverse_management' - // } - // }, - // { - // default: () => '一键反推' - // } - // ), - // key: 'reverse_management' - // }, + { + label: () => + h( + RouterLink, + { + to: { + name: 'reverse_management' + } + }, + { + default: () => '一键反推' + } + ), + key: 'reverse_management' + }, // { // label: "剪辑", // key: "clip_options", diff --git a/src/renderer/src/components/Setting/Components/AddMultiRemoteMj.vue b/src/renderer/src/components/Setting/Components/AddMultiRemoteMj.vue new file mode 100644 index 0000000..5feeb99 --- /dev/null +++ b/src/renderer/src/components/Setting/Components/AddMultiRemoteMj.vue @@ -0,0 +1,196 @@ + + + diff --git a/src/renderer/src/components/Setting/Components/ManageRemoteMjAccount.vue b/src/renderer/src/components/Setting/Components/ManageRemoteMjAccount.vue new file mode 100644 index 0000000..d28077f --- /dev/null +++ b/src/renderer/src/components/Setting/Components/ManageRemoteMjAccount.vue @@ -0,0 +1,175 @@ + + + diff --git a/src/renderer/src/components/Setting/MJSetting.vue b/src/renderer/src/components/Setting/MJSetting.vue index 629f8ec..77f9b7c 100644 --- a/src/renderer/src/components/Setting/MJSetting.vue +++ b/src/renderer/src/components/Setting/MJSetting.vue @@ -1,263 +1,156 @@