V 2.2.11 优化MJ代理模式

This commit is contained in:
lq1405 2024-06-27 16:24:41 +08:00
parent bac97bc41c
commit 669e57824d
40 changed files with 3364 additions and 1644 deletions

4
.gitignore vendored
View File

@ -15,9 +15,11 @@ resources/scripts/virtual py
resources/scripts/_internal resources/scripts/_internal
resources/logger resources/logger
resources/scripts/Temp resources/scripts/Temp
*scripts/db*
resources/image/Temp* resources/image/Temp*
resources/package/ffmpeg-2023* resources/package/ffmpeg/w*
resources/config* resources/config*
*ffmpeg.exe*
*Lai.exe* *Lai.exe*
*Lai_1.exe* *Lai_1.exe*
.DS_Store .DS_Store

View File

@ -3,7 +3,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[javascript]": { "[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[json]": { "[json]": {
"editor.defaultFormatter": "vscode.json-language-features" "editor.defaultFormatter": "vscode.json-language-features"

30
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "laitool", "name": "laitool",
"version": "2.2.9", "version": "2.2.10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "laitool", "name": "laitool",
"version": "2.2.9", "version": "2.2.10",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@alicloud/alimt20181012": "^1.2.0", "@alicloud/alimt20181012": "^1.2.0",
@ -25,7 +25,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"electron-store": "^9.0.0", "electron-store": "^9.0.0",
"electron-updater": "^6.1.7", "electron-updater": "^6.1.7",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.3",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"install": "^0.13.0", "install": "^0.13.0",
"jimp": "^0.22.10", "jimp": "^0.22.10",
@ -51,6 +51,7 @@
"devDependencies": { "devDependencies": {
"@electron-toolkit/eslint-config": "^1.0.1", "@electron-toolkit/eslint-config": "^1.0.1",
"@rushstack/eslint-patch": "^1.6.1", "@rushstack/eslint-patch": "^1.6.1",
"@types/fluent-ffmpeg": "^2.1.24",
"@vitejs/plugin-vue": "^5.0.2", "@vitejs/plugin-vue": "^5.0.2",
"@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-prettier": "^9.0.0",
"electron": "^28.1.1", "electron": "^28.1.1",
@ -2177,6 +2178,15 @@
"version": "1.0.5", "version": "1.0.5",
"license": "MIT" "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": { "node_modules/@types/fs-extra": {
"version": "9.0.13", "version": "9.0.13",
"dev": true, "dev": true,
@ -5049,16 +5059,22 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/fluent-ffmpeg": { "node_modules/fluent-ffmpeg": {
"version": "2.1.2", "version": "2.1.3",
"license": "MIT", "resolved": "https://registry.npmmirror.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz",
"integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==",
"dependencies": { "dependencies": {
"async": ">=0.2.9", "async": "^0.2.9",
"which": "^1.1.1" "which": "^1.1.1"
}, },
"engines": { "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": { "node_modules/fluent-ffmpeg/node_modules/which": {
"version": "1.3.1", "version": "1.3.1",
"license": "ISC", "license": "ISC",

View File

@ -1,6 +1,6 @@
{ {
"name": "laitool", "name": "laitool",
"version": "2.2.10", "version": "2.2.11",
"description": "An AI tool for image processing, video processing, and other functions.", "description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "laitool.cn", "author": "laitool.cn",
@ -33,7 +33,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"electron-store": "^9.0.0", "electron-store": "^9.0.0",
"electron-updater": "^6.1.7", "electron-updater": "^6.1.7",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.3",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"install": "^0.13.0", "install": "^0.13.0",
"jimp": "^0.22.10", "jimp": "^0.22.10",
@ -59,6 +59,7 @@
"devDependencies": { "devDependencies": {
"@electron-toolkit/eslint-config": "^1.0.1", "@electron-toolkit/eslint-config": "^1.0.1",
"@rushstack/eslint-patch": "^1.6.1", "@rushstack/eslint-patch": "^1.6.1",
"@types/fluent-ffmpeg": "^2.1.24",
"@vitejs/plugin-vue": "^5.0.2", "@vitejs/plugin-vue": "^5.0.2",
"@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-prettier": "^9.0.0",
"electron": "^28.1.1", "electron": "^28.1.1",
@ -81,7 +82,7 @@
], ],
"extraResources": [ "extraResources": [
"resources/package/exittool/**", "resources/package/exittool/**",
"resources/package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/**", "resources/package/ffmpeg/**",
"resources/package/Improve/**", "resources/package/Improve/**",
"resources/image/style/**", "resources/image/style/**",
"resources/image/zhanwei.png", "resources/image/zhanwei.png",
@ -94,4 +95,4 @@
"icon": "./resources/icon.ico" "icon": "./resources/icon.ico"
} }
} }
} }

View File

@ -17,8 +17,8 @@ if len(sys.argv) < 2:
"C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe", "C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe",
"-ka", "-ka",
"C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.mp4", "C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.mp4",
"C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.json", "C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.json",
30 30,
] ]
print(sys.argv) print(sys.argv)
@ -35,9 +35,7 @@ elif __file__:
def set_ffmpeg_env(): def set_ffmpeg_env():
# 根据你的ffmpeg路径替换这个 # 根据你的ffmpeg路径替换这个
ffmpeg_path = os.path.join( ffmpeg_path = os.path.join(cript_directory, "../package/ffmpeg/win")
cript_directory, "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin"
)
if sys.platform == "win32": if sys.platform == "win32":
ffmpeg_path = ffmpeg_path.replace("/", "\\") ffmpeg_path = ffmpeg_path.replace("/", "\\")

View File

@ -33,10 +33,10 @@ class Clip:
self.config_path = config_path self.config_path = config_path
self.gpu_type = gpu_type self.gpu_type = gpu_type
self.ffmpeg_path = ( self.ffmpeg_path = (
"../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" "../package/ffmpeg/win/ffmpeg"
) )
self.ffprobe_path = ( self.ffprobe_path = (
"../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffprobe" "../package/ffmpeg/win/ffprobe"
) )
self.getInitData() self.getInitData()
pass pass

Binary file not shown.

View File

@ -130,7 +130,7 @@ def init(draft_path, out_dir, package_path):
file.write(line + "\n") file.write(line + "\n")
ffmpeg_path = os.path.join( ffmpeg_path = os.path.join(
package_path, "ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" package_path, "ffmpeg/win/ffmpeg"
) )
# 抽取关键帧 # 抽取关键帧
num = 1 num = 1

View File

@ -13,12 +13,8 @@ class ImageToVideo:
self.frames = 0 self.frames = 0
self.gpu_type = gpu_type self.gpu_type = gpu_type
self.public_tools = public_tools.PublicTools() self.public_tools = public_tools.PublicTools()
self.ffmpeg_path = ( self.ffmpeg_path = "../package/ffmpeg/win/ffmpeg"
"../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" self.ffprobe_path = "../package/ffmpeg/win/ffprobe"
)
self.ffprobe_path = (
"../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffprobe"
)
pass pass
def create_video_from_image_with_center_offset( def create_video_from_image_with_center_offset(

View File

@ -1,102 +1,107 @@
import { basicApi } from './apiBasic'
import { basicApi } from "./apiBasic"; import { Tools } from '../main/tools'
import { Tools } from "../main/tools"; import { define } from '../define/define'
import { define } from "../define/define";
export class DiscordAPI { export class DiscordAPI {
constructor() { constructor() {
this.tools = new Tools(); this.tools = new Tools()
} }
/**
/** * 通过设置的ID获取MJ API的任务
* 通过设置的ID获取MJ API的任务 * @param {*} id
* @param {*} id */
*/ async GetMJAPITaskByID(id, url, key) {
async GetMJAPITaskByID(id, url, key) { try {
try { let res
let res; url = url.replace('${id}', id)
url = url.replace("${id}", id); let headers = {
let headers = { Authorization: key
"Authorization": key }
} if (url.includes(define.remotemj_api)) {
if (url.includes(define.remotemj_api)) { headers = {
headers = { 'mj-api-secret': define.API
"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,
}
// 判断当前的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
} }
}
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
}
/** // 判断当前的API是哪个
* MJ使用API进行生图 if (url.includes('mjapi.deepwl.net')) {
*/ if (res_data.code == 0) {
async mjApiImagine(url, data, headers) { res_data['message'] = res.data.failReason
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;
} }
} 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
}
}
} }

View File

@ -1,4 +1,3 @@
import fs from 'node:fs'; import fs from 'node:fs';
const fspromises = fs.promises; const fspromises = fs.promises;

40
src/define/Tools/time.js Normal file
View File

@ -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}`
}

View File

@ -5,7 +5,7 @@ export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
id: string id: string
bookId: string bookId: string
bookTaskId: string bookTaskId: string
name: string name: string // 任务名称,小说名+批次名+分镜名
type: BookBackTaskType type: BookBackTaskType
status: BookBackTaskStatus status: BookBackTaskStatus
createTime: Date createTime: Date

View File

@ -112,6 +112,7 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
bookId: string bookId: string
bookTaskId: string bookTaskId: string
videoPath: string | null // 视频地址 videoPath: string | null // 视频地址
audioPath: string | null // 音频地址
word: string | null // 文案 word: string | null // 文案
oldImage: string | null // 旧图片用于SD的图生图 oldImage: string | null // 旧图片用于SD的图生图
afterGpt: string | null // GPT生成的文案 afterGpt: string | null // GPT生成的文案
@ -123,7 +124,7 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
gptPrompt: string | null // GPT提示词 gptPrompt: string | null // GPT提示词
mjMessage: MJMessage | null // MJ消息 mjMessage: MJMessage | null // MJ消息
outImagePath: string | null // 输出图片地址 outImagePath: string | null // 输出图片地址
subImagePath: string[] | null // 字幕图片地址 subImagePath: string[] | null // 图片地址
prompt: string | null // 提示 prompt: string | null // 提示
adetailer: boolean // 是否开启修脸 adetailer: boolean // 是否开启修脸
sdConifg: SDConfig | null // SD配置 sdConifg: SDConfig | null // SD配置
@ -139,6 +140,7 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
bookId: { type: 'string', indexed: true }, bookId: { type: 'string', indexed: true },
bookTaskId: { type: 'string', indexed: true }, bookTaskId: { type: 'string', indexed: true },
videoPath: 'string?', videoPath: 'string?',
audioPath: 'string?',
word: 'string?', word: 'string?',
oldImage: 'string?', oldImage: 'string?',
afterGpt: 'string?', afterGpt: 'string?',

View File

@ -39,9 +39,10 @@ export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
accountId: string | null accountId: string | null
channelId: string channelId: string
coreSize: number coreSize: number
guildId: string guildId: string
mjBotChannelId: string enable: boolean // 是否启用
nijiBotChannelId: string mjBotChannelId: string | null
nijiBotChannelId: string | null
queueSize: number queueSize: number
remark: string remark: string
remixAutoSubmit: boolean remixAutoSubmit: boolean
@ -59,8 +60,9 @@ export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
channelId: 'string', channelId: 'string',
coreSize: 'int', coreSize: 'int',
guildId: 'string', guildId: 'string',
mjBotChannelId: 'string', enable: 'bool',
nijiBotChannelId: 'string', mjBotChannelId: 'string?',
nijiBotChannelId: 'string?',
queueSize: 'int', queueSize: 'int',
remark: 'string', remark: 'string',
remixAutoSubmit: 'bool', remixAutoSubmit: 'bool',

View File

@ -26,14 +26,29 @@ export class BookBackTaskListService extends BaseRealmService {
BookBackTaskListService.instance = new BookBackTaskListService() BookBackTaskListService.instance = new BookBackTaskListService()
await super.getInstance() await super.getInstance()
} }
await BookBackTaskListService.instance.open()
return BookBackTaskListService.instance return BookBackTaskListService.instance
} }
/**
*
* bookId
* @param query bookIdbookTaskIdnametypestatus
*/
getBookBackTaskList(query) {
try {
// if()
} catch (error) {
throw error
}
}
/** /**
* *
* @param bookBackTask * @param bookBackTask
*/ */
async AddBookBackTaskList(bookBackTask) { AddBookBackTaskList(bookBackTask) {
try { try {
// 判断数据是不是存在 // 判断数据是不是存在
if ( if (

View File

@ -32,6 +32,13 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
newBookTask[i].isAuto = false // 为新属性设置默认值 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 { export class BaseRealmService extends BaseService {
@ -72,7 +79,7 @@ export class BaseRealmService extends BaseService {
BookTaskDetailModel BookTaskDetailModel
], ],
path: this.dbpath, path: this.dbpath,
schemaVersion: 2, schemaVersion: 3,
migration: migration migration: migration
} }
this.realm = await Realm.open(config) this.realm = await Realm.open(config)

View File

@ -11,8 +11,8 @@ import { BookTaskService } from './bookTaskService'
import { BaseRealmService } from './bookBasic.js' import { BaseRealmService } from './bookBasic.js'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
class BooKService extends BaseRealmService { export class BookService extends BaseRealmService {
static instance: BooKService | null = null static instance: BookService | null = null
realm: Realm realm: Realm
private constructor() { private constructor() {
@ -24,20 +24,59 @@ class BooKService extends BaseRealmService {
* @returns * @returns
*/ */
public static async getInstance() { public static async getInstance() {
if (BooKService.instance === null) { if (BookService.instance === null) {
BooKService.instance = new BooKService() BookService.instance = new BookService()
await super.getInstance() 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<BookModel>('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 * @returns
*/ */
async GetBookData(bookQuery) { GetBookData(bookQuery) {
try { try {
await this.open()
// 获取所有的小说数据,并进行时间降序排序 // 获取所有的小说数据,并进行时间降序排序
let books = this.realm.objects<BookModel>('Book') let books = this.realm.objects<BookModel>('Book')
let book_length = books.length let book_length = books.length
@ -106,7 +145,6 @@ class BooKService extends BaseRealmService {
*/ */
async AddOrModifyBook(book) { async AddOrModifyBook(book) {
try { try {
await this.open()
if (book == null) { if (book == null) {
throw new Error('小说数据为空,无法修改') throw new Error('小说数据为空,无法修改')
} }
@ -141,6 +179,7 @@ class BooKService extends BaseRealmService {
let bookFolderPath = path.resolve(define.project_path, book.id) let bookFolderPath = path.resolve(define.project_path, book.id)
let imageFolder = path.resolve(define.project_path, `${book.id}/tmp`) let imageFolder = path.resolve(define.project_path, `${book.id}/tmp`)
let oldVideoPath = path.resolve(define.project_path, `${book.id}/data/${book.id}.mp4`) let oldVideoPath = path.resolve(define.project_path, `${book.id}/data/${book.id}.mp4`)
let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001')
// 将视频拷贝一个到项目文件下面 // 将视频拷贝一个到项目文件下面
if (book.oldVideoPath) { if (book.oldVideoPath) {
@ -150,11 +189,11 @@ class BooKService extends BaseRealmService {
// 创建对应的文件夹 // 创建对应的文件夹
await CheckFolderExistsOrCreate(bookFolderPath) await CheckFolderExistsOrCreate(bookFolderPath)
await CheckFolderExistsOrCreate(imageFolder) await CheckFolderExistsOrCreate(imageFolder)
await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹
// 修改数据 // 修改数据
book.oldVideoPath = path.relative(define.project_path, oldVideoPath) book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
this.realm.write(() => { this.realm.write(() => {
this.realm.create('Book', book) this.realm.create('Book', book)
let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001')
// 添加一个任务 // 添加一个任务
let bookTask = { let bookTask = {
id: uuidv4(), id: uuidv4(),
@ -210,5 +249,3 @@ class BooKService extends BaseRealmService {
} }
} }
} }
export default BooKService

View File

@ -6,6 +6,10 @@ import { BookTaskModel } from '../../model/Book/bookTask.js'
import { BookTaskStatus } from '../../../enum/bookEnum.js' import { BookTaskStatus } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/generalTools.js' import { successMessage } from '../../../../main/generalTools.js'
import { BaseRealmService } from './bookBasic' 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') const { v4: uuidv4 } = require('uuid')
let dbPath = path.resolve(define.db_path, 'book.realm') let dbPath = path.resolve(define.db_path, 'book.realm')
@ -30,16 +34,202 @@ export class BookTaskDetailService extends BaseRealmService {
BookTaskDetailService.instance = new BookTaskDetailService() BookTaskDetailService.instance = new BookTaskDetailService()
await super.getInstance() await super.getInstance()
} }
await BookTaskDetailService.instance.open()
return BookTaskDetailService.instance return BookTaskDetailService.instance
} }
/** /**
* *
* @param condition idnamebookIdbookTaskId
*/
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<Realm.Object<DefaultObject, never> & 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 * @param BookTaskDetail
*/ */
public async AddBookTaskDetail(BookTaskDetail) { public AddBookTaskDetail(bookTaskDetail) {
try { try {
// 判断是不是又小说的ID // 判断是不是又小说ID
if (isEmpty(bookTaskDetail.bookId) || isEmpty(bookTaskDetail.bookTaskId)) {
throw new Error(
'新增小说任务详细信息到数据库失败数据不完整缺少小说ID或者小说批次任务ID'
)
}
// 开始初始化数据获取指定的bookId和bookTaskId中最大的no
let bookTaskDetails = this.realm
.objects<BookTaskModel>('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 bookIdbookTaskIdnameid
*/
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) { } catch (error) {
throw error throw error
} }

View File

@ -29,6 +29,7 @@ export class BookTaskService extends BaseRealmService {
BookTaskService.instance = new BookTaskService() BookTaskService.instance = new BookTaskService()
await super.getInstance() await super.getInstance()
} }
await BookTaskService.instance.open()
return BookTaskService.instance return BookTaskService.instance
} }
@ -36,9 +37,8 @@ export class BookTaskService extends BaseRealmService {
* *
* @param bookTaskCondition idbookIdnamenopage, pageSize * @param bookTaskCondition idbookIdnamenopage, pageSize
*/ */
async GetBookTaskData(bookTaskCondition) { GetBookTaskData(bookTaskCondition) {
try { try {
await this.open()
// 获取所有的小说数据,并进行时间降序排序 // 获取所有的小说数据,并进行时间降序排序
let bookTasks = this.realm.objects<BookTaskModel>('BookTask') let bookTasks = this.realm.objects<BookTaskModel>('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 { try {
await this.open()
if (bookTask == null) { if (bookTask == null) {
throw new Error('添加的小说任务不能为空') throw new Error('添加的小说任务不能为空')
} }

View File

@ -249,7 +249,6 @@ export class MJSettingService extends BaseSoftWareService {
if (remoteMjQuery?.id) { if (remoteMjQuery?.id) {
remoteMjSettings = this.realm.objects('RemoteMJ').filtered('id = $0', remoteMjQuery.id) remoteMjSettings = this.realm.objects('RemoteMJ').filtered('id = $0', remoteMjQuery.id)
} }
let resRemoteMj = Array.from(remoteMjSettings).map((remoteMj) => { let resRemoteMj = Array.from(remoteMjSettings).map((remoteMj) => {
return { return {
...remoteMj ...remoteMj
@ -298,6 +297,7 @@ export class MJSettingService extends BaseSoftWareService {
remoteMjSetting.createTime = new Date() remoteMjSetting.createTime = new Date()
remoteMjSetting.updateTime = new Date() remoteMjSetting.updateTime = new Date()
remoteMjSetting.version = version remoteMjSetting.version = version
remoteMjSetting.enable = true
remoteMjSetting.remark = global.machineId remoteMjSetting.remark = global.machineId
// 判断当前this.relam 是不是已经处于一个事务中 // 判断当前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 //#endregion
//#region MJ设置的基础设置 //#region MJ设置的基础设置
@ -540,22 +562,6 @@ export class MJSettingService extends BaseSoftWareService {
} }
// 组合添加数据 // 组合添加数据
this.realm.write(() => { 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设置的数据是不是存在 // 判断API设置的数据是不是存在
let apiSetting = mjSetting.apiSetting ? mjSetting.apiSetting : null let apiSetting = mjSetting.apiSetting ? mjSetting.apiSetting : null
if (apiSetting != null) { if (apiSetting != null) {

View File

@ -60,7 +60,7 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
} }
if (oldRealm.schemaVersion < 9) { if (oldRealm.schemaVersion < 9) {
newRealm.write(() => { newRealm.write(() => {
const newSoftwares = newRealm.objects('MjSetting') const newSoftwares = newRealm.objects('RemoteMJ')
for (let software of newSoftwares) { for (let software of newSoftwares) {
software.accountId = null 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 { export class BaseSoftWareService extends BaseService {
@ -112,7 +137,7 @@ export class BaseSoftWareService extends BaseService {
MjSettingModel MjSettingModel
], ],
path: dbPath, path: dbPath,
schemaVersion: 10, // 当前版本号 schemaVersion: 13, // 当前版本号
migration: migration migration: migration
} }
// 判断当前全局是不是又当前这个 // 判断当前全局是不是又当前这个

View File

@ -1,222 +1,227 @@
export const DEFINE_STRING = { export const DEFINE_STRING = {
OPEN_DEV_TOOLS_PASSWORD: "OPEN_DEV_TOOLS_PASSWORD", OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
OPEN_DEV_TOOLS: "OPEN_DEV_TOOLS", OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS',
GET_FILE_BASE64: "GET_FILE_BASE64", GET_FILE_BASE64: 'GET_FILE_BASE64',
SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY: "SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY", 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_DEFINE_CONFIG_JSON_BY_PROPERTY: 'GET_DEFINE_CONFIG_JSON_BY_PROPERTY',
GET_IMAGE_GENERATE_CATEGORY: "GET_IMAGE_GENERATE_CATEGORY", GET_IMAGE_GENERATE_CATEGORY: 'GET_IMAGE_GENERATE_CATEGORY',
SHOW_MAIN_NOTIFICATION: "SHOW_MAIN_NOTIFICATION", SHOW_MAIN_NOTIFICATION: 'SHOW_MAIN_NOTIFICATION',
SHOW_GLOABAL_MESSAGE: "SHOW_GLOABAL_MESSAGE", SHOW_GLOABAL_MESSAGE: 'SHOW_GLOABAL_MESSAGE',
CHECK_MACHINE_ID: "CHECK_MACHINE_ID", CHECK_MACHINE_ID: 'CHECK_MACHINE_ID',
GET_CUSTOMIZE_GPT_PROMPT: "GET_CUSTOMIZE_GPT_PROMPT", GET_CUSTOMIZE_GPT_PROMPT: 'GET_CUSTOMIZE_GPT_PROMPT',
GENERATE_GPT_EXAMPLE_OUT: "GENERATE_GPT_EXAMPLE_OUT", GENERATE_GPT_EXAMPLE_OUT: 'GENERATE_GPT_EXAMPLE_OUT',
GET_PERMISSION: "GET_PERMISSION", GET_PERMISSION: 'GET_PERMISSION',
SAVE_IMAGE_TO_OTHER_FOLDER: "SAVE_IMAGE_TO_OTHER_FOLDER", SAVE_IMAGE_TO_OTHER_FOLDER: 'SAVE_IMAGE_TO_OTHER_FOLDER',
GET_IMAGE_AUTO_SAVE_SETTING: "GET_IMAGE_AUTO_SAVE_SETTING", GET_IMAGE_AUTO_SAVE_SETTING: 'GET_IMAGE_AUTO_SAVE_SETTING',
SAVE_IMAGE_AUTO_SAVE_SETTING: "SAVE_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", GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS: 'GET_AUTO_SAVE_IMAGE_CLASSIFY_OPTIONS',
MODIFY_GENERATE_TASK_STATUS: "MODIFY_GENERATE_TASK_STATUS", MODIFY_GENERATE_TASK_STATUS: 'MODIFY_GENERATE_TASK_STATUS',
DELETE_BACK_TASK: "DELETE_BACK_TASK", DELETE_BACK_TASK: 'DELETE_BACK_TASK',
SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE: "SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE", SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE: 'SAVE_VIDEO_SRT_AND_AUDIO_MESSAGE',
SAVE_KEY_FRAME_SETTING: "SAVE_KEY_FRAME_SETTING", SAVE_KEY_FRAME_SETTING: 'SAVE_KEY_FRAME_SETTING',
MODIFY_SAMPLE_SETTING: "MODIFY_SAMPLE_SETTING", MODIFY_SAMPLE_SETTING: 'MODIFY_SAMPLE_SETTING',
GET_SETTING_Dafault_DATA: "GET_SETTING_Dafault_DATA", GET_SETTING_Dafault_DATA: 'GET_SETTING_Dafault_DATA',
GET_DRAFT_FILE_LIST: "GET_DRAFT_FILE_LIST", GET_DRAFT_FILE_LIST: 'GET_DRAFT_FILE_LIST',
GET_FRAME: "GET_FRAME", GET_FRAME: 'GET_FRAME',
PYTHON_ERROR: "PYTHON_ERROR", PYTHON_ERROR: 'PYTHON_ERROR',
PYTHON_CLOSE: "PYTHON_CLOSE", PYTHON_CLOSE: 'PYTHON_CLOSE',
PYTHON_OUTPUT: "PYTHON_OUTPUT", PYTHON_OUTPUT: 'PYTHON_OUTPUT',
RESTART_GENERATE: "RESTART_GENERATE", RESTART_GENERATE: 'RESTART_GENERATE',
ALIGN_DRAFT_IMG: "ALIGN_DRAFT_IMG", ALIGN_DRAFT_IMG: 'ALIGN_DRAFT_IMG',
ALIGN_DRAFT_IMG_TO_TEXT: "ALIGN_DRAFT_IMG_TO_TEXT", ALIGN_DRAFT_IMG_TO_TEXT: 'ALIGN_DRAFT_IMG_TO_TEXT',
REGENERATE_IMAGE_RETUN: "REGENERATE_IMAGE_RETUN", REGENERATE_IMAGE_RETUN: 'REGENERATE_IMAGE_RETUN',
GET_SUBFOLDER_LIST: "GET_SUBFOLDER_LIST", GET_SUBFOLDER_LIST: 'GET_SUBFOLDER_LIST',
REFRASH_IMAGWE_DATA: "REFRASH_IMAGWE_DATA", REFRASH_IMAGWE_DATA: 'REFRASH_IMAGWE_DATA',
GET_IMAGE_PROMPTLIST: "GET_IMAGE_PROMPTLIST", GET_IMAGE_PROMPTLIST: 'GET_IMAGE_PROMPTLIST',
SELECT_FILE: "SELECT_FILE", SELECT_FILE: 'SELECT_FILE',
IMPROVE_IMAGE_RESOULTION: "IMPROVE_IMAGE_RESOULTION", IMPROVE_IMAGE_RESOULTION: 'IMPROVE_IMAGE_RESOULTION',
GET_BACKGROUND_MUSIC_CONFIG_LIST: "GET_BACKGROUND_MUSIC_CONFIG_LIST", GET_BACKGROUND_MUSIC_CONFIG_LIST: 'GET_BACKGROUND_MUSIC_CONFIG_LIST',
ADD_BACKGROUND_MUSIC_FOLDER: "ADD_BACKGROUND_MUSIC_FOLDER", ADD_BACKGROUND_MUSIC_FOLDER: 'ADD_BACKGROUND_MUSIC_FOLDER',
DELETE_CLIP_SETTING: "DELETE_CLIP_SETTING", DELETE_CLIP_SETTING: 'DELETE_CLIP_SETTING',
DELETE_FRIENDLY_REMINDER: "DELETE_FRIENDLY_REMINDER", DELETE_FRIENDLY_REMINDER: 'DELETE_FRIENDLY_REMINDER',
MODIFY_INPUT_CROP_JSON: "MODIFY_INPUT_CROP_JSON", MODIFY_INPUT_CROP_JSON: 'MODIFY_INPUT_CROP_JSON',
PUSH_BACK_PROMPT: "PUSH_BACK_PROMPT", PUSH_BACK_PROMPT: 'PUSH_BACK_PROMPT',
GET_FRIENDLY_REMINDER_DRAFT: "GET_FRIENDLY_REMINDER_DRAFT", GET_FRIENDLY_REMINDER_DRAFT: 'GET_FRIENDLY_REMINDER_DRAFT',
GET_FRIENDLY_REMINDER_LIST: "GET_FRIENDLY_REMINDER_LIST", GET_FRIENDLY_REMINDER_LIST: 'GET_FRIENDLY_REMINDER_LIST',
AUTO_GENERATION_VIDEO: "AUTO_GENERATION_VIDEO", AUTO_GENERATION_VIDEO: 'AUTO_GENERATION_VIDEO',
GET_PROJECT_WORD: "GET_PROJECT_WORD", GET_PROJECT_WORD: 'GET_PROJECT_WORD',
AIMODIFY_ONE_WORD: "AIMODIFY_ONE_WORD", AIMODIFY_ONE_WORD: 'AIMODIFY_ONE_WORD',
IMPORT_SRT_AND_GET_TIME: "IMPORT_SRT_AND_GET_TIME", IMPORT_SRT_AND_GET_TIME: 'IMPORT_SRT_AND_GET_TIME',
SAVE_NEW_WORD: "SAVE_NEW_WORD", SAVE_NEW_WORD: 'SAVE_NEW_WORD',
SAVE_COPYWRITING_INFOMATION: "SAVE_COPYWRITING_INFOMATION", SAVE_COPYWRITING_INFOMATION: 'SAVE_COPYWRITING_INFOMATION',
SAVE_SD_CONFIG: "SAVE_SD_CONFIG", SAVE_SD_CONFIG: 'SAVE_SD_CONFIG',
SAVE_GENERAL_SETTING: "SAVE_GENERAL_SETTING", SAVE_GENERAL_SETTING: 'SAVE_GENERAL_SETTING',
GET_VIDEO_CONFIG_MESSAGE: "GET_VIDEO_CONFIG_MESSAGE", GET_VIDEO_CONFIG_MESSAGE: 'GET_VIDEO_CONFIG_MESSAGE',
GET_SYSTEM_INSTALL_FONTNAME: "GET_SYSTEM_INSTALL_FONTNAME", GET_SYSTEM_INSTALL_FONTNAME: 'GET_SYSTEM_INSTALL_FONTNAME',
SAVE_ASS_CONFIG: "SAVE_ASS_CONFIG", SAVE_ASS_CONFIG: 'SAVE_ASS_CONFIG',
DELETE_VIDEO_CONFIG: "DELETE_VIDEO_CONFIG", DELETE_VIDEO_CONFIG: 'DELETE_VIDEO_CONFIG',
SHOW_NEW_WINDOW: "SHOW_NEW_WINDOW", SHOW_NEW_WINDOW: 'SHOW_NEW_WINDOW',
GET_DRAFT_FILE_LIST: "GET_DRAFT_FILE_LIST", GET_DRAFT_FILE_LIST: 'GET_DRAFT_FILE_LIST',
SELECT_FOLDER: "SELECT_FOLDER", SELECT_FOLDER: 'SELECT_FOLDER',
GET_DRAFT_TEXT_STYLE: "GET_DRAFT_TEXT_STYLE", GET_DRAFT_TEXT_STYLE: 'GET_DRAFT_TEXT_STYLE',
GET_TEXT_STYLE_LIST: "GET_TEXT_STYLE_LIST", GET_TEXT_STYLE_LIST: 'GET_TEXT_STYLE_LIST',
DELETE_DRAFT_TEXT_STYLE: "DELETE_DRAFT_TEXT_STYLE", DELETE_DRAFT_TEXT_STYLE: 'DELETE_DRAFT_TEXT_STYLE',
ADD_DRAFT: "ADD_DRAFT", ADD_DRAFT: 'ADD_DRAFT',
RETURN_IMAGE_PROMPT: "RETURN_IMAGE_PROMPT", RETURN_IMAGE_PROMPT: 'RETURN_IMAGE_PROMPT',
RE_GENERATE_IAMGE_ONE: "RE_GENERATE_IAMGE_ONE", RE_GENERATE_IAMGE_ONE: 'RE_GENERATE_IAMGE_ONE',
INIT_SD_CONFIG: "INIT_SD_CONFIG", INIT_SD_CONFIG: 'INIT_SD_CONFIG',
ADD_IMAGE_TASK_LIST: "ADD_IMAGE_TASK_LIST", ADD_IMAGE_TASK_LIST: 'ADD_IMAGE_TASK_LIST',
GET_GENERATE_TASK_LIST: "GET_GENERATE_TASK_LIST", GET_GENERATE_TASK_LIST: 'GET_GENERATE_TASK_LIST',
DELETE_IMAGE_TASK_LIST: "DELETE_IMAGE_TASK_LIST", DELETE_IMAGE_TASK_LIST: 'DELETE_IMAGE_TASK_LIST',
GENERATE_IMAGWE_IN_SELECT_TASK: "GENERATE_IMAGWE_IN_SELECT_TASK", GENERATE_IMAGWE_IN_SELECT_TASK: 'GENERATE_IMAGWE_IN_SELECT_TASK',
GET_MACHINE_ID: "GET_MACHINE_ID", GET_MACHINE_ID: 'GET_MACHINE_ID',
QUIT_APP: "QUIT_APP", QUIT_APP: 'QUIT_APP',
GET_BAD_PROMPT: "GET_BAD_PROMPT", GET_BAD_PROMPT: 'GET_BAD_PROMPT',
SAVE_BAD_PROMPT: "SAVE_BAD_PROMPT", SAVE_BAD_PROMPT: 'SAVE_BAD_PROMPT',
DELETE_BAD_PROMPT: "DELETE_BAD_PROMPT", DELETE_BAD_PROMPT: 'DELETE_BAD_PROMPT',
ADD_WEBUI_JSON: "ADD_WEBUI_JSON", ADD_WEBUI_JSON: 'ADD_WEBUI_JSON',
OPEN_GPT_BUY_URL: "OPEN_GPT_BUY_URL", OPEN_GPT_BUY_URL: 'OPEN_GPT_BUY_URL',
GET_IAMGE_PROMPT_LIST: "GET_IAMGE_PROMPT_LIST", GET_IAMGE_PROMPT_LIST: 'GET_IAMGE_PROMPT_LIST',
GET_ADETAILER_LIST: "GET_ADETAILER_LIST", GET_ADETAILER_LIST: 'GET_ADETAILER_LIST',
SAVE_DETAILER_CONFIG: "SAVE_DETAILER_CONFIG", SAVE_DETAILER_CONFIG: 'SAVE_DETAILER_CONFIG',
OPEN_URL: "OPEN_URL", OPEN_URL: 'OPEN_URL',
GET_VERSION: "GET_VERSION", GET_VERSION: 'GET_VERSION',
GET_FRAME_RETUN: "GET_FRAME_RETUN", GET_FRAME_RETUN: 'GET_FRAME_RETUN',
DOWNLOAD_MODEL: "DOWNLOAD_MODEL", DOWNLOAD_MODEL: 'DOWNLOAD_MODEL',
START_STORY_BOARDING: "START_STORY_BOARDING", START_STORY_BOARDING: 'START_STORY_BOARDING',
SHOW_MESSAGE_DIALOG: "SHOW_MESSAGE_DIALOG", SHOW_MESSAGE_DIALOG: 'SHOW_MESSAGE_DIALOG',
SHOW_GLOABAL_MESSAGE_DIALOG: "SHOW_GLOABAL_MESSAGE_DIALOG", SHOW_GLOABAL_MESSAGE_DIALOG: 'SHOW_GLOABAL_MESSAGE_DIALOG',
IMAGE_TASK_STATUS_REFRESH: "IMAGE_TASK_STATUS_REFRESH", IMAGE_TASK_STATUS_REFRESH: 'IMAGE_TASK_STATUS_REFRESH',
SAVE_TRIAL_END_TIME: "SAVE_TRIAL_END_TIME", SAVE_TRIAL_END_TIME: 'SAVE_TRIAL_END_TIME',
DOWNLOAD_IMAGE_FILE: "DOWNLOAD_IMAGE_FILE", DOWNLOAD_IMAGE_FILE: 'DOWNLOAD_IMAGE_FILE',
OPEN_FOLDER: "OPEN_FOLDER", OPEN_FOLDER: 'OPEN_FOLDER',
VIDEO_GENERATE_STATUS_REFRESH: "VIDEO_GENERATE_STATUS_REFRESH", VIDEO_GENERATE_STATUS_REFRESH: 'VIDEO_GENERATE_STATUS_REFRESH',
AUTO_CONDITION_CHECK: "AUTO_CONDITION_CHECK", AUTO_CONDITION_CHECK: 'AUTO_CONDITION_CHECK',
MODIFY_IMAGE_TASK_LIST: "MODIFY_IMAGE_TASK_LIST", MODIFY_IMAGE_TASK_LIST: 'MODIFY_IMAGE_TASK_LIST',
ACTION_AUTO_VIDEO_TASK: "ACTION_AUTO_VIDEO_TASK", ACTION_AUTO_VIDEO_TASK: 'ACTION_AUTO_VIDEO_TASK',
GET_VIDEO_GENERATE_CONFIG: "GET_VIDEO_GENERATE_CONFIG", GET_VIDEO_GENERATE_CONFIG: 'GET_VIDEO_GENERATE_CONFIG',
TRANSLATE_PROMPT: "TRANSLATE_PROMPT", TRANSLATE_PROMPT: 'TRANSLATE_PROMPT',
TRANSLATE_RETURN_NOW: "TRANSLATE_RETURN_NOW", TRANSLATE_RETURN_NOW: 'TRANSLATE_RETURN_NOW',
TRANSLATE_RETURN_REFRESH: "TRANSLATE_RETURN_REFRESH", TRANSLATE_RETURN_REFRESH: 'TRANSLATE_RETURN_REFRESH',
GET_SHOW_MESSAGE: "GET_SHOW_MESSAGE", GET_SHOW_MESSAGE: 'GET_SHOW_MESSAGE',
AUTO_ANALYZE_CHARACTER: "AUTO_ANALYZE_CHARACTER", AUTO_ANALYZE_CHARACTER: 'AUTO_ANALYZE_CHARACTER',
GET_CONFIG_JSON: "GET_CONFIG_JSON", GET_CONFIG_JSON: 'GET_CONFIG_JSON',
ORIGINAL_ADD_WEBUI_JSON: "ORIGINAL_ADD_WEBUI_JSON", ORIGINAL_ADD_WEBUI_JSON: 'ORIGINAL_ADD_WEBUI_JSON',
GET_PROMPT_JSON: "GET_PROMPT_JSON", GET_PROMPT_JSON: 'GET_PROMPT_JSON',
GPT_PROMPT: "GPT_PROMPT", GPT_PROMPT: 'GPT_PROMPT',
GPT_GENERATE_PROMPT_RETURN: "GPT_GENERATE_PROMPT_RETURN", GPT_GENERATE_PROMPT_RETURN: 'GPT_GENERATE_PROMPT_RETURN',
AUTO_SAVE_DATA_JSON: "AUTO_SAVE_DATA_JSON", AUTO_SAVE_DATA_JSON: 'AUTO_SAVE_DATA_JSON',
ORIGINAL_SD_SINGLE_IMAGE_GENERATE: "ORIGINAL_SD_SINGLE_IMAGE_GENERATE", ORIGINAL_SD_SINGLE_IMAGE_GENERATE: 'ORIGINAL_SD_SINGLE_IMAGE_GENERATE',
SD_ORIGINAL_GENERATE_IMAGE_RETURN: "SD_ORIGINAL_GENERATE_IMAGE_RETURN", SD_ORIGINAL_GENERATE_IMAGE_RETURN: 'SD_ORIGINAL_GENERATE_IMAGE_RETURN',
GET_STYLE_IMAGE_SUB_LIST: "GET_STYLE_IMAGE_SUB_LIST", GET_STYLE_IMAGE_SUB_LIST: 'GET_STYLE_IMAGE_SUB_LIST',
GET_IMAGE_STYLE_INFOMATION: "GET_IMAGE_STYLE_INFOMATION", GET_IMAGE_STYLE_INFOMATION: 'GET_IMAGE_STYLE_INFOMATION',
GET_IMAGE_STYLE_MENU: "GET_IMAGE_STYLE_MENU", GET_IMAGE_STYLE_MENU: 'GET_IMAGE_STYLE_MENU',
GET_GPT_BUSINESS_OPTION: "GET_GPT_BUSINESS_OPTION", GET_GPT_BUSINESS_OPTION: 'GET_GPT_BUSINESS_OPTION',
GET_GPT_MODEL_OPTION: "GET_GPT_MODEL_OPTION", GET_GPT_MODEL_OPTION: 'GET_GPT_MODEL_OPTION',
GET_GPT_AUTO_INFERENCE_OPTIONS: "GET_GPT_AUTO_INFERENCE_OPTIONS", GET_GPT_AUTO_INFERENCE_OPTIONS: 'GET_GPT_AUTO_INFERENCE_OPTIONS',
SAVE_DYNAMIC_GPT_OPTION: "SAVE_DYNAMIC_GPT_OPTION", SAVE_DYNAMIC_GPT_OPTION: 'SAVE_DYNAMIC_GPT_OPTION',
DELETE_DYNAMIC_GPT_OPTION: "DELETE_DYNAMIC_GPT_OPTION", DELETE_DYNAMIC_GPT_OPTION: 'DELETE_DYNAMIC_GPT_OPTION',
TEST_GPT_CONNECTION: "TEST_GPT_CONNECTION", TEST_GPT_CONNECTION: 'TEST_GPT_CONNECTION',
SAVE_WORD_TXT: "SAVE_WORD_TXT", SAVE_WORD_TXT: 'SAVE_WORD_TXT',
GET_KEY_FRAME_CONFIG_DATA: "GET_KEY_FRAME_CONFIG_DATA", GET_KEY_FRAME_CONFIG_DATA: 'GET_KEY_FRAME_CONFIG_DATA',
GET_KEYFRAME_OPTIONS: "GET_KEYFRAME_OPTIONS", GET_KEYFRAME_OPTIONS: 'GET_KEYFRAME_OPTIONS',
QUEUE_BATCH: { QUEUE_BATCH: {
SD_ORIGINAL_GENERATE_IMAGE: "SD_ORIGINAL_GENERATE_IMAGE", SD_ORIGINAL_GENERATE_IMAGE: 'SD_ORIGINAL_GENERATE_IMAGE',
SD_ORIGINAL_GPT_PROMPT: "SD_ORIGINAL_GPT_PROMPT", SD_ORIGINAL_GPT_PROMPT: 'SD_ORIGINAL_GPT_PROMPT',
SD_BACKSTEP_GENERATE_IMAGE: "SD_BACKSTEP_GENERATE_IMAGE", SD_BACKSTEP_GENERATE_IMAGE: 'SD_BACKSTEP_GENERATE_IMAGE',
MJ_ORIGINAL_GENERATE_IMAGE: "MJ_ORIGINAL_GENERATE_IMAGE", MJ_ORIGINAL_GENERATE_IMAGE: 'MJ_ORIGINAL_GENERATE_IMAGE',
LOCAL_IMAGE_IMPROVE: "LOCAL_IMAGE_IMPROVE", LOCAL_IMAGE_IMPROVE: 'LOCAL_IMAGE_IMPROVE',
AUTO_VIDEO_GENERATE: "AUTO_VIDEO_GENERATE", AUTO_VIDEO_GENERATE: 'AUTO_VIDEO_GENERATE',
AUTO_VIDEO_GENERATE_SINGLE: "AUTO_VIDEO_GENERATE_SINGLE", AUTO_VIDEO_GENERATE_SINGLE: 'AUTO_VIDEO_GENERATE_SINGLE',
TRANSLATE_PROMPT: "TRANSLATE_PROMPT", TRANSLATE_PROMPT: 'TRANSLATE_PROMPT',
TRANSLATE_RETURN_NOW_TASK: "TRANSLATE_RETURN_NOW_TASK", TRANSLATE_RETURN_NOW_TASK: 'TRANSLATE_RETURN_NOW_TASK',
IMAGE_SAVE_TO_OTHER_FOLDER: "IMAGE_SAVE_TO_OTHER_FOLDER", IMAGE_SAVE_TO_OTHER_FOLDER: 'IMAGE_SAVE_TO_OTHER_FOLDER',
SAVE_FILE_QUEUE: "SAVE_FILE_QUEUE", SAVE_FILE_QUEUE: 'SAVE_FILE_QUEUE',
AUTO_SAVE_DATA_JSON: "AUTO_SAVE_DATA_JSON" AUTO_SAVE_DATA_JSON: 'AUTO_SAVE_DATA_JSON'
}, },
PERMISSIONS: { PERMISSIONS: {
NORMAL_PERMISSION: "NORMAL_PERMISSION", NORMAL_PERMISSION: 'NORMAL_PERMISSION',
AUTO_SAVE_IMAGE_PERMISSION: "AUTO_SAVE_IMAGE_PERMISSION", AUTO_SAVE_IMAGE_PERMISSION: 'AUTO_SAVE_IMAGE_PERMISSION'
}, },
SD: { SD: {
LOAD_SD_SERVICE_DATA: "LOAD_SD_SERVICE_DATA", LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
TXT2IMG: "TXT2IMG", TXT2IMG: 'TXT2IMG'
}, },
MJ: { MJ: {
SAVE_WORD_SRT: "SAVE_WORD_SRT", SAVE_WORD_SRT: 'SAVE_WORD_SRT',
GET_MJ_CONFIG_SRT_INFORMATION: "GET_MJ_CONFIG_SRT_INFORMATION", GET_MJ_CONFIG_SRT_INFORMATION: 'GET_MJ_CONFIG_SRT_INFORMATION',
GET_TAG_DATA_BY_TYPE_AND_PROPERTY: "GET_TAG_DATA_BY_TYPE_AND_PROPERTY", GET_TAG_DATA_BY_TYPE_AND_PROPERTY: 'GET_TAG_DATA_BY_TYPE_AND_PROPERTY',
SAVE_TAG_PROPERTY_DATA: "SAVE_TAG_PROPERTY_DATA", SAVE_TAG_PROPERTY_DATA: 'SAVE_TAG_PROPERTY_DATA',
DELETE_TAG_PROPERTY_DATA: "DELETE_TAG_PROPERTY_DATA", DELETE_TAG_PROPERTY_DATA: 'DELETE_TAG_PROPERTY_DATA',
GET_TAG_SELECT_MODEL: "GET_TAG_SELECT_MODEL", GET_TAG_SELECT_MODEL: 'GET_TAG_SELECT_MODEL',
TRANSLATE_RETURN_NOW_TASK: "TRANSLATE_RETURN_NOW_TASK", TRANSLATE_RETURN_NOW_TASK: 'TRANSLATE_RETURN_NOW_TASK',
ORIGINAL_MJ_IMAGE_GENERATE: "ORIGINAL_MJ_IMAGE_GENERATE", ORIGINAL_MJ_IMAGE_GENERATE: 'ORIGINAL_MJ_IMAGE_GENERATE',
GET_CHANNEL_ROBOTS: "GET_CHANNEL_ROBOTS", GET_CHANNEL_ROBOTS: 'GET_CHANNEL_ROBOTS',
GET_MJ_GENERATE_CATEGORY: "GET_MJ_GENERATE_CATEGORY", GET_MJ_GENERATE_CATEGORY: 'GET_MJ_GENERATE_CATEGORY',
IMAGE_SPLIT: "IMAGE_SPLIT", IMAGE_SPLIT: 'IMAGE_SPLIT',
ADD_MJ_BAD_PROMPT: "ADD_MJ_BAD_PROMPT", ADD_MJ_BAD_PROMPT: 'ADD_MJ_BAD_PROMPT',
MJ_BAD_PROMPT_CHECK: "MJ_BAD_PROMPT_CHECK", MJ_BAD_PROMPT_CHECK: 'MJ_BAD_PROMPT_CHECK',
GET_GENERATED_MJ_IMAGE_AND_SPLIT: "GET_GENERATED_MJ_IMAGE_AND_SPLIT", GET_GENERATED_MJ_IMAGE_AND_SPLIT: 'GET_GENERATED_MJ_IMAGE_AND_SPLIT',
DOWNLOAD_IMAGE_URL_AND_SPLIT: "DOWNLOAD_IMAGE_URL_AND_SPLIT", DOWNLOAD_IMAGE_URL_AND_SPLIT: 'DOWNLOAD_IMAGE_URL_AND_SPLIT',
GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE', GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE',
GET_MJ_IMAGE_ROBOT_MODEL: "GET_MJ_IMAGE_ROBOT_MODEL", GET_MJ_IMAGE_ROBOT_MODEL: 'GET_MJ_IMAGE_ROBOT_MODEL',
MACTH_USER_RETURN: "MACTH_USER_RETURN", MACTH_USER_RETURN: 'MACTH_USER_RETURN',
AUTO_MATCH_USER: "AUTO_MATCH_USER", AUTO_MATCH_USER: 'AUTO_MATCH_USER'
}, },
DISCORD: { DISCORD: {
OPERATE_REFRASH_DISCORD_URL: "OPERATE_REFRASH_DISCORD_URL", OPERATE_REFRASH_DISCORD_URL: 'OPERATE_REFRASH_DISCORD_URL',
GET_DISCORD_WINDOW_URL: "GET_DISCORD_WINDOW_URL", GET_DISCORD_WINDOW_URL: 'GET_DISCORD_WINDOW_URL',
CREATE_MESSAGE: "CREATE_MESSAGE", CREATE_MESSAGE: 'CREATE_MESSAGE',
UPDATE_MESSAGE: "UPDATE_MESSAGE", UPDATE_MESSAGE: 'UPDATE_MESSAGE',
DELETE_MESSAGE: "DELETE_MESSAGE", DELETE_MESSAGE: 'DELETE_MESSAGE',
MAIN_DISCORD_MESSAGE_CHANGE: "MAIN_DISCORD_MESSAGE_CHANGE", MAIN_DISCORD_MESSAGE_CHANGE: 'MAIN_DISCORD_MESSAGE_CHANGE'
}, },
DISCORD_REQUEST_LISTENER_TYPE: { DISCORD_REQUEST_LISTENER_TYPE: {
INPUT_MODEL_IMAGINE_REQUEST: "INPUT_MODEL_IMAGINE_REQUEST", INPUT_MODEL_IMAGINE_REQUEST: 'INPUT_MODEL_IMAGINE_REQUEST'
}, },
DISCORD_SIMPLE_DATA_TYPE: { DISCORD_SIMPLE_DATA_TYPE: {
URL: "URL", URL: 'URL',
TOKEN: "TOKEN", TOKEN: 'TOKEN'
}, },
MAIN: { MAIN: {
OPEN_DISCORD_WINDOW: "OPEN_DISCORD_WINDOW" OPEN_DISCORD_WINDOW: 'OPEN_DISCORD_WINDOW'
}, },
IMG: { IMG: {
ONE_SPLIT_FOUR: "ONE_SPLIT_FOUR", ONE_SPLIT_FOUR: 'ONE_SPLIT_FOUR',
BASE64_TO_FILE: "BASE64_TO_FILE", BASE64_TO_FILE: 'BASE64_TO_FILE',
PROCESS_IMAGE: "PROCESS_IMAGE", PROCESS_IMAGE: 'PROCESS_IMAGE',
BATCH_PROCESS_IMAGE: "BATCH_PROCESS_IMAGE", BATCH_PROCESS_IMAGE: 'BATCH_PROCESS_IMAGE',
BATCH_PROCESS_IMAGE_RESULT: "BATCH_PROCESS_IMAGE_RESULT" BATCH_PROCESS_IMAGE_RESULT: 'BATCH_PROCESS_IMAGE_RESULT'
}, },
BOOK: { BOOK: {
GET_BOOK_TYPE: "GET_BOOK_TYPE", GET_BOOK_TYPE: 'GET_BOOK_TYPE',
ADD_OR_MODIFY_BOOK: "ADD_OR_MODIFY_BOOK", ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK',
GET_BOOK_DATA: "GET_BOOK_DATA", GET_BOOK_DATA: 'GET_BOOK_DATA',
GET_FRAME_DATA: "GET_FRAME_DATA", GET_FRAME_DATA: 'GET_FRAME_DATA',
GET_BOOK_TASK_DATA: "GET_BOOK_TASK_DATA" GET_BOOK_TASK_DATA: 'GET_BOOK_TASK_DATA',
}, AUTO_ACTION: 'AUTO_ACTION'
SYSTEM: { },
OPEN_FILE: "OPEN_FILE", SYSTEM: {
RETURN_LOGGER: "RETURN_LOGGER", OPEN_FILE: 'OPEN_FILE',
}, RETURN_LOGGER: 'RETURN_LOGGER'
SETTING: { },
GET_DATA_BY_TYPE_AND_PROPERTY: "GET_DATA_BY_TYPE_AND_PROPERTY", SETTING: {
SAVE_DATA_BY_TYPE_AND_PROPERTY: "SAVE_DATA_BY_TYPE_AND_PROPERTY", GET_DATA_BY_TYPE_AND_PROPERTY: 'GET_DATA_BY_TYPE_AND_PROPERTY',
DELETE_DATA_BY_TYPE_AND_PROPERTY: "DELETE_DATA_BY_TYPE_AND_PROPERTY", SAVE_DATA_BY_TYPE_AND_PROPERTY: 'SAVE_DATA_BY_TYPE_AND_PROPERTY',
GET_SOFTWARE_SETTING: "GET_SOFTWARE_SETTING", DELETE_DATA_BY_TYPE_AND_PROPERTY: 'DELETE_DATA_BY_TYPE_AND_PROPERTY',
SAVE_SOFT_WARE_SETTING: "SAVE_SOFT_WARE_SETTING", GET_SOFTWARE_SETTING: 'GET_SOFTWARE_SETTING',
GET_COMPONENT_SIZE: "GET_COMPONENT_SIZE", SAVE_SOFT_WARE_SETTING: 'SAVE_SOFT_WARE_SETTING',
GET_MJ_SETTING_TREE_DATA: "GET_MJ_SETTING_TREE_DATA", GET_COMPONENT_SIZE: 'GET_COMPONENT_SIZE',
SAVE_MJ_SETTING_TREE_DATA: "SAVE_MJ_SETTING_TREE_DATA", GET_MJ_SETTING_TREE_DATA: 'GET_MJ_SETTING_TREE_DATA',
MJ_REMOTE_ACCOUNT_SYNC: "MJ_REMOTE_ACCOUNT_SYNC", SAVE_MJ_SETTING_TREE_DATA: 'SAVE_MJ_SETTING_TREE_DATA',
GET_MJ_SETTING: "GET_MJ_SETTING", MJ_REMOTE_ACCOUNT_SYNC: 'MJ_REMOTE_ACCOUNT_SYNC',
UPDATE_MJ_SETTING: "UPDATE_MJ_SETTING" GET_MJ_SETTING: 'GET_MJ_SETTING',
}, UPDATE_MJ_SETTING: 'UPDATE_MJ_SETTING',
PROMPT: { GET_REMOTE_MJ_SETTINGS: 'GET_REMOTE_MJ_SETTINGS',
GET_SORT_OPTIONS: "GET_SORT_OPTIONS", ADD_REMOTE_MJ_SETTING: 'ADD_REMOTE_MJ_SETTING',
SAVE_PROMPT_SORT_DATA: "SAVE_PROMPT_SORT_DATA", UPDATE_REMOTE_MJ_SETTING: 'UPDATE_REMOTE_MJ_SETTING',
GET_PROMPT_SORT_DATA: "GET_PROMPT_SORT_DATA", DELETE_REMOTE_MJ_SETTING: 'DELETE_REMOTE_MJ_SETTING'
OPEN_PROMPT_FILE_TXT: "OPEN_PROMPT_FILE_TXT" },
} 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'
}
}

View File

@ -1,123 +1,217 @@
const { const { ipcMain, app } = require('electron')
ipcMain, app
} = require("electron")
import { DEFINE_STRING } from '../../define/define_string' import { DEFINE_STRING } from '../../define/define_string'
import { GetDataByTypeAndProperty, SaveDataByTypeAndProperty, DeleteDataByTypeAndProperty } from '../../define/setting/dynamicSetting';
import { import {
Setting GetDataByTypeAndProperty,
} from '../setting/setting' SaveDataByTypeAndProperty,
let setting = new Setting(global); DeleteDataByTypeAndProperty
import { BasicSetting } from '../setting/basicSetting'; } from '../../define/setting/dynamicSetting'
let basicSetting = new BasicSetting(); import { Setting } from '../setting/setting'
import { MJSetting } from '../setting/mjSetting'; let setting = new Setting(global)
let mjSetting = new MJSetting(); import { BasicSetting } from '../setting/basicSetting'
let basicSetting = new BasicSetting()
import { MJSetting } from '../setting/mjSetting'
let mjSetting = new MJSetting()
async function SettingIpc() { 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配置任务 // 监听获取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_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 // 获取选择角色场景模式的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 // 获取当前生成图片的生图方式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 动态设置(只是动态设置) //#region 动态设置(只是动态设置)
// 获取动态配置的的指定主分类指定的属性的数据只是获取动态的type定死了dynamic // 获取动态配置的的指定主分类指定的属性的数据只是获取动态的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 //#endregion
//#region 基础设置 //#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 //#endregion
//#region MJ 设置 //#region MJ 设置
// 获取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的基础设置信息 // 保存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的所有设置 // 获取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的所有设置 // 保存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 //#endregion
} }
export { export { SettingIpc }
SettingIpc
}

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +1,56 @@
import { BookType } from "../../../define/enum/bookEnum"; import { BookType } from '../../../define/enum/bookEnum'
import { errorMessage, successMessage } from "../../generalTools"; import { errorMessage, successMessage } from '../../generalTools'
import BooKService from "../../../define/db/service/Book/bookService"; import { BookService } from '../../../define/db/service/Book/bookService'
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; import { BookTaskService } from '../../../define/db/service/Book/bookTaskService'
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid')
import { define } from '../../../define/define' import { define } from '../../../define/define'
import path from 'path' import path from 'path'
import { CheckFolderExistsOrCreate } from "../../../define/Tools/file"; import { CheckFolderExistsOrCreate } from '../../../define/Tools/file'
export class BookBasic { export class BookBasic {
constructor() { constructor() {}
}
/** /**
* 获取路径中的最后一层或两层目录 * 新增或者是修小说数据
* @param {string} path 文件或目录的完整路径 * @param {*} book 小说信息
* @param {number} level 需要获取的层级数1表示最后一层2表示最后两层 * @returns
* @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
*/
async AddOrModifyBook(book) { async AddOrModifyBook(book) {
try { try {
if (book == null) { if (book == null) {
return errorMessage('小说数据为空,无法修改'); return errorMessage('小说数据为空,无法修改')
} }
// 处理一下数据,处理文件地址(删除前缀,转换为默认地址) // 处理一下数据,处理文件地址(删除前缀,转换为默认地址)
// 当前的小说的名字是不是在数据库中以存在 // 当前的小说的名字是不是在数据库中以存在
let _bookService = await BooKService.getInstance(); let _bookService = await BookService.getInstance()
let res = await _bookService.AddOrModifyBook(book); let res = await _bookService.AddOrModifyBook(book)
return res; return res
} catch (error) { } catch (error) {
return errorMessage('修改数据错误,错误信息如下:' + error.message, 'BookBasic_AddOrModifyBook'); return errorMessage(
'修改数据错误,错误信息如下:' + error.message,
'BookBasic_AddOrModifyBook'
)
} }
} }
// 小说类型返回 // 小说类型返回
GetBookType() { GetBookType() {
return successMessage([{ return successMessage(
label: 'SD反推', [
value: BookType.SD_REVERSE {
}, { label: 'SD反推',
label: 'MJ反推', value: BookType.SD_REVERSE
value: BookType.MJ_REVERSE },
}, { {
label: "原创", label: 'MJ反推',
value: BookType.ORIGINAL value: BookType.MJ_REVERSE
}], '获取小说类型成功'); },
{
label: '原创',
value: BookType.ORIGINAL
}
],
'获取小说类型成功'
)
} }
} }

View File

@ -1,49 +1,104 @@
import { successMessage, errorMessage } from "../../generalTools.js"; import { successMessage, errorMessage } from '../../generalTools.js'
import { BookBasic } from "./BooKBasic.js"; import { BookBasic } from './BooKBasic.js'
import BooKService from "../../../define/db/service/Book/bookService"; import { BookService } from '../../../define/db/service/Book/bookService'
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; import { BookTaskService } from '../../../define/db/service/Book/bookTaskService'
import { define } from '../../../define/define.js' import { define } from '../../../define/define.js'
import path from 'path' import path from 'path'
import { BasicReverse } from '../../Task/basicReverse.js'
/**
* 一键反推的相关操作
*/
export class ReverseBook extends BookBasic { export class ReverseBook extends BookBasic {
constructor() { constructor() {
super() super()
this.basicReverse = new BasicReverse()
} }
//#region 小说相关操作
/** /**
* 获取当前的小说数据 * 获取当前的小说数据
* @param {*} bookQuery * @param {*} bookQuery
*/ */
async GetBookData(bookQuery) { async GetBookData(bookQuery) {
try { 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) { if (res.code == 0) {
throw new Error(res.message) throw new Error(res.message)
} }
return res return res
} catch (error) { } catch (error) {
return errorMessage(error.message, 'ReverseBook_GetBookData'); return errorMessage(error.message, 'ReverseBook_GetBookData')
} }
} }
//#endregion
//#region 小说批次任务相关操作
/** /**
* 获取小说的任务列表 * 获取小说的任务列表
* @param {*} bookTaskCondition 查询任务列表的条件 * @param {*} bookTaskCondition 查询任务列表的条件
*/ */
async GetBookTaskData(bookTaskCondition) { async GetBookTaskData(bookTaskCondition) {
try { try {
let _bookTaskService = await BookTaskService.getInstance(); let _bookTaskService = await BookTaskService.getInstance()
let res = await _bookTaskService.GetBookTaskData(bookTaskCondition) let res = await _bookTaskService.GetBookTaskData(bookTaskCondition)
if (res.code == 0) { if (res.code == 0) {
throw new Error(res.message) throw new Error(res.message)
} }
return res; return res
} catch (error) { } catch (error) {
return errorMessage("获取小说对应批次错误,错误信息入校:" + error.message, 'ReverseBook_GetBookTaskData'); return errorMessage(
'获取小说对应批次错误,错误信息入校:' + error.message,
'ReverseBook_GetBookTaskData'
)
} }
} }
} //#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
}

View File

@ -1,95 +1,567 @@
import path from 'path'; import path from 'path'
import fs from 'fs'; import fs from 'fs'
const util = require('util'); const util = require('util')
const { exec } = require('child_process'); const { exec } = require('child_process')
const execAsync = util.promisify(exec); const execAsync = util.promisify(exec)
import { define } from '../../define/define'; import { define } from '../../define/define'
import BooKService from '../../define/db/service/Book/bookService'; import { BookService } from '../../define/db/service/Book/bookService'
import { TaskScheduler } from './taskScheduler'; import { TaskScheduler } from './taskScheduler'
import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum'; import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum'
import { errorMessage } from '../generalTools'; import { errorMessage, successMessage } from '../generalTools'
import { CheckFileOrDirExist } from '../../define/Tools/file'; import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from '../../define/Tools/file'
import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService'; 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 { export class BasicReverse {
constructor() { constructor() {
this.taskScheduler = new TaskScheduler() 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 * 分镜通过传入的bookId
* @param {*} bookId 传入的bookId * @param {*} bookId 传入的bookId
* @returns * @returns
*/ */
async GetFrameData(bookId) { async GetFrameData(bookId) {
try { try {
let _bookService = await BooKService.getInstance(); let _bookService = await BookService.getInstance()
let _bookTaskDetailService = await BookTaskDetailService.getInstance(); let _bookTaskDetailService = await BookTaskDetailService.getInstance()
let _bookTaskService = await BookTaskService.getInstance()
// 获取对应的小说小说数据,找到对应的小说视频地址 // 获取对应的小说小说数据,找到对应的小说视频地址
let bookQuery = { let bookQuery = {
bookId: bookId bookId: bookId
} }
let bookData = await _bookService.GetBookData(bookQuery) let bookData = _bookService.GetBookData(bookQuery)
if (bookData.code == 0) { if (bookData.code == 0) {
return bookData return bookData
} }
if (bookData.data.book_length <= 0 || bookData.data.res_book.length <= 0) { 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 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 oldVideoPath = book.oldVideoPath
let frameJson = oldVideoPath + '.json' let frameJson = oldVideoPath + '.json'
let sensitivity = 30 let sensitivity = 30
// 开始之前,推送日志 // 开始之前,推送日志
let log_content = `开始进行分镜操作,视频地址:${oldVideoPath},敏感度:${sensitivity},正在调用程序进行处理` 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里面
// 使用异步的方法调用一个python程序然后写入到指定的json文件中k // 使用异步的方法调用一个python程序然后写入到指定的json文件中k
let command = `"${path.join(define.scripts_path, "Lai.exe")}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"` let command = `"${path.join(
const output = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }); define.scripts_path,
'Lai.exe'
)}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"`
const output = await execAsync(command, {
maxBuffer: 1024 * 1024 * 10,
encoding: 'utf-8'
})
// 有错误输出 // 有错误输出
if (output.stderr != '') { if (output.stderr != '') {
await this.taskScheduler.AddLogToDB(bookId, book.type, `分镜失败,错误信息如下:${output.stderr}`, OtherData.DEFAULT, LoggerStatus.FAIL) let error_msg = `分镜失败,错误信息如下:${output.stderr}`
throw new Error(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) let josnIsExist = CheckFileOrDirExist(frameJson)
if (!josnIsExist) { if (!josnIsExist) {
let error_message = `分镜失败,没有找到对应的分镜输出文件:${frameJson}` 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) throw new Error(error_message)
} }
let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8')) let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8'))
if (frameJsonData.length <= 0) { if (frameJsonData.length <= 0) {
await this.taskScheduler.AddLogToDB(bookId, book.type, `分镜失败,没有找到对应的分镜数据`, OtherData.DEFAULT, LoggerStatus.FAIL) let error_msg = `分镜失败,没有找到对应的分镜数据`
throw new Error("分镜失败,没有找到对应的分镜数据") _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++) { for (let i = 0; i < frameJsonData.length; i++) {
let frameData = frameJsonData[i] let dataArray = frameJsonData[i]
let bookTaskDetail = { let bookTaskDetail = {
bookId: bookId, 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() return successMessage(null, `分镜成功,分镜信息在 ${frameJson}`, 'BasicReverse_GetFrameData')
console.log(output.stdout)
} catch (error) { } catch (error) {
return errorMessage(error.message, 'BasicReverse_GetFrameData'); return errorMessage(error.message, 'BasicReverse_GetFrameData')
} }
} }
}
/**
* 裁剪视频
* @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')
}
}
}

214
src/main/Task/taskManage.js Normal file
View File

@ -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))

View File

@ -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)
}

View File

@ -1,11 +1,12 @@
import axios from 'axios'; import axios from 'axios'
import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService' import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService'
import { define } from '../../define/define'; import { define } from '../../define/define'
import { errorMessage, successMessage } from '../generalTools'; import { errorMessage, successMessage } from '../generalTools'
import { isEmpty } from 'lodash'
const { v4: uuidv4 } = require('uuid')
export class MJSetting { export class MJSetting {
constructor() { constructor() {}
}
/** /**
* 获取MJ的基础设置数据 * 获取MJ的基础设置数据
@ -13,143 +14,276 @@ export class MJSetting {
async GetMJSetting(mjSettingQuery) { async GetMJSetting(mjSettingQuery) {
try { try {
let _mjSetting = await MJSettingService.getInstance() let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.GetMjSetting(mjSettingQuery); let res = _mjSetting.GetMjSetting(mjSettingQuery)
return res return res
} catch (error) { } catch (error) {
return errorMessage("获取MJ的基础配置错误错误信息如下" + error.toString(), "MJSetting_GetMJSetting"); return errorMessage(
'获取MJ的基础配置错误错误信息如下' + error.toString(),
'MJSetting_GetMJSetting'
)
} }
} }
/** /**
* 保存MJ的基础设置 * 保存MJ的基础设置
* @param {*} mjSetting 保存的数据 * @param {*} mjSetting 保存的数据
*/ */
async UpdateMJSetting(mjSetting) { async UpdateMJSetting(mjSetting) {
try { try {
let _mjSetting = await MJSettingService.getInstance() let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.UpdateMJSetting(mjSetting); let res = _mjSetting.UpdateMJSetting(mjSetting)
return res return res
} catch (error) { } catch (error) {
return errorMessage("保存MJ的基础配置错误错误信息如下" + error.toString(), "MJSetting_UpdateMJSetting"); return errorMessage(
'保存MJ的基础配置错误错误信息如下' + error.toString(),
'MJSetting_UpdateMJSetting'
)
} }
} }
/** /**
* 获取MJ配置的所有数据 * 获取MJ配置的所有数据
*/ */
async GetMJSettingTreeData() { async GetMJSettingTreeData() {
try { try {
let _mjSetting = await MJSettingService.getInstance() let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.GetMJSettingTreeData(); let res = _mjSetting.GetMJSettingTreeData()
return res return res
} catch (error) { } catch (error) {
return errorMessage("获取MJ配置错误详细错误信息如下" + error.toString(), 'MJSetting_GetMJSettingTreeData'); return errorMessage(
'获取MJ配置错误详细错误信息如下' + error.toString(),
'MJSetting_GetMJSettingTreeData'
)
} }
} }
/** /**
* 保存MJ设置的所有数据 * 保存MJ设置的所有数据
* @param {*} mjSetting * @param {*} mjSetting
*/ */
async SaveMJSettingTreeData(mjSetting) { async SaveMJSettingTreeData(mjSetting) {
try { try {
let _mjSetting = await MJSettingService.getInstance() let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.SaveMJSettingTreeData(mjSetting); let res = _mjSetting.SaveMJSettingTreeData(mjSetting)
return res return res
} catch (error) { } catch (error) {
return errorMessage("保存MJ配置错误详细错误信息如下" + error.toString(), 'MJSetting_SaveMJSettingTreeData'); return errorMessage(
'保存MJ配置错误详细错误信息如下' + error.toString(),
'MJSetting_SaveMJSettingTreeData'
)
} }
} }
/** /**
* 同步MJ代理模式账号信息 * 获取所有的MJ代理模式账号信息
* @param {*} value
* @returns
*/ */
async MjRemoteAccountSync() { async GetRemoteMJSettings() {
try { try {
// 获取账号数据 let _mjSetting = await MJSettingService.getInstance()
let _mjSettingService = await MJSettingService.getInstance() let res = _mjSetting.GetRemoteMJSettings(null)
let remoteMjSettings = _mjSettingService.GetRemoteMJSettings(null); return res
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")
}
} catch (error) { } catch (error) {
return errorMessage("MJ代理模式账号同步错误详细错误信息如下" + error.toString(), 'MJSetting_MjRemoteAccountSync'); return errorMessage(
'获取MJ代理模式账号信息错误详细错误信息如下' + error.toString(),
'MJSetting_GetRemoteMJSettings'
)
} }
} }
}
/**
* 创建新的代理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'
)
}
}
}

View File

@ -20,6 +20,9 @@ const book = {
// 获取小说的分镜 // 获取小说的分镜
GetFrameData: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_FRAME_DATA, bookId), 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 //#endregion
} }

View File

@ -1,45 +1,66 @@
import { ipcRenderer } from "electron" import { ipcRenderer } from 'electron'
import { DEFINE_STRING } from "../define/define_string" import { DEFINE_STRING } from '../define/define_string'
const setting = { const setting = {
// 获取动态配置的的指定主分类指定的属性的数据只是获取动态的type定死了dynamic // 获取动态配置的的指定主分类指定的属性的数据只是获取动态的type定死了dynamic
GetDataByTypeAndProperty: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_DATA_BY_TYPE_AND_PROPERTY, value)), 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的基础设置数据 // 获取MJ的基础设置数据
GetMjSetting: async (value = null) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING, value), GetMjSetting: async (value = null) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING, value),
// 保存MJ的基础设置 // 保存MJ的基础设置
UpdateMJSetting: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, value), UpdateMJSetting: async (value) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, value),
// 获取MJ的所有设置 // 获取MJ的所有设置
GetMJSettingTreeData: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA), GetMJSettingTreeData: async () =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA),
// 保存MJ的所有设置 // 保存MJ的所有设置
SaveMJSettingTreeData: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, value), SaveMJSettingTreeData: async (value) =>
await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, value),
// MJ代理模式账号同步 // 获取所有的代理MJ的账号
MjRemoteAccountSync: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.MJ_REMOTE_ACCOUNT_SYNC), 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 { export { setting }
setting
}

View File

@ -48,7 +48,6 @@ export default defineComponent({
if (software.data == null) { if (software.data == null) {
throw new Error('初始化信息错误: 未获取到数据') throw new Error('初始化信息错误: 未获取到数据')
} }
debugger
if (software.data.length == 0) { if (software.data.length == 0) {
throw new Error('初始化信息错误: 未获取到数据') throw new Error('初始化信息错误: 未获取到数据')
} }

View File

@ -316,21 +316,21 @@ export default defineComponent({
} }
] ]
}, },
// { {
// label: () => label: () =>
// h( h(
// RouterLink, RouterLink,
// { {
// to: { to: {
// name: 'reverse_management' name: 'reverse_management'
// } }
// }, },
// { {
// default: () => '' default: () => '一键反推'
// } }
// ), ),
// key: 'reverse_management' key: 'reverse_management'
// }, },
// { // {
// label: "", // label: "",
// key: "clip_options", // key: "clip_options",

View File

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

View File

@ -0,0 +1,175 @@
<template>
<div style="margin-top: 20px; margin-left: 20px">
<n-form ref="addRef" :model="settingStore.actionRemoteMJ" :rules="rules">
<div style="display: flex">
<div style="margin-top: 10px; flex: 1">
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="guildId">
<n-input
v-model:value="settingStore.actionRemoteMJ.guildId"
placeholder="请填写服务器ID"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="settingStore.actionRemoteMJ.channelId"
placeholder="请填写频道ID"
/>
</n-form-item>
<n-form-item
label="MJ私信ID"
style="width: 200px; margin-left: 10px"
path="mjBotChannelId"
>
<n-input
v-model:value="settingStore.actionRemoteMJ.mjBotChannelId"
placeholder="请填写MJ私信ID"
/>
</n-form-item>
<n-form-item
label="Niji私信ID"
style="width: 200px; margin-left: 10px"
path="nijiBotChannelId"
>
<n-input
v-model:value="settingStore.actionRemoteMJ.nijiBotChannelId"
placeholder="请填写NIJI私信ID"
/>
</n-form-item>
<n-form-item label="用户token" style="width: 240px; margin-left: 10px" path="userToken">
<n-input
v-model:value="settingStore.actionRemoteMJ.userToken"
placeholder="请填写MJtoken"
/>
</n-form-item>
<n-form-item label="用户Agent" style="width: 250px; margin-left: 10px" path="userAgent">
<n-input
v-model:value="settingStore.actionRemoteMJ.userAgent"
placeholder="请填写用户Agent"
/>
</n-form-item>
</div>
<div style="margin-top: 10px; flex: 1">
<n-form-item label="账号并发数" style="width: 100px; margin-left: 10px" path="coreSize">
<n-input-number
v-model:value="settingStore.actionRemoteMJ.coreSize"
:show-button="false"
placeholder="请填写账号并发数"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item label="等待队列" style="width: 100px; margin-left: 10px" path="queueSize">
<n-input-number
v-model:value="settingStore.actionRemoteMJ.queueSize"
:show-button="false"
placeholder="请填写等待队列数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
label="任务超时时间"
style="width: 100px; margin-left: 10px"
path="timeoutMinutes"
>
<n-input-number
v-model:value="settingStore.actionRemoteMJ.timeoutMinutes"
:show-button="false"
placeholder="请填写任务超时时间"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
v-if="settingStore.actionRemoteMJ.accountId != null"
label="账号状态"
style="width: 100px; margin-left: 10px"
path="enable"
>
<n-switch v-model:value="settingStore.actionRemoteMJ.enable">
<template #checked> 启用 </template>
<template #unchecked> 禁用 </template>
</n-switch>
</n-form-item>
<n-form-item style="margin-left: 10px">
<n-button type="info" @click="CreateAccount" :loading="loading">{{
settingStore.actionRemoteMJ.accountId ? '修改并重连' : '创建账号'
}}</n-button>
</n-form-item>
</div>
</div>
</n-form>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NForm, NFormItem, NInput, NInputNumber, NButton, NSwitch } from 'naive-ui'
import { useSettingStore } from '../../../../../stores/setting'
export default defineComponent({
components: {
NForm,
NFormItem,
NInput,
NInputNumber,
NButton,
NSwitch
},
setup() {
let message = useMessage()
debugger
let settingStore = useSettingStore()
let addRef = ref(null)
let loading = ref(false)
onMounted(async () => {
debugger
console.log(settingStore)
})
let rules = {
guildId: [{ required: true, message: '请输入服务器ID', trigger: 'blur' }],
channelId: [{ required: true, message: '请输入频道ID', trigger: 'blur' }],
userToken: [{ required: true, message: '请输入用户token', trigger: 'blur' }]
}
/**
* 创建账号
*/
async function CreateAccount(e) {
debugger
e.preventDefault()
addRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
loading.value = true
//
if (settingStore.actionRemoteMJ.accountId) {
//
let res = await window.setting.UpdateRemoteMJSetting(toRaw(settingStore.actionRemoteMJ))
loading.value = false
if (res.code == 0) {
message.error('更新账号失败,错误消息如下:' + res.message)
return
}
message.success('更新账号成功')
} else {
//
let res = await window.setting.AddRemoteMJSetting(toRaw(settingStore.actionRemoteMJ))
loading.value = false
if (res.code == 0) {
message.error('创建账号失败,错误消息如下:' + res.message)
return
}
message.success('创建账号成功')
settingStore.ResetActionRemoteMJ()
}
})
}
return { settingStore, rules, CreateAccount, addRef, loading }
}
})
</script>

View File

@ -1,263 +1,156 @@
<template> <template>
<n-spin :show="show" size="large"> <div style="overflow: auto; height: 100%">
<div style="overflow: auto; height: 100%"> <n-card title="基础设置" size="medium" hoverable style="min-width: 850px">
<n-card title="基础设置" size="medium" hoverable style="min-width: 850px"> <n-form :model="mjSetting" ref="sampleRef" :rules="sampleRules">
<n-form :model="mjSetting" ref="sampleRef" :rules="sampleRules"> <div style="display: flex; align-items: center">
<div style="display: flex; align-items: center"> <n-form-item label="出图模式" style="width: 150px" path="requestModel">
<n-form-item label="出图模式" style="width: 150px" path="requestModel"> <n-select
<n-select :options="request_model_options"
:options="request_model_options" v-model:value="mjSetting.requestModel"
v-model:value="mjSetting.requestModel" placeholder="请选择出图模式"
placeholder="请选择出图模式" ></n-select>
></n-select>
</n-form-item>
<n-form-item
label="选择生图机器人"
path="selectRobot"
style="width: 120px; margin-left: 10px"
>
<n-select
:options="select_robot_options"
v-model:value="mjSetting.selectRobot"
@update:value="UpdateSelectRobot"
></n-select>
</n-form-item>
<n-form-item
label="机器人模型"
style="width: 120px; margin-left: 10px"
path="imageModel"
>
<n-select
placeholder="请选择机器人模型"
:options="image_model_options"
v-model:value="mjSetting.imageModel"
></n-select>
</n-form-item>
<n-form-item label="生图尺寸" style="width: 120px; margin-left: 10px" path="imageScale">
<n-select
placeholder="请选择生图尺寸"
:options="image_scale_options"
v-model:value="mjSetting.imageScale"
></n-select>
</n-form-item>
<n-form-item
label="命令后缀"
style="width: 160px; margin-left: 10px"
path="image_suffix"
>
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
</n-form-item>
<n-form-item
label="生图任务量"
style="width: 100px; margin-left: 10px"
path="taskCount"
>
<n-input-number
v-model:value="mjSetting.taskCount"
:show-button="false"
placeholder="MJ并发出图数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
label="间隔时间(s)"
style="width: 100px; margin-left: 10px"
path="spaceTime"
>
<n-input-number
v-model:value="mjSetting.spaceTime"
:show-button="false"
placeholder="请输入间隔时间(s)"
:min="1"
:max="30"
></n-input-number>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card
title="API模式设置"
hoverable
style="margin-top: 10px; min-width: 850px"
size="medium"
>
<n-form :model="mjSetting.apiSetting">
<div style="display: flex">
<n-form-item
label="选择出图的API"
style="width: 160px; margin-left: 10px"
path="mjApiUrl"
>
<n-select
:options="mj_api_options"
v-model:value="mjSetting.apiSetting.mjApiUrl"
placeholder="选择出图的中转API"
/>
</n-form-item>
<n-form-item style="margin-left: 10px" path="mj_api_url">
<n-button type="success" @click="openGptBuyUrl">购买</n-button>
</n-form-item>
<n-form-item
label="选择出图速度模式"
style="width: 160px; margin-left: 10px"
path="mjSpeed"
>
<n-select
:options="mj_speed_options"
v-model:value="mjSetting.apiSetting.mjSpeed"
placeholder="选择出图速度模式"
/>
</n-form-item>
<n-form-item label="输入API密钥" style="width: 160px; margin-left: 10px" path="apiKey">
<n-input
type="password"
placeholder="请输入密钥"
v-model:value="mjSetting.apiSetting.apiKey"
></n-input>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card title="代理模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-form :model="mjSetting.remoteSetting">
<div style="display: flex; margin-top: 10px">
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="guildId">
<n-input
v-model:value="mjSetting.remoteSetting.guildId"
placeholder="请填写服务器ID"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="mjSetting.remoteSetting.channelId"
placeholder="请填写频道ID"
/>
</n-form-item>
<n-form-item
label="MJ私信ID"
style="width: 200px; margin-left: 10px"
path="mjBotChannelId"
>
<n-input
v-model:value="mjSetting.remoteSetting.mjBotChannelId"
placeholder="请填写MJ私信ID"
/>
</n-form-item>
<n-form-item
label="Niji私信ID"
style="width: 200px; margin-left: 10px"
path="nijiBotChannelId"
>
<n-input
v-model:value="mjSetting.remoteSetting.nijiBotChannelId"
placeholder="请填写NIJI私信ID"
/>
</n-form-item>
<n-form-item style="width: 200px; margin-left: 10px">
<n-button type="info" @click="AccountSync">账号同步</n-button>
</n-form-item>
</div>
<div style="display: flex; margin-top: 10px">
<n-form-item label="用户token" style="width: 240px" path="token">
<n-input
v-model:value="mjSetting.remoteSetting.userToken"
placeholder="请填写MJtoken"
/>
</n-form-item>
<n-form-item label="用户Agent" style="width: 250px; margin-left: 10px" path="userAgent">
<n-input
v-model:value="mjSetting.remoteSetting.userAgent"
placeholder="请填写用户Agent"
/>
</n-form-item>
<n-form-item label="账号并发数" style="width: 100px; margin-left: 10px" path="coreSize">
<n-input-number
v-model:value="mjSetting.remoteSetting.coreSize"
:show-button="false"
placeholder="请填写账号并发数"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item label="等待队列" style="width: 100px; margin-left: 10px" path="queueSize">
<n-input-number
v-model:value="mjSetting.remoteSetting.queueSize"
:show-button="false"
placeholder="请填写等待队列数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
label="任务超时时间"
style="width: 100px; margin-left: 10px"
path="timeoutMinutes"
>
<n-input-number
v-model:value="mjSetting.remoteSetting.timeoutMinutes"
:show-button="false"
placeholder="请填写任务超时时间"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card title="浏览器模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-form :model="mjSetting.browserSetting">
<div style="display: flex; margin-top: 10px">
<n-form-item>
<n-button type="info" @click="OpenDiscordWindow">打开登录MJ</n-button>
</n-form-item>
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="serviceId">
<n-input
v-model:value="mjSetting.browserSetting.serviceId"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="mjSetting.browserSetting.channelId"
placeholder="登录MJ后切换频道自动获取"
/>
</n-form-item>
<n-form-item label="用户token" style="width: 300px; margin-left: 10px" path="token">
<n-input
v-model:value="mjSetting.browserSetting.token"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
</div>
<n-form-item label="用户Agent" style="width: 810px" path="userAgent">
<n-input
v-model:value="mjSetting.browserSetting.userAgent"
placeholder="登录MJ后切换服务器自动获取可自定义"
style="margin-right: 10px"
/>
<n-tooltip trigger="hover" style="background-color: aliceblue; color: black">
<template #trigger>
<n-checkbox
v-model:checked="mjSetting.browserSetting.userAgentCustom"
style="width: 100px"
>
自定义
</n-checkbox>
</template>
开启自定义需要手动填写userAgent可以填入浏览器的userAgent
</n-tooltip>
</n-form-item> </n-form-item>
</n-form> <n-form-item
</n-card> label="选择生图机器人"
<n-button type="info" round @click="SaveMjSetting" style="margin-top: 10px" path="selectRobot"
>保存MJ配置</n-button style="width: 120px; margin-left: 10px"
> >
</div> <n-select
<template #description> 正在添加或同步MJ账号信息 </template> :options="select_robot_options"
</n-spin> v-model:value="mjSetting.selectRobot"
@update:value="UpdateSelectRobot"
></n-select>
</n-form-item>
<n-form-item label="机器人模型" style="width: 120px; margin-left: 10px" path="imageModel">
<n-select
placeholder="请选择机器人模型"
:options="image_model_options"
v-model:value="mjSetting.imageModel"
></n-select>
</n-form-item>
<n-form-item label="生图尺寸" style="width: 120px; margin-left: 10px" path="imageScale">
<n-select
placeholder="请选择生图尺寸"
:options="image_scale_options"
v-model:value="mjSetting.imageScale"
></n-select>
</n-form-item>
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="image_suffix">
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
</n-form-item>
<n-form-item label="生图任务量" style="width: 100px; margin-left: 10px" path="taskCount">
<n-input-number
v-model:value="mjSetting.taskCount"
:show-button="false"
placeholder="MJ并发出图数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item label="间隔时间(s)" style="width: 100px; margin-left: 10px" path="spaceTime">
<n-input-number
v-model:value="mjSetting.spaceTime"
:show-button="false"
placeholder="请输入间隔时间(s)"
:min="1"
:max="30"
></n-input-number>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card title="API模式设置" hoverable style="margin-top: 10px; min-width: 850px" size="medium">
<n-form :model="mjSetting.apiSetting">
<div style="display: flex">
<n-form-item
label="选择出图的API"
style="width: 160px; margin-left: 10px"
path="mjApiUrl"
>
<n-select
:options="mj_api_options"
v-model:value="mjSetting.apiSetting.mjApiUrl"
placeholder="选择出图的中转API"
/>
</n-form-item>
<n-form-item style="margin-left: 10px" path="mj_api_url">
<n-button type="success" @click="openGptBuyUrl">购买</n-button>
</n-form-item>
<n-form-item
label="选择出图速度模式"
style="width: 160px; margin-left: 10px"
path="mjSpeed"
>
<n-select
:options="mj_speed_options"
v-model:value="mjSetting.apiSetting.mjSpeed"
placeholder="选择出图速度模式"
/>
</n-form-item>
<n-form-item label="输入API密钥" style="width: 160px; margin-left: 10px" path="apiKey">
<n-input
type="password"
placeholder="请输入密钥"
v-model:value="mjSetting.apiSetting.apiKey"
></n-input>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card title="代理模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-button type="info" @click="AddMultiMjAccount">账号管理</n-button>
</n-card>
<n-card title="浏览器模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-form :model="mjSetting.browserSetting">
<div style="display: flex; margin-top: 10px">
<n-form-item>
<n-button type="info" @click="OpenDiscordWindow">打开登录MJ</n-button>
</n-form-item>
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="serviceId">
<n-input
v-model:value="mjSetting.browserSetting.serviceId"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="mjSetting.browserSetting.channelId"
placeholder="登录MJ后切换频道自动获取"
/>
</n-form-item>
<n-form-item label="用户token" style="width: 300px; margin-left: 10px" path="token">
<n-input
v-model:value="mjSetting.browserSetting.token"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
</div>
<n-form-item label="用户Agent" style="width: 810px" path="userAgent">
<n-input
v-model:value="mjSetting.browserSetting.userAgent"
placeholder="登录MJ后切换服务器自动获取可自定义"
style="margin-right: 10px"
/>
<n-tooltip trigger="hover" style="background-color: aliceblue; color: black">
<template #trigger>
<n-checkbox
v-model:checked="mjSetting.browserSetting.userAgentCustom"
style="width: 100px"
>
自定义
</n-checkbox>
</template>
开启自定义需要手动填写userAgent可以填入浏览器的userAgent
</n-tooltip>
</n-form-item>
</n-form>
</n-card>
<n-button type="info" round @click="SaveMjSetting" style="margin-top: 10px"
>保存MJ配置</n-button
>
</div>
</template> </template>
<script> <script>
@ -283,6 +176,7 @@ import { DEFINE_STRING } from '../../../../define/define_string'
import { Reload } from '@vicons/ionicons5' import { Reload } from '@vicons/ionicons5'
import { isEmpty, max, min } from 'lodash' import { isEmpty, max, min } from 'lodash'
import { MJImageType } from '../../../../define/enum/mjEnum' import { MJImageType } from '../../../../define/enum/mjEnum'
import AddMultiRemoteMj from './Components/AddMultiRemoteMj.vue'
export default defineComponent({ export default defineComponent({
components: { components: {
NButton, NButton,
@ -304,7 +198,6 @@ export default defineComponent({
let message = useMessage() let message = useMessage()
let dialog = useDialog() let dialog = useDialog()
let sampleRef = ref(null) let sampleRef = ref(null)
let show = ref(false)
let select_robot_options = ref([ let select_robot_options = ref([
{ {
label: 'MJ', label: 'MJ',
@ -543,25 +436,15 @@ export default defineComponent({
} }
if (request_model == MJImageType.REMOTE_MJ) { if (request_model == MJImageType.REMOTE_MJ) {
if (mjSetting.value.remoteSetting == null) { //
message.error('请先添加代理模式的配置') let remoteMjRes = await window.setting.GetRemoteMJSettings()
if (remoteMjRes.code == 0) {
message.error('获取代理MJ配置失败')
return return
} }
// if (mjSetting.value.remoteSetting.accountId == null) { if (remoteMjRes.data.length <= 0) {
// message.error('') message.error('请先添加代理模式的配置')
// return
// }
//
if (
mjSetting.value.remoteSetting == null ||
mjSetting.value.remoteSetting.guildId == null ||
mjSetting.value.remoteSetting.channelId == null ||
mjSetting.value.remoteSetting.userToken == null ||
mjSetting.value.remoteSetting.userAgent == null
) {
message.error('请检查代理模式设置的必填字段')
return return
} }
} }
@ -590,8 +473,7 @@ export default defineComponent({
if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) { if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) {
window.api.showGlobalMessageDialog({ window.api.showGlobalMessageDialog({
code: 1, code: 1,
message: `数据保存成功, message: `数据保存成功,当前模式为代理模式`
当前生图模式为代理模式若有修改配置请手动同步账号数据但是不要频繁同步有封号风险 `
}) })
} else { } else {
window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' }) window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' })
@ -639,49 +521,18 @@ export default defineComponent({
} }
/** /**
* 账号同步 * 添加多个账号这样可以同时跑多个账号
*/ */
async function AccountSync() { async function AddMultiMjAccount() {
dialog.warning({ //
title: '警告', let dW = window.innerWidth * 0.9
content: () => let dH = window.innerHeight * 0.9
h('div', {}, [ dialog.create({
h( showIcon: false,
'span', title: '管理代理模式MJ账号',
{}, content: () => h(AddMultiRemoteMj, { height: dH }),
{ style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
default: () => '同步数据的信息是保存后的数据' maskClosable: false
}
),
h('br'),
h(
'span',
{ style: 'color : red;font-size : 18px' },
{
default: () => '修改数据后请先保存,请先保存再执行同步操作'
}
),
h('br'),
h(
'span',
{},
{
default: () => '同步操作不要频繁,有封号风险'
}
)
]),
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
show.value = true
let res = await window.setting.MjRemoteAccountSync()
show.value = false
if (res.code == 0) {
message.error(res.message)
return
}
message.success('MJ账号同步成功可以开始使用')
}
}) })
} }
@ -700,8 +551,7 @@ export default defineComponent({
mj_speed_options, mj_speed_options,
openGptBuyUrl, openGptBuyUrl,
sampleRules, sampleRules,
AccountSync, AddMultiMjAccount
show
} }
} }
}) })

51
src/stores/setting.js Normal file
View File

@ -0,0 +1,51 @@
import { defineStore } from 'pinia'
// 系统相关设置
export const useSettingStore = defineStore('setting', {
state: () => ({
actionRemoteMJ: {
id: null,
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
enable: true,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 10,
remark: null,
timeoutMinutes: 10,
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
userToken: null,
createTime: null,
updateTime: null
}
}),
getters: {},
actions: {
/**
* 重置MJ代理模式的数据
*/
ResetActionRemoteMJ() {
this.actionRemoteMJ = {
id: null,
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
enable: true,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 10,
remark: null,
timeoutMinutes: 10,
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
userToken: null,
createTime: null,
updateTime: null
}
}
}
})