V 2.2.10 新增MJ的代理模式

This commit is contained in:
lq1405 2024-06-24 13:11:19 +08:00
parent 79a1929e79
commit bac97bc41c
102 changed files with 6374 additions and 1172 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
node_modules
dist
out
project
resources/scripts/build*
resources/scripts/dist
resources/scripts/model

BIN
default.realm Normal file

Binary file not shown.

BIN
default.realm.lock Normal file

Binary file not shown.

264
package-lock.json generated
View File

@ -6,7 +6,7 @@
"packages": {
"": {
"name": "laitool",
"version": "2.2.8",
"version": "2.2.9",
"hasInstallScript": true,
"dependencies": {
"@alicloud/alimt20181012": "^1.2.0",
@ -17,6 +17,7 @@
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@volcengine/openapi": "^1.16.0",
"7zip-min": "^1.4.4",
"artplayer": "^5.1.6",
"awesome-js": "^2.0.0",
"axios": "^1.6.5",
"blob-to-buffer": "^1.2.9",
@ -36,6 +37,7 @@
"npm": "^10.7.0",
"paddle": "^1.0.0",
"pinia": "^2.1.7",
"realm": "^12.9.0",
"sharp": "^0.33.2",
"systeminformation": "^5.22.10",
"tencentcloud-sdk-nodejs": "^4.0.821",
@ -57,7 +59,7 @@
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.19.2",
"less": "^4.2.0",
"naive-ui": "^2.37.3",
"naive-ui": "^2.38.2",
"prettier": "^3.1.1",
"vfonts": "^0.0.3",
"vite": "^5.0.11",
@ -2084,6 +2086,14 @@
"version": "1.1.0",
"license": "BSD-3-Clause"
},
"node_modules/@realm/fetch": {
"version": "0.1.1",
"resolved": "https://registry.npmmirror.com/@realm/fetch/-/fetch-0.1.1.tgz",
"integrity": "sha512-hkTprw79RXGv54Je0DrjpQPLaz4QID2dO3FmthAQQWAkqwyrqMzrCGzJzLlmTKWZFsgLrN8KQyNewod27P+nJg==",
"engines": {
"node": ">=18"
}
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.9.4",
"cpu": [
@ -2935,6 +2945,14 @@
"version": "2.0.1",
"license": "Python-2.0"
},
"node_modules/artplayer": {
"version": "5.1.6",
"resolved": "https://registry.npmmirror.com/artplayer/-/artplayer-5.1.6.tgz",
"integrity": "sha512-cqnVVLKCKWCryKl6Pmop50/Di9IQwOeNNQs5qWGzJDPiM0qTC7Q/Enusa+8JQid8p09fvp4Vc32ViSSYutdEeQ==",
"dependencies": {
"option-validator": "^2.0.6"
}
},
"node_modules/async": {
"version": "3.2.5",
"license": "MIT"
@ -3148,6 +3166,17 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/bson": {
"version": "4.7.2",
"resolved": "https://registry.npmmirror.com/bson/-/bson-4.7.2.tgz",
"integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
"dependencies": {
"buffer": "^5.6.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"funding": [
@ -3931,6 +3960,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"dev": true,
@ -4864,6 +4901,14 @@
"node_modules/exif-parser": {
"version": "0.1.12"
},
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"engines": {
"node": ">=6"
}
},
"node_modules/extract-zip": {
"version": "2.0.1",
"license": "BSD-2-Clause",
@ -5214,6 +5259,11 @@
"omggif": "^1.0.10"
}
},
"node_modules/github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
},
"node_modules/glob": {
"version": "7.2.3",
"devOptional": true,
@ -6017,6 +6067,14 @@
"json-buffer": "3.0.1"
}
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/kitx": {
"version": "2.1.0",
"license": "MIT",
@ -6430,6 +6488,11 @@
"node": ">=10"
}
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
@ -6463,8 +6526,9 @@
}
},
"node_modules/naive-ui": {
"version": "2.37.3",
"license": "MIT",
"version": "2.38.2",
"resolved": "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.38.2.tgz",
"integrity": "sha512-WhZ+6DW61aYSmFyfH7evcSGFmd2xR68Yq1mNRrVdJwBhZsnNdAUsMN9IeNCVEPMCND/jzYZghkStoNoR5Xa09g==",
"dependencies": {
"@css-render/plugin-bem": "^0.15.12",
"@css-render/vue3-ssr": "^0.15.12",
@ -6512,6 +6576,11 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/napi-build-utils": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
},
"node_modules/natural-compare": {
"version": "1.4.0",
"dev": true,
@ -6532,6 +6601,28 @@
"node": ">= 4.4.x"
}
},
"node_modules/node-abi": {
"version": "3.65.0",
"resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-3.65.0.tgz",
"integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-abi/node_modules/semver": {
"version": "7.6.2",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"license": "MIT",
@ -9093,6 +9184,14 @@
"fn.name": "1.x.x"
}
},
"node_modules/option-validator": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/option-validator/-/option-validator-2.0.6.tgz",
"integrity": "sha512-tmZDan2LRIRQyhUGvkff68/O0R8UmF+Btmiiz0SmSw2ng3CfPZB9wJlIjHpe/MKUZqyIZkVIXCrwr1tIN+0Dzg==",
"dependencies": {
"kind-of": "^6.0.3"
}
},
"node_modules/optionator": {
"version": "0.9.3",
"dev": true,
@ -9204,6 +9303,11 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"node_modules/path-exists": {
"version": "4.0.0",
"dev": true,
@ -9407,6 +9511,55 @@
"node": ">=4"
}
},
"node_modules/prebuild-install": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.2.tgz",
"integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==",
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1",
"node-abi": "^3.3.0",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
"bin": {
"prebuild-install": "bin.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/prebuild-install/node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"dev": true,
@ -9561,6 +9714,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"bin": {
"rc": "cli.js"
}
},
"node_modules/rc/node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/read-config-file": {
"version": "6.3.2",
"dev": true,
@ -9612,6 +9787,31 @@
"minimatch": "^5.1.0"
}
},
"node_modules/realm": {
"version": "12.9.0",
"resolved": "https://registry.npmmirror.com/realm/-/realm-12.9.0.tgz",
"integrity": "sha512-K7JblaSaqqFEu8kObgTCo1ITTYnR8rXYBdb5/5VXxD4VNKQVlrnO6Z4GhxDlohubmF8eNvRdC2wlHAsv2aUsOg==",
"hasInstallScript": true,
"dependencies": {
"@realm/fetch": "^0.1.1",
"bson": "^4.7.2",
"debug": "^4.3.4",
"node-machine-id": "^1.1.12",
"path-browserify": "^1.0.1",
"prebuild-install": "^7.1.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"react-native": ">=0.71.0"
},
"peerDependenciesMeta": {
"react-native": {
"optional": true
}
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"license": "MIT"
@ -9960,9 +10160,7 @@
"url": "https://feross.org/support"
}
],
"license": "MIT",
"optional": true,
"peer": true
"license": "MIT"
},
"node_modules/simple-get": {
"version": "3.1.1",
@ -10275,6 +10473,47 @@
"node": ">=10"
}
},
"node_modules/tar-fs": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.1.tgz",
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^2.1.4"
}
},
"node_modules/tar-fs/node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/tar-fs/node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"node_modules/tar-fs/node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tar-stream": {
"version": "1.6.2",
"license": "MIT",
@ -10516,6 +10755,17 @@
"devOptional": true,
"license": "0BSD"
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"dev": true,

View File

@ -1,9 +1,9 @@
{
"name": "laitool",
"version": "2.2.9",
"description": "An Electron application with Vue",
"version": "2.2.10",
"description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js",
"author": "example.com",
"author": "laitool.cn",
"homepage": "https://electron-vite.org",
"scripts": {
"format": "prettier --write .",
@ -25,6 +25,7 @@
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@volcengine/openapi": "^1.16.0",
"7zip-min": "^1.4.4",
"artplayer": "^5.1.6",
"awesome-js": "^2.0.0",
"axios": "^1.6.5",
"blob-to-buffer": "^1.2.9",
@ -44,6 +45,7 @@
"npm": "^10.7.0",
"paddle": "^1.0.0",
"pinia": "^2.1.7",
"realm": "^12.9.0",
"sharp": "^0.33.2",
"systeminformation": "^5.22.10",
"tencentcloud-sdk-nodejs": "^4.0.821",
@ -65,7 +67,7 @@
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.19.2",
"less": "^4.2.0",
"naive-ui": "^2.37.3",
"naive-ui": "^2.38.2",
"prettier": "^3.1.1",
"vfonts": "^0.0.3",
"vite": "^5.0.11",
@ -84,8 +86,6 @@
"resources/image/style/**",
"resources/image/zhanwei.png",
"resources/scripts/model/**",
"resources/scripts/Lai.exe",
"resources/scripts/_internal/**",
"resources/scripts/discordScript.js",
"resources/tmp/**",
"resources/icon.ico"
@ -94,4 +94,4 @@
"icon": "./resources/icon.ico"
}
}
}
}

View File

@ -15,9 +15,10 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
if len(sys.argv) < 2:
sys.argv = [
"C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe",
"-c",
"C:/Users/27698/Desktop/测试/mjTest/scripts/output_crop_00001.json",
"NVIDIA",
"-ka",
"C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.mp4",
"C:\\Users\\27698\\Desktop\\测试\\123\\测试用 不删.json",
30
]
print(sys.argv)
@ -84,6 +85,10 @@ elif sys.argv[1] == "-k":
getgrame.init(sys.argv[2], sys.argv[3], sys.argv[4])
pass
elif sys.argv[1] == "-ka":
shotSplit.get_fram(sys.argv[2], sys.argv[3], sys.argv[4])
pass
# 智能分镜。字幕识别
elif sys.argv[1] == "-a":
print("开始算法分镜:" + sys.argv[2] + " -- 输出文件夹:" + sys.argv[3])

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,6 +6,7 @@ from scenedetect.stats_manager import StatsManager
from scenedetect.detectors.content_detector import ContentDetector
import os
import sys
import json
import subprocess
from huggingface_hub import hf_hub_download
from faster_whisper import WhisperModel
@ -228,6 +229,22 @@ def GetText(out_folder, mp3_list):
sys.stdout.flush()
def get_fram(video_path, out_path, sensitivity):
try:
shijian_list = find_scenes(video_path, sensitivity) # 多组时间列表
print("总共有%s个场景" % str(len(shijian_list)))
print("开始输出json")
print(shijian_list)
# 将数组中的消息写道json文件中
with open(out_path, "w") as file:
# 将数组写入到指定的json文件
json.dump(shijian_list, file)
print("输出完成")
except Exception as e:
print("出现错误" + str(e))
exit(0)
def init(video_path, video_out_folder, image_out_folder, sensitivity, gpu_type):
v_l = ClipVideo(
video_path, video_out_folder, image_out_folder, sensitivity, gpu_type

View File

@ -1,6 +1,7 @@
import { basicApi } from "./apiBasic";
import { Tools } from "../main/tools";
import { define } from "../define/define";
export class DiscordAPI {
constructor() {
@ -19,6 +20,11 @@ export class DiscordAPI {
let headers = {
"Authorization": key
}
if (url.includes(define.remotemj_api)) {
headers = {
"mj-api-secret": define.API
}
}
res = await basicApi.get(url, headers);
let progress = res.data.progress && res.data.progress.length > 0 ? parseInt(res.data.progress.slice(0, -1)) : 0;

View File

@ -1,5 +1,6 @@
import fs from "fs"
import { isEmpty } from "lodash";
import path from "path";
const fspromises = fs.promises;
@ -17,6 +18,87 @@ export async function CheckFileOrDirExist(path) {
}
}
// 检查文件夹是不是存在,不存在的话,创建
export async function CheckFolderExistsOrCreate(folderPath) {
try {
if (!(await CheckFileOrDirExist(folderPath))) {
await fspromises.mkdir(folderPath, { recursive: true });
}
} catch (error) {
throw new Error(error);
}
}
/**
* 拼接两个地址返回拼接后的地址
* @param {*} rootPath 根目录的消息
* @param {*} subPath 子目录的消息
* @returns
*/
export function JoinPath(rootPath, subPath) {
// 判断第二个地址是不是存在不存在返回null存在返回拼接后的地址
if (subPath && !isEmpty(subPath)) {
return path.resolve(rootPath, subPath)
} else {
return null
}
}
/**
* 拷贝一个文件或者是文件夹到指定的目标地址
* @param {*} source 源文件或文件夹地址
* @param {*} target 目标文件或文件夹地址
* @param {*} checkParent 是否检查父文件夹是否存在不存在的话创建默认false不检查不存在直接创建
*/
export async function CopyFileOrFolder(source, target, checkParent = false) {
try {
// 判断源文件或文件夹是不是存在
if (!(await CheckFileOrDirExist(source))) {
throw new Error(`源文件或文件夹不存在: ${source}`);
}
// 判断父文件夹是否存在,不存在创建
const parent_path = path.dirname(target);
let parentIsExist = await CheckFileOrDirExist(parent_path);
if (!parentIsExist) {
if (checkParent) {
throw new Error(`目的文件或文件夹的父文件夹不存在: ${parent_path}`);
} else {
await fspromises.mkdir(parent_path, { recursive: true });
}
}
// 判断是不是文件夹
const isDirectory = await IsDirectory(source);
// 复制文件夹的逻辑
async function copyDirectory(source, target) {
// 创建目标文件夹
await fspromises.mkdir(target, { recursive: true });
let entries = await fspromises.readdir(source, { withFileTypes: true });
for (let entry of entries) {
let srcPath = path.join(source, entry.name);
let tgtPath = path.join(target, entry.name);
if (entry.isDirectory()) {
await copyDirectory(srcPath, tgtPath);
} else {
await fspromises.copyFile(srcPath, tgtPath);
}
}
}
if (isDirectory) {
// 创建目标文件夹
await copyDirectory(source, target);
} else {
// 复制文件
await fspromises.copyFile(source, target);
}
} catch (error) {
throw error;
}
}
/** *
* @param {*} path 输入的文件地址
* @returns true false 不是

View File

@ -0,0 +1,28 @@
import Realm, { ObjectSchema } from 'realm'
import { BookBackTaskStatus, BookBackTaskType } from '../../../enum/bookEnum'
export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
id: string
bookId: string
bookTaskId: string
name: string
type: BookBackTaskType
status: BookBackTaskStatus
createTime: Date
updateTime: Date
static schema: ObjectSchema = {
name: 'BookBackTaskList',
properties: {
id: 'string',
bookId: { type: 'string', indexed: true },
bookTaskId: { type: 'string', indexed: true },
name: 'string',
type: 'string',
status: 'string',
createTime: 'date',
updateTime: 'date'
},
primaryKey: 'id'
}
}

View File

@ -0,0 +1,37 @@
import Realm, { ObjectSchema } from 'realm'
import { BookType } from '../../../enum/bookEnum'
export class BookModel extends Realm.Object<BookModel> {
id: string
no: number
name: string
bookFolderPath: string
imageFolder: string | null
type: BookType
oldVideoPath: string | null
srtPath: string | null
audioPath: string | null
updateTime: Date
createTime: Date
test: string | null
static schema: ObjectSchema = {
name: 'Book',
properties: {
id: 'string',
no: 'int',
name: 'string',
bookFolderPath: 'string',
type: 'string',
oldVideoPath: 'string?',
srtPath: 'string?',
audioPath: 'string?',
imageFolder: 'string?',
updateTime: 'date',
createTime: 'date',
test: 'string?'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,43 @@
import Realm, { ObjectSchema } from 'realm'
import { BookTaskStatus, BookType } from '../../../enum/bookEnum'
export class BookTaskModel extends Realm.Object<BookTaskModel> {
id: string
no: number
bookId: string
name: string
generateVideoPath: string | null
srtPath: string | null
audioPath: string | null
imageFolder: string | null
styleList: Realm.List<string> | null
prefix: string | null
status: BookTaskStatus
errorMsg: string | null
isAuto: boolean // 是否自动
updateTime: Date
createTime: Date
static schema: ObjectSchema = {
name: 'BookTask',
properties: {
id: 'string',
bookId: { type: 'string', indexed: true },
no: 'int',
name: 'string',
generateVideoPath: 'string?',
srtPath: 'string?',
audioPath: 'string?',
imageFolder: 'string?',
styleList: 'string[]',
prefix: 'string?',
status: 'string',
errorMsg: 'string?',
isAuto: 'bool',
updateTime: 'date',
createTime: 'date'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,163 @@
import Realm, { ObjectSchema } from 'realm'
import {
BookBackTaskStatus,
BookBackTaskType,
BookTaskStatus,
BookType,
MJAction,
MJCategroy
} from '../../../enum/bookEnum'
export class Subtitle extends Realm.Object<Subtitle> {
startTime: number
endTime: number
srtValue: string
id: string
static schema = {
name: 'Subtitle',
properties: {
startTime: 'int',
endTime: 'int',
srtValue: 'string',
id: 'string'
},
primaryKey: 'id'
}
}
export class MJMessage extends Realm.Object<MJMessage> {
id: string
mjApiUrl: string | null
progress: number
category: MJCategroy
imageClick: string | null // 图片点击(显示的小的)
imageShow: string | null // 图片实际的地址
messageId: string // 消息ID可以是MJ中的也可以是API中的
action: MJAction // 动作(生图,反推之类)
status: string // 状态
message: string | null // 消息
static schema: ObjectSchema = {
name: 'MJMessage',
properties: {
id: 'string',
mjApiUrl: 'string?',
progress: 'int',
category: 'string',
imageClick: 'string?',
imageShow: 'string?',
messageId: 'string',
action: 'string',
status: 'string',
message: 'string?'
},
primaryKey: 'id'
}
}
export class WebuiConfig extends Realm.Object<WebuiConfig> {
sampler_name: string // 采样器名称
negative_prompt: string // 负面提示
batch_size: number // 批次大小
steps: number // 步数
cfg_scale: number // 提示词相关性
denoising_strength: number // 降噪强度
width: number // 宽度
height: number // 高度
seed: number // 种子
init_images: string // 初始图片(垫图的图片地址)
id: string
static schema: ObjectSchema = {
name: 'WebuiConfig',
properties: {
sampler_name: 'string',
negative_prompt: 'string',
batch_size: 'int',
steps: 'int',
cfg_scale: 'int',
denoising_strength: 'int',
width: 'int',
height: 'int',
seed: 'int',
init_images: 'string',
id: 'string'
},
primaryKey: 'id'
}
}
export class SDConfig extends Realm.Object<SDConfig> {
checkpoints: string // 大模型
api: string // api地址
model: string // 生图方式
webuiConfig: WebuiConfig
id: string
static schema: ObjectSchema = {
name: 'SDConfig',
properties: {
checkpoints: 'string',
api: 'string',
model: 'string',
webuiConfig: 'WebuiConfig',
id: 'string'
},
primaryKey: 'id'
}
}
export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
id: string
no: number
name: string
bookId: string
bookTaskId: string
videoPath: string | null // 视频地址
word: string | null // 文案
oldImage: string | null // 旧图片用于SD的图生图
afterGpt: string | null // GPT生成的文案
startTime: number | null // 开始时间
endTime: number | null // 结束时间
timeLimit: string | null // 事件实现0 -- 3000
subValue: Realm.List<Subtitle> | null // 包含的字幕数据
characterTags: string[] | null // 角色标签
gptPrompt: string | null // GPT提示词
mjMessage: MJMessage | null // MJ消息
outImagePath: string | null // 输出图片地址
subImagePath: string[] | null // 字幕图片地址
prompt: string | null // 提示
adetailer: boolean // 是否开启修脸
sdConifg: SDConfig | null // SD配置
createTime: Date
updateTime: Date
static schema: ObjectSchema = {
name: 'BookTaskDetail',
properties: {
id: 'string',
no: 'int',
name: 'string',
bookId: { type: 'string', indexed: true },
bookTaskId: { type: 'string', indexed: true },
videoPath: 'string?',
word: 'string?',
oldImage: 'string?',
afterGpt: 'string?',
startTime: 'int?',
endTime: 'int?',
timeLimit: 'string?',
subValue: { type: 'list', objectType: 'Subtitle' },
characterTags: { type: 'list', objectType: 'string' },
gptPrompt: 'string?',
mjMessage: 'MJMessage?',
outImagePath: 'string?',
subImagePath: 'string[]',
prompt: 'string?',
adetailer: 'bool',
sdConifg: 'SDConfig?',
createTime: 'date',
updateTime: 'date'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,27 @@
import Realm, { ObjectSchema } from 'realm'
import { LoggerStatus, LoggerType } from '../../../enum/softwareEnum'
export class LoggerModel extends Realm.Object<LoggerModel> {
id: string
bookId: string // 小说ID
bookTaskId: string // 小说任务ID
type: LoggerType
status: LoggerStatus
date: Date
content: string
static schema: ObjectSchema = {
name: 'Logger',
properties: {
id: 'string',
bookId: 'string',
bookTaskId: 'string',
type: 'string',
status: 'string',
date: 'date',
content: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,136 @@
import Realm, { ObjectSchema } from 'realm'
import { LoggerStatus, LoggerType } from '../../../enum/softwareEnum'
import { MJImageType, MJRobotType } from '../../../enum/mjEnum'
export class BrowserMJModel extends Realm.Object<BrowserMJModel> {
id: string
serviceId: string
channelId: string
mjBotId: string
nijBotId: string
token: string
userAgent: string
userAgentCustom: boolean
createTime: Date
updateTime: Date
version: string
static schema: ObjectSchema = {
name: 'BrowserMJ',
properties: {
id: 'string',
serviceId: 'string',
channelId: 'string',
mjBotId: 'string?',
nijBotId: 'string?',
token: 'string',
userAgent: 'string',
userAgentCustom: 'bool',
createTime: 'date',
updateTime: 'date',
version: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}
export class RemoteMJModel extends Realm.Object<RemoteMJModel> {
id: string
accountId: string | null
channelId: string
coreSize: number
guildId: string
mjBotChannelId: string
nijiBotChannelId: string
queueSize: number
remark: string
remixAutoSubmit: boolean
timeoutMinutes: number
userAgent: string
userToken: string
createTime: Date
updateTime: Date
version: string
static schema: ObjectSchema = {
name: 'RemoteMJ',
properties: {
id: 'string',
accountId: 'string?',
channelId: 'string',
coreSize: 'int',
guildId: 'string',
mjBotChannelId: 'string',
nijiBotChannelId: 'string',
queueSize: 'int',
remark: 'string',
remixAutoSubmit: 'bool',
timeoutMinutes: 'int',
userAgent: 'string',
userToken: 'string',
createTime: 'date',
updateTime: 'date',
version: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}
export class APIMjModel extends Realm.Object<APIMjModel> {
id: string
mjApiUrl: string
mjSpeed: string // MJ出图的速度模式
apiKey: string
createTime: Date
updateTime: Date
version: string
static schema: ObjectSchema = {
name: 'APIMj',
properties: {
id: 'string',
mjApiUrl: 'string',
mjSpeed: 'string',
apiKey: 'string',
createTime: 'date',
updateTime: 'date',
version: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}
export class MjSettingModel extends Realm.Object<MjSettingModel> {
id: string
type: MJImageType
requestModel: MJImageType
selectRobot: MJRobotType
imageScale: string
imageModel: string
imageSuffix: string
taskCount: number
spaceTime: number
createTime: Date
updateTime: Date
version: string
static schema: ObjectSchema = {
name: 'MjSetting',
properties: {
id: 'string',
type: 'string',
requestModel: 'string',
selectRobot: 'string',
imageScale: 'string',
imageModel: 'string',
imageSuffix: 'string',
taskCount: 'int',
spaceTime: 'int',
createTime: 'date',
updateTime: 'date',
version: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,23 @@
import Realm, { ObjectSchema } from 'realm'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum'
export class SoftwareModel extends Realm.Object<SoftwareModel> {
id: string
theme: SoftwareThemeType
reverse_display_show: boolean
reverse_show_book_striped: boolean
reverse_data_table_size: ComponentSize
static schema: ObjectSchema = {
name: 'Software',
properties: {
id: 'string',
theme: 'string',
reverse_display_show: 'bool',
reverse_show_book_striped: 'bool',
reverse_data_table_size: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,141 @@
import Realm from 'realm'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { BookTaskModel } from '../../model/Book/bookTask.js'
import { BookTaskStatus } from '../../../enum/bookEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { BaseRealmService } from './bookBasic'
import { isEmpty } from 'lodash'
const { v4: uuidv4 } = require('uuid')
export class BookBackTaskListService extends BaseRealmService {
static instance: BookBackTaskListService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (BookBackTaskListService.instance === null) {
BookBackTaskListService.instance = new BookBackTaskListService()
await super.getInstance()
}
return BookBackTaskListService.instance
}
/**
*
* @param bookBackTask
*/
async AddBookBackTaskList(bookBackTask) {
try {
// 判断数据是不是存在
if (
isEmpty(bookBackTask.bookId) ||
isEmpty(bookBackTask.bookTaskId) ||
isEmpty(bookBackTask.name) ||
isEmpty(bookBackTask.type)
) {
throw new Error('新增后台队列任务到数据库失败,数据不完整,缺少必要字段')
}
// 开始新建
bookBackTask.id = uuidv4()
bookBackTask.createTime = new Date()
bookBackTask.updateTime = new Date()
bookBackTask.status = BookTaskStatus.WAIT
this.realm.write(() => {
this.realm.create('BookBackTaskList', bookBackTask)
})
return successMessage(
bookBackTask,
'新增后台队列任务到数据库成功',
'BookBackTaskList_AddBookBackTaskList'
)
} catch (error) {
return errorMessage(
'新增后台队列任务到数据库失败,错误信息入校' + error.toString(),
'BookBackTaskList_AddBookBackTaskList'
)
}
}
/**
*
* @param bookBackTask
*/
async ModifyBookBackTaskList(bookBackTask) {
try {
// 判断数据是不是存在
if (isEmpty(bookBackTask.id) || isEmpty(bookBackTask.status)) {
throw new Error('修改后台队列任务失败,数据不完整,缺少必要字段')
}
// 开始修改
this.realm.write(() => {
// 获取指定ID的队列任务
let _bookBackTask = this.realm.objectForPrimaryKey('BookBackTaskList', bookBackTask.id)
// 判断数据是不是存在
if (_bookBackTask == null) {
throw new Error('修改后台队列任务失败,数据不存在')
}
// 修改数据
_bookBackTask.status = bookBackTask.status
})
return successMessage(
bookBackTask,
'修改后台队列任务成功',
'BookBackTaskList_ModifyBookBackTaskList'
)
} catch (error) {
return errorMessage(
'修改后台队列任务失败,错误信息如下:' + error.toString(),
'BookBackTaskList_ModifyBookBackTaskList'
)
}
}
/**
* idbookIdbookTaskId
* @param bookBackTask
*/
async DeleteBookBackTaskListBy(bookBackTask) {
try {
this.realm.write(() => {
// 构建查询条件
let query = [] as string[]
if (bookBackTask.id) {
query.push(`id = ${bookBackTask.id}`)
}
if (bookBackTask.bookId) {
query.push(`bookId = ${bookBackTask.bookId}`)
}
if (bookBackTask.bookTaskId) {
query.push(`bookTaskId = ${bookBackTask.bookTaskId}`)
}
const queryString = query.join(' && ')
// 获取指定的数据
if (queryString) {
const tasksToDelete = this.realm.objects('BookBackTaskList').filtered(queryString)
this.realm.delete(tasksToDelete)
} else {
throw new Error('删除后台队列任务失败,没有筛选条件')
}
return successMessage(
bookBackTask,
'删除后台队列任务成功',
'BookBackTaskList_DeleteBookBackTaskListBy'
)
})
} catch (error) {
return errorMessage(
'删除后台队列任务失败,错误信息如下:' + error.toString(),
'BookBackTaskList_DeleteBookBackTaskListBy'
)
}
}
}

View File

@ -0,0 +1,83 @@
import Realm from 'realm'
import { BookModel } from '../../model/Book/book'
import { BookTaskModel } from '../../model/Book/bookTask'
import { BaseService } from '../baseService'
import { define } from '../../../define'
import path from 'path'
import {
BookTaskDetailModel,
MJMessage,
SDConfig,
Subtitle,
WebuiConfig
} from '../../model/Book/bookTaskDetail'
import { BookBackTaskList } from '../../model/Book/BookBackTaskListModel'
let dbPath = path.resolve(define.db_path, 'book.realm')
// 版本迁移
const migration = (oldRealm: Realm, newRealm: Realm) => {
if (oldRealm.schemaVersion < 1) {
const oldBooks = oldRealm.objects('Book')
const newBooks = newRealm.objects('Book')
for (let i = 0; i < oldBooks.length; i++) {
newBooks[i].test = 'defaultValue' // 为新属性设置默认值
}
}
if (oldRealm.schemaVersion < 2) {
const oldBookTask = oldRealm.objects('BookTask')
const newBookTask = newRealm.objects('BookTask')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].isAuto = false // 为新属性设置默认值
}
}
}
export class BaseRealmService extends BaseService {
static instance: BaseRealmService | null = null
protected realm: Realm | null = null
dbpath: string
protected constructor() {
super()
this.dbpath = dbPath
}
public static async getInstance() {
if (BaseRealmService.instance === null) {
BaseRealmService.instance = new BaseRealmService()
await BaseRealmService.instance.open()
}
return BaseRealmService.instance
}
/**
*
* @returns
*/
async open() {
try {
if (this.realm != null) return
// 判断当前全局是不是又当前这个
const config = {
schema: [
BookModel,
Subtitle,
MJMessage,
BookBackTaskList,
SDConfig,
WebuiConfig,
BookTaskModel,
BookTaskDetailModel
],
path: this.dbpath,
schemaVersion: 2,
migration: migration
}
this.realm = await Realm.open(config)
} catch (error) {
throw error
}
}
}

View File

@ -0,0 +1,214 @@
import Realm, { UpdateMode } from 'realm'
import { BookModel } from '../../model/Book/book.js'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { BookTaskStatus, BookType } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/generalTools.js'
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../Tools/file.js'
const { v4: uuidv4 } = require('uuid')
import { BookTaskService } from './bookTaskService'
import { BaseRealmService } from './bookBasic.js'
import { isEmpty } from 'lodash'
class BooKService extends BaseRealmService {
static instance: BooKService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (BooKService.instance === null) {
BooKService.instance = new BooKService()
await super.getInstance()
}
return BooKService.instance
}
/**
*
* @returns
*/
async GetBookData(bookQuery) {
try {
await this.open()
// 获取所有的小说数据,并进行时间降序排序
let books = this.realm.objects<BookModel>('Book')
let book_length = books.length
// 开始开始筛选
if (bookQuery.bookId) {
// 查询对应的小说ID的数据
books = books.filtered('id = $0', bookQuery.bookId)
}
books = books.sorted('updateTime', true)
// 判断是不是有page和pageSize有的话对查询返回的信息做分页
if (bookQuery.page && bookQuery.pageSize) {
books = books.slice(
(bookQuery.page - 1) * bookQuery.pageSize,
bookQuery.page * bookQuery.pageSize
) as unknown as Realm.Results<BookModel>
}
if (books.length <= 0) {
return successMessage(
{
res_book: [],
book_length: 0
},
'没有数据',
'ReverseBook_GetBookData'
)
}
// 将realm对象数组转换为普通对象数组
let res_book = 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(
{
res_book,
book_length
},
'获取成功',
'ReverseBook_GetBookData'
)
} catch (error) {
throw error
}
}
/**
*
* @param {*} book
* @returns
*/
async AddOrModifyBook(book) {
try {
await this.open()
if (book == null) {
throw new Error('小说数据为空,无法修改')
}
// 当小说的类型是反推的时候,必须传入视频
if (book.type == BookType.MJ_REVERSE || book.type == BookType.SD_REVERSE) {
// 判断视频是否存在
if (book.oldVideoPath == null || book.oldVideoPath == '') {
throw new Error('反推必须传入视频')
}
}
if (book.id == null) {
// 新增
// 判断指定的名字在数据库中是否存在
let books = this.realm.objects('Book').filtered('name = $0', book.name)
if (books.length > 0) {
throw new Error(`小说名字 ${book.name} 已经存在,请更换小说名字`)
}
console.log(this)
// 新增数据
book.id = uuidv4()
book.createTime = new Date()
book.updateTime = new Date()
// 检查传入的视频文件是不是存在
// 获取当前最大的no
let maxNo = this.realm.objects('Book').max('no')
book.no = maxNo == null ? 1 : Number(maxNo) + 1
// 拼接项目文件夹
book.bookFolderPath = book.id
book.imageFolder = `${book.id}/tmp`
let bookFolderPath = path.resolve(define.project_path, book.id)
let imageFolder = path.resolve(define.project_path, `${book.id}/tmp`)
let oldVideoPath = path.resolve(define.project_path, `${book.id}/data/${book.id}.mp4`)
// 将视频拷贝一个到项目文件下面
if (book.oldVideoPath) {
await CopyFileOrFolder(book.oldVideoPath, oldVideoPath)
}
// 创建对应的文件夹
await CheckFolderExistsOrCreate(bookFolderPath)
await CheckFolderExistsOrCreate(imageFolder)
// 修改数据
book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
this.realm.write(() => {
this.realm.create('Book', book)
let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001')
// 添加一个任务
let bookTask = {
id: uuidv4(),
bookId: book.id,
no: 1,
name: 'output_00001',
generateVideoPath: null,
srtPath: null,
audioPath: null,
imageFolder: path.relative(define.project_path, bookTaskImageFolder), // 获取文件输出对于项目的相对路径
styleList: [],
prefix: null,
status: BookTaskStatus.WAIT,
errorMsg: null,
isAuto: false,
updateTime: new Date(),
createTime: new Date()
}
// 添加任务
this.realm.create('BookTask', bookTask)
})
// 保存成功,返回数据,但是要做处理
book.bookFolderPath = bookFolderPath
book.imageFolder = imageFolder
book.oldVideoPath = oldVideoPath
return successMessage(book, '新增成功', 'BookBasic_AddOrModifyBook')
} else {
// 修改
// 判断指定的名字在数据库中是否存在(不算自己)
let books = this.realm
.objects('Book')
.filtered('name = $0 AND id != $1', book.name, book.id)
if (books.length > 0) {
throw new Error(`小说名字 ${book.name} 已经存在,请更换小说名字`)
}
// 两个文件夹地址不能改,删除两个属性
delete book.bookFolderPath
delete book.imageFolder
// 修改数据
book.updateTime = new Date()
this.realm.write(() => {
this.realm.create('Book', book, UpdateMode.Modified)
})
// 保存成功,返回数据,但是要做处理
return successMessage(null, '修改成功', 'BookBasic_AddOrModifyBook')
}
} catch (error) {
throw error
}
}
}
export default BooKService

View File

@ -0,0 +1,47 @@
import Realm from 'realm'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { BookTaskModel } from '../../model/Book/bookTask.js'
import { BookTaskStatus } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/generalTools.js'
import { BaseRealmService } from './bookBasic'
const { v4: uuidv4 } = require('uuid')
let dbPath = path.resolve(define.db_path, 'book.realm')
// 版本迁移
const migration = (oldRealm: Realm, newRealm: Realm) => {}
export class BookTaskDetailService extends BaseRealmService {
static instance: BookTaskDetailService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (BookTaskDetailService.instance === null) {
BookTaskDetailService.instance = new BookTaskDetailService()
await super.getInstance()
}
return BookTaskDetailService.instance
}
/**
*
* @param BookTaskDetail
*/
public async AddBookTaskDetail(BookTaskDetail) {
try {
// 判断是不是又小说的ID
} catch (error) {
throw error
}
}
}

View File

@ -0,0 +1,139 @@
import Realm from 'realm'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { BookTaskModel } from '../../model/Book/bookTask.js'
import { BookTaskStatus } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/generalTools.js'
import { BaseRealmService } from './bookBasic'
import { isEmpty } from 'lodash'
import { JoinPath } from '../../../Tools/file.js'
const { v4: uuidv4 } = require('uuid')
let dbPath = path.resolve(define.db_path, 'book.realm')
export class BookTaskService extends BaseRealmService {
static instance: BookTaskService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (BookTaskService.instance === null) {
BookTaskService.instance = new BookTaskService()
await super.getInstance()
}
return BookTaskService.instance
}
/**
*
* @param bookTaskCondition idbookIdnamenopage, pageSize
*/
async GetBookTaskData(bookTaskCondition) {
try {
await this.open()
// 获取所有的小说数据,并进行时间降序排序
let bookTasks = this.realm.objects<BookTaskModel>('BookTask')
// 开始开始筛选
if (bookTaskCondition.id) {
// 查询对应的小说ID的数据
bookTasks = bookTasks.filtered('id = $0', bookTaskCondition.id)
}
if (bookTaskCondition.bookId) {
// 查询对应的小说ID的数据
bookTasks = bookTasks.filtered('bookId = $0', bookTaskCondition.bookId)
}
if (bookTaskCondition.name) {
// 查询对应的小说ID的数据
bookTasks = bookTasks.filtered('name = $0', bookTaskCondition.name)
}
if (bookTaskCondition.no) {
// 查询对应的小说ID的数据
bookTasks = bookTasks.filtered('no = $0', bookTaskCondition.no)
}
let bookTask_length = bookTasks.length
bookTasks = bookTasks.sorted('updateTime', true)
// 判断是不是有page和pageSize有的话对查询返回的信息做分页
if (bookTaskCondition.page && bookTaskCondition.pageSize) {
bookTasks = bookTasks.slice(
(bookTaskCondition.page - 1) * bookTaskCondition.pageSize,
bookTaskCondition.page * bookTaskCondition.pageSize
) as unknown as Realm.Results<BookTaskModel>
}
// 做一下数据转换
// 将realm对象数组转换为普通对象数组
let res_bookTasks = Array.from(bookTasks).map((bookTask) => {
// 这里可以直接操作普通对象
let bookObj = {
...bookTask,
styleList: bookTask.styleList ? Array.from(bookTask.styleList) : [],
generateVideoPath: JoinPath(define.project_path, bookTask.generateVideoPath),
srtPath: JoinPath(define.project_path, bookTask.srtPath),
audioPath: JoinPath(define.project_path, bookTask.audioPath),
imageFolder: JoinPath(define.project_path, bookTask.imageFolder)
}
return bookObj
})
return successMessage(
{
bookTasks: res_bookTasks,
total: bookTask_length
},
'查询小说任务成功',
'BookTaskService_GetBookTaskData'
)
} catch (error) {
throw error
}
}
// 添加一条数据
async AddOrModifyBookTask(bookTask) {
try {
await this.open()
if (bookTask == null) {
throw new Error('添加的小说任务不能为空')
}
if (bookTask.id == null) {
// 新增
if (bookTask.bookId == '' || bookTask.bookId == null) {
throw new Error('小说ID不能为空')
}
bookTask.id = uuidv4()
// 获取当前bookID对应的最大的no
let maxNo = this.realm
.objects('BookTask')
.filtered('bookId = $0', bookTask.bookId)
.max('no')
bookTask.no = maxNo == null ? 1 : Number(maxNo) + 1
bookTask.name = 'output_0000' + bookTask.no
bookTask.status = BookTaskStatus.WAIT
bookTask.updateTime = new Date()
bookTask.createTime = new Date()
this.realm.write(() => {
this.realm.create('BookTask', bookTask)
})
return successMessage(bookTask, '新增小说任务成功', 'BookTaskService_AddOrModifyBookTask')
} else {
// 修改
}
} catch (error) {
throw error
}
}
}

View File

@ -0,0 +1,80 @@
import Realm, { UpdateMode } from 'realm'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { SoftwareModel } from '../../model/SoftWare/software.js'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { BaseSoftWareService } from './softwareBasic.js'
import { isEmpty } from 'lodash'
const { v4: uuidv4 } = require('uuid')
export class LoggerService extends BaseSoftWareService {
static instance: LoggerService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (LoggerService.instance === null) {
LoggerService.instance = new LoggerService()
await super.getInstance()
}
return LoggerService.instance
}
// 添加一条日志信息
async AddLogger(logger) {
try {
await this.open()
// 判断数据是不是存在 bookIdbookTaskIdtypestatuscontent
if (
isEmpty(logger.bookId) ||
isEmpty(logger.bookTaskId) ||
isEmpty(logger.type) ||
isEmpty(logger.status) ||
isEmpty(logger.content)
) {
throw new Error('新增日志信息到数据库失败,数据不完整,缺少必要字段')
}
logger.id = uuidv4()
logger.date = new Date()
this.realm.write(() => {
this.realm.create('Logger', logger)
})
return successMessage(logger, '新增日志信息成功', 'LoggerService_AddLogger')
} catch (error) {
return errorMessage(
'新增日志信息失败,错误信息如下:' + error.toString(),
'LoggerService_AddLogger'
)
}
}
// 删除日志信息 (删除指定日期之前的)
async DeleteLogger(date) {
try {
await this.open()
this.realm.write(() => {
// 删除十五天之前的日志数据
const currentDate = new Date()
currentDate.setDate(currentDate.getDate() - 5)
let logger = this.realm.objects('Logger').filtered('date < $0', currentDate)
this.realm.delete(logger)
})
return successMessage(null, '删除日志信息成功', 'LoggerService_DeleteLogger')
} catch (error) {
return errorMessage(
'删除日志信息失败,错误信息如下:' + error.toString(),
'LoggerService_DeleteLogger'
)
}
}
}

View File

@ -0,0 +1,611 @@
import Realm, { UpdateMode } from 'realm'
import path from 'path'
import { BaseService } from '../baseService'
import { define } from '../../../define.js'
import { SoftwareModel } from '../../model/SoftWare/software.js'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { BaseSoftWareService } from './softwareBasic.js'
import { isEmpty, isNumber } from 'lodash'
const { v4: uuidv4 } = require('uuid')
import { version } from '../../../../../package.json'
export class MJSettingService extends BaseSoftWareService {
static instance: MJSettingService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (MJSettingService.instance === null) {
MJSettingService.instance = new MJSettingService()
await super.getInstance()
}
await MJSettingService.instance.open()
return MJSettingService.instance
}
//#region 览器模式的MJ设置
/**
* MJ设置
* @param browserQuery Id null
*/
GetBrowserMJSetting(browserQuery) {
try {
let browserMjSettings = this.realm.objects('BrowserMJ')
if (browserQuery?.id) {
browserMjSettings = this.realm.objects('BrowserMJ').filtered('id = $0', browserQuery.id)
}
let resBrowserMj = Array.from(browserMjSettings).map((browserMj) => {
return {
...browserMj
}
})
return successMessage(
resBrowserMj,
'获取浏览器配置成功',
'MJSettingService_GetBrowserMJSetting'
)
} catch (error) {
throw error
}
}
/**
* MJ设置
* @param browserMj MJ设置对象
* @returns
*/
AddBrowserMJSetting(browserMj) {
try {
if (isEmpty(browserMj.serviceId) || isEmpty(browserMj.channelId)) {
throw new Error('服务器ID和频道ID必填')
}
if (isEmpty(browserMj.token) || isEmpty(browserMj.userAgent)) {
throw new Error('用户Agent和token必填')
}
browserMj.id = uuidv4()
browserMj.createTime = new Date()
browserMj.updateTime = new Date()
browserMj.version = version
browserMj.userAgentCustom = false
if (this.realm.isInTransaction) {
this.realm.create('BrowserMJ', browserMj)
} else {
this.realm.write(() => {
this.realm.create('BrowserMJ', browserMj)
})
}
return successMessage(
browserMj,
'新增MJ浏览器模式配置成功',
'MJSettingService_AddBrowserMJSetting'
)
} catch (error) {
throw error
}
}
/**
* MJ设置
* @param browserMj
*/
UpdateBrowserMJSetting(browserMj) {
try {
if (isEmpty(browserMj.id)) {
throw new Error('更改浏览器模式配置ID不能为空')
}
if (
isEmpty(browserMj.serviceId) ||
isEmpty(browserMj.channelId) ||
isEmpty(browserMj.token)
) {
throw new Error('更改浏览器配置服务器ID频道IDToken不能为空')
}
// 判断是不是有数据
let browserMjRes = this.realm.objects('BrowserMJ').filtered('id = $0', browserMj.id)
if (browserMjRes.length <= 0) {
throw new Error('没有找到对应的浏览器配置信息')
}
browserMj.updateTime = new Date()
browserMj.version = version
if (this.realm.isInTransaction) {
this.realm.create('BrowserMJ', browserMj, UpdateMode.Modified)
} else {
this.realm.write(() => {
this.realm.create('BrowserMJ', browserMj, UpdateMode.Modified)
})
}
return successMessage(
browserMj,
'修改浏览器模式配置成功',
'MJSettingService_UpdateBrowserMJSetting'
)
} catch (error) {
throw error
}
}
//#endregion
//#region API 模式的相关配置
/**
* API配置信息
* @param apiQuery Id null
* @returns
*/
GetAPIMjSetting(apiQuery) {
try {
let apiMjSettings = this.realm.objects('APIMj')
if (apiQuery?.id) {
apiMjSettings = this.realm.objects('APIMj').filtered('id = $0', apiQuery.id)
}
let resApiMj = Array.from(apiMjSettings).map((apiMj) => {
return {
...apiMj
}
})
return successMessage(resApiMj, '获取API配置成功', 'MJSettingService_GetAPIMjSetting')
} catch (error) {
throw error
}
}
/**
* API模式的配置
* @param apiMj API的配置信息
*/
AddAPIMjSetting(apiMj) {
try {
if (isEmpty(apiMj.mjApiUrl) || isEmpty(apiMj.mjSpeed) || isEmpty(apiMj.apiKey)) {
throw new Error('请求的API URL对应的API Key请求模式这些必填')
}
apiMj.id = uuidv4()
apiMj.createTime = new Date()
apiMj.updateTime = new Date()
apiMj.version = version
if (this.realm.isInTransaction) {
this.realm.create('APIMj', apiMj)
} else {
this.realm.write(() => {
this.realm.create('APIMj', apiMj)
})
}
return successMessage(apiMj, '添加API设置成功', 'MJSettingService_AddAPIMjSetting')
} catch (error) {
throw error
}
}
/**
* APIMJ的配置信息
* @param apiSetting
*/
UpdateAPIMJSetting(apiSetting) {
try {
if (apiSetting.id == null) {
throw new Error('修改API配置数据ID必填')
}
// 判断必填的数据是不是为空
if (
isEmpty(apiSetting.mjApiUrl) ||
isEmpty(apiSetting.mjSpeed) ||
isEmpty(apiSetting.apiKey)
) {
throw new Error('请求的API URL对应的API Key请求模式这些必填')
}
// 判断对应的ID是不是存在
let apiSettingRes = this.realm.objects('APIMj').filtered('id = $0', apiSetting.id)
if (apiSettingRes.length <= 0) {
throw new Error('没有找到对应的API配置信息')
}
apiSetting.updateTime = new Date()
apiSetting.version = version
if (this.realm.isInTransaction) {
this.realm.create('APIMj', apiSetting, UpdateMode.Modified)
} else {
this.realm.write(() => {
this.realm.create('APIMj', apiSetting, UpdateMode.Modified)
})
}
return successMessage(apiSetting, '修改API设置成功', 'MJSettingService_UpdateAPIMJSetting')
} catch (error) {
throw error
}
}
//#endregion
//#region 代理模式的相关配置
/**
*
* @param remoteMjQuery idnull-
*/
GetRemoteMJSettings(remoteMjQuery) {
try {
let remoteMjSettings = this.realm.objects('RemoteMJ')
if (remoteMjQuery?.id) {
remoteMjSettings = this.realm.objects('RemoteMJ').filtered('id = $0', remoteMjQuery.id)
}
let resRemoteMj = Array.from(remoteMjSettings).map((remoteMj) => {
return {
...remoteMj
}
})
return successMessage(
resRemoteMj,
'获取代理模式配置成功',
'MJSettingService_GetRemoteMjSettings'
)
} catch (error) {
throw error
}
}
/**
* API配置
* @param remoteMjSetting API的设置对象
* @returns
*/
AddRemoteMjSetting(remoteMjSetting) {
try {
if (
isEmpty(remoteMjSetting.channelId) ||
isEmpty(remoteMjSetting.guildId) ||
isEmpty(remoteMjSetting.userToken)
) {
throw new Error('代理模式的频道ID服务器ID用户Token必填')
}
let defaultSetting = {
coreSize: 3,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 5,
remark: global.machineId,
remixAutoSubmit: false,
timeoutMinutes: 6,
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
}
// 覆盖
remoteMjSetting = Object.assign(defaultSetting, remoteMjSetting)
remoteMjSetting.id = uuidv4()
remoteMjSetting.createTime = new Date()
remoteMjSetting.updateTime = new Date()
remoteMjSetting.version = version
remoteMjSetting.remark = global.machineId
// 判断当前this.relam 是不是已经处于一个事务中
if (this.realm.isInTransaction) {
this.realm.create('RemoteMJ', remoteMjSetting)
} else {
this.realm.write(() => {
this.realm.create('RemoteMJ', remoteMjSetting)
})
}
return successMessage(
remoteMjSetting,
'新增代理API配置成功',
'MJSettingService_AddRemoteMjSetting'
)
} catch (error) {
throw error
}
}
/**
*
* @param remoteMjSetting
*/
UpdateRemoteMjSetting(remoteMjSetting) {
try {
if (isEmpty(remoteMjSetting.id)) {
throw new Error('更改代理模式配置ID不能为空')
}
if (
isEmpty(remoteMjSetting.channelId) ||
isEmpty(remoteMjSetting.guildId) ||
isEmpty(remoteMjSetting.userToken)
) {
throw new Error('代理模式的账号ID服务ID频道ID用户Token不能为空')
}
if (
remoteMjSetting.coreSize == null ||
remoteMjSetting.queueSize == null ||
remoteMjSetting.timeoutMinutes == null
) {
throw new Error('核心数量,队列数量,超时时间不能为空')
}
let remoteMjSettingRes = this.realm
.objects('RemoteMJ')
.filtered('id = $0', remoteMjSetting.id)
if (remoteMjSettingRes.length <= 0) {
throw new Error('没有找到对应的代理模式配置信息')
}
remoteMjSetting.updateTime = new Date()
remoteMjSetting.version = version
remoteMjSetting.remark = global.machineId
// 判断relam是不是在事务中
if (this.realm.isInTransaction) {
this.realm.create('RemoteMJ', remoteMjSetting, UpdateMode.Modified)
} else {
this.realm.write(() => {
this.realm.create('RemoteMJ', remoteMjSetting, UpdateMode.Modified)
})
}
return successMessage(
remoteMjSetting,
'修改代理API配置成功',
'MJSettingService_UpdateRemoteMjSetting'
)
} catch (error) {
throw error
}
}
//#endregion
//#region MJ设置的基础设置
/**
* MJ的基础配置信息
* @param mjSettingQuery Id null
* @returns
*/
GetMjSetting(mjSettingQuery) {
try {
let mjSettings = this.realm.objects('MjSetting')
if (mjSettingQuery?.id) {
mjSettings = this.realm.objects('MjSetting').filtered('id = $0', mjSettingQuery.id)
}
let resMjSetting = Array.from(mjSettings).map((mjSetting) => {
return {
...mjSetting
}
})
return successMessage(resMjSetting, '获取MJ基础设置成功', 'MJSettingService_getMjSetting')
} catch (error) {
throw error
}
}
/**
* MJ的基础配置到数据库
* @param mjSetting mj基础配置的对象
* @returns
*/
AddMJSetting(mjSetting) {
try {
mjSetting.type = mjSetting.requestModel
// 判断传入的必填数据是不是为空
if (isEmpty(mjSetting.type) || isEmpty(mjSetting.requestModel)) {
throw new Error('MJ设置的类型和请求模型不能为空')
}
if (
isEmpty(mjSetting.imageScale) ||
isEmpty(mjSetting.imageModel) ||
isEmpty(mjSetting.imageSuffix) ||
isEmpty(mjSetting.selectRobot)
) {
throw new Error('MJ设置的图片比例、图片模型、生图后缀、选择机器人不能为空')
}
mjSetting.id = uuidv4()
mjSetting.createTime = new Date()
mjSetting.updateTime = new Date()
mjSetting.version = version
//TODO 还有一些判断条件,后面需要添加,比如选择生图模式,要保存对应的配置数据
if (this.realm.isInTransaction) {
this.realm.create('MjSetting', mjSetting)
} else {
this.realm.write(() => {
this.realm.create('MjSetting', mjSetting)
})
}
// 返回成功信息
return successMessage(mjSetting, '添加MJ设置成功', 'MJSettingService_AddMJSetting')
} catch (error) {
throw error
}
}
/**
* MJ的基础配置信息
* @param mjSetting
*/
UpdateMJSetting(mjSetting) {
try {
// 判断传入的数据中的必填数据是不是为空
if (isEmpty(mjSetting.id)) {
throw new Error('更改MJ基础设置ID不能为空')
}
if (isEmpty(mjSetting.requestModel)) {
throw new Error('MJ设置的请求模型不能为空')
}
mjSetting.type = mjSetting.requestModel
if (
isEmpty(mjSetting.selectRobot) ||
isEmpty(mjSetting.imageScale) ||
isEmpty(mjSetting.imageModel) ||
isEmpty(mjSetting.imageSuffix)
) {
throw new Error('MJ设置的图片比例、图片模型、生图后缀、选择机器人不能为空')
}
if (mjSetting.taskCount == null || mjSetting.spaceTime == null) {
throw new Error('任务数量和间隔时间不能为空')
}
// 判断指定ID的数据是不是存在
let mjSettingRes = this.realm.objects('MjSetting').filtered('id = $0', mjSetting.id)
if (mjSettingRes.length <= 0) {
throw new Error('没有找到对应的MJ配置信息')
}
mjSetting.updateTime = new Date()
mjSetting.version = version
if (this.realm.isInTransaction) {
this.realm.create('MjSetting', mjSetting, UpdateMode.Modified)
} else {
this.realm.write(() => {
this.realm.create('MjSetting', mjSetting, UpdateMode.Modified)
})
}
// 返回成功信息
return successMessage(mjSetting, '修改MJ配置信息成功', 'MJSettingService_UpdateMJSetting')
} catch (error) {
throw error
}
}
//#endregion
//#region 组合操作,组合返回前端的数据信息
/**
* MJ的所有配置信息
*/
GetMJSettingTreeData() {
try {
// 获取MJ的基础配置信息
let mjSettings = this.GetMjSetting(null)
if (mjSettings.data.length <= 0) {
throw new Error('没有找到MJ的配置信息请先添加')
}
// 获取API的配置信息
let apiSettings = this.GetAPIMjSetting(null)
// 获取代理模式的配置信息
let remoteSettings = this.GetRemoteMJSettings(null)
// 获取浏览器模式的配置信息
let browserSettings = this.GetBrowserMJSetting(null)
let mjSetting = mjSettings.data[0]
mjSetting.apiSetting = apiSettings.data.length > 0 ? apiSettings.data[0] : null
mjSetting.remoteSetting = remoteSettings.data.length > 0 ? remoteSettings.data[0] : null
mjSetting.browserSetting = browserSettings.data.length > 0 ? browserSettings.data[0] : null
return successMessage(
mjSetting,
'获取MJ的所有配置信息成功',
'MJSettingService_GetMJSettingTreeData'
)
} catch (error) {
throw error
}
}
/**
*
* @param mjSetting
*/
SaveMJSettingTreeData(mjSetting) {
try {
if (mjSetting == null) {
throw new Error('保存的数据不能为空')
}
// 组合添加数据
this.realm.write(() => {
// 先添加RemoteMJ的数据
let remoteSetting = mjSetting.remoteSetting ? mjSetting.remoteSetting : null
if (remoteSetting != null) {
let remoteSettingRes: { code: number; data: any; message: any }
if (isEmpty(remoteSetting.id)) {
// 新增
remoteSettingRes = this.AddRemoteMjSetting(remoteSetting)
} else {
// 修改
remoteSettingRes = this.UpdateRemoteMjSetting(remoteSetting)
}
if (remoteSettingRes && remoteSettingRes.code == 1) {
mjSetting.remoteSetting = remoteSettingRes.data
}
}
// 判断API设置的数据是不是存在
let apiSetting = mjSetting.apiSetting ? mjSetting.apiSetting : null
if (apiSetting != null) {
let apiSettingRes: { code: number; data: any; message: any }
if (isEmpty(apiSetting.id)) {
// 新增
apiSettingRes = this.AddAPIMjSetting(apiSetting)
} else {
// 修改
apiSettingRes = this.UpdateAPIMJSetting(apiSetting)
}
if (apiSettingRes && apiSettingRes.code == 1) {
mjSetting.apiSetting = apiSettingRes.data
}
}
// 判断浏览器模式的数据是不是存在
let browserSetting = mjSetting.browserSetting ? mjSetting.browserSetting : null
if (browserSetting != null) {
let browserSettingRes: { code: number; data: any; message: any }
if (isEmpty(browserSetting.id)) {
// 新增
browserSettingRes = this.AddBrowserMJSetting(browserSetting)
} else {
// 修改
browserSettingRes = this.UpdateBrowserMJSetting(browserSetting)
}
if (browserSettingRes && browserSettingRes.code == 1) {
mjSetting.browserSetting = browserSettingRes.data
}
}
// 添加MJ的基础配置信息
let mjSettingRes: { code: number; data: any; message: any }
if (isEmpty(mjSetting.id)) {
// 新增
mjSettingRes = this.AddMJSetting(mjSetting)
} else {
// 修改
mjSettingRes = this.UpdateMJSetting(mjSetting)
}
if (mjSettingRes && mjSettingRes.code == 1) {
mjSetting = mjSettingRes.data
}
})
return successMessage(mjSetting, '添加信息成功', 'MJSettingService_SaveMJSettingTreeData')
} catch (error) {
throw error
}
}
//#endregion
}

View File

@ -0,0 +1,133 @@
import Realm from 'realm'
import { BaseService } from '../baseService'
import { define } from '../../../define'
import path from 'path'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum'
import { SoftwareModel } from '../../model/SoftWare/software'
import { LoggerModel } from '../../model/SoftWare/logger'
import {
APIMjModel,
BrowserMJModel,
MjSettingModel,
RemoteMJModel
} from '../../model/SoftWare/mjSetting'
import { MJImageType, MJRobotType } from '../../../enum/mjEnum'
const { v4: uuidv4 } = require('uuid')
let dbPath = path.resolve(define.db_path, 'software.realm')
// 版本迁移
const migration = (oldRealm: Realm, newRealm: Realm) => {
const oldBooks = oldRealm.objects('Software')
const newBooks = newRealm.objects('Software')
if (oldRealm.schemaVersion < 1) {
}
// 第二个版本
if (oldRealm.schemaVersion < 2) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('Software')
for (let software of newSoftwares) {
software.theme = SoftwareThemeType.LIGHT // 为新属性设置默认值
}
})
}
// 第三个版本
if (oldRealm.schemaVersion < 3) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('Software')
for (let software of newSoftwares) {
software.reverse_display_show = false
software.reverse_show_book_striped = false
software.reverse_data_table_size = ComponentSize.SMALL
}
})
}
if (oldRealm.schemaVersion < 6) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('MjSetting')
for (let software of newSoftwares) {
software.requestModel = MJImageType.API_MJ
}
})
}
if (oldRealm.schemaVersion < 8) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('MjSetting')
for (let software of newSoftwares) {
software.imageModel = MJRobotType.MJ
}
})
}
if (oldRealm.schemaVersion < 9) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('MjSetting')
for (let software of newSoftwares) {
software.accountId = null
}
})
}
if (oldRealm.schemaVersion < 10) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('MjSetting')
for (let software of newSoftwares) {
software.accountId = null
}
})
}
}
export class BaseSoftWareService extends BaseService {
static instance: BaseSoftWareService | null = null
protected realm: Realm
dbpath: string
protected constructor() {
super()
this.dbpath = dbPath
}
public static async getInstance() {
if (BaseSoftWareService.instance === null) {
BaseSoftWareService.instance = new BaseSoftWareService()
await BaseSoftWareService.instance.open()
}
return BaseSoftWareService.instance
}
/**
*
* @param dbPath
* @returns
*/
async open() {
try {
if (this.realm != null) return
let config = {
schema: [
SoftwareModel,
LoggerModel,
BrowserMJModel,
RemoteMJModel,
APIMjModel,
MjSettingModel
],
path: dbPath,
schemaVersion: 10, // 当前版本号
migration: migration
}
// 判断当前全局是不是又当前这个
this.realm = await Realm.open(config)
// 判断当前是不是有数据,一条都没有的话添加一条空白数据
if (this.realm.objects('Software').length == 0) {
this.realm.write(() => {
this.realm.create('Software', {
id: uuidv4(),
theme: SoftwareThemeType.LIGHT // 默认是亮色主题
})
})
}
} catch (error) {
console.log(error)
}
}
}

View File

@ -0,0 +1,78 @@
import Realm, { UpdateMode } from 'realm'
import path from 'path'
import { BaseService } from '../baseService.js'
import { define } from '../../../define.js'
import { SoftwareModel } from '../../model/SoftWare/software.js'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
import { successMessage } from '../../../../main/generalTools.js'
import { BaseSoftWareService } from './softwareBasic.js'
const { v4: uuidv4 } = require('uuid')
export class SoftwareService extends BaseSoftWareService {
static instance: SoftwareService | null = null
realm: Realm
private constructor() {
super()
}
/**
*
* @returns
*/
public static async getInstance() {
if (SoftwareService.instance === null) {
SoftwareService.instance = new SoftwareService()
await super.getInstance()
}
return SoftwareService.instance
}
// 修改数据库中行中的某个属性数据
async UpdateSoftware(software) {
try {
await this.open()
this.realm.write(() => {
this.realm.create('Software', software, UpdateMode.Modified)
})
// 返回成功信息
return successMessage(null, '修改软件配置信息成功', 'SoftwareService_UpdateSoftware')
} catch (error) {
throw error
}
}
async AddSfotware(software) {
try {
await this.open()
software.id = uuidv4()
this.realm.write(() => {
this.realm.create('Software', software)
})
} catch (error) {
throw error
}
}
/**
*
*/
async GetSoftwareData() {
try {
await this.open()
let software = this.realm.objects('Software')
return successMessage(
software.toJSON(),
'获取软件配置信息成功',
'SoftwareService_GetSoftwareData'
)
} catch (error) {
global.logger.error(
'SoftwareService_GetSoftwareData',
'获取软件的基础设置失败 ,错误信息如下:' + error.toString()
)
throw error
}
}
}
export default SoftwareService

View File

@ -0,0 +1,36 @@
// 定义抽象基类
import Realm from 'realm'
export abstract class BaseService {
protected realm: Realm | null = null
// 抽象类的构造函数应该是protected以防止外部直接实例化
protected constructor() {
// 构造函数逻辑使用someValue进行初始化
}
// 定义抽象方法,子类必须实现,打开数据库连接
abstract open(dbPath: string): void
// 关闭数据库连接
close(): void {
// 关闭数据库的连接,防止内存溢出
// 实现关闭数据库连接的逻辑
if (this.realm != null) {
console.log('Closing database connection')
this.realm.close()
this.realm = null // 清理引用,确保垃圾回收
}
}
transaction(func: () => unknown): void {
if (this.realm != null) {
// 判断当前的relam是不是在一个事务中
if (this.realm.isInTransaction) {
func()
} else {
this.realm.write(() => {
func()
})
}
}
}
}

View File

@ -13,6 +13,8 @@ if (!app.isPackaged) {
img_base: path.join(__dirname, "../../resources/config/img_base.json"),
video_config: path.join(__dirname, "../../resources/config/video_config.json"),
scripts_path: path.join(__dirname, "../../resources/scripts"),
db_path: path.join(__dirname, "../../resources/scripts/db"),
project_path: path.join(__dirname, "../../project"),
logger_path: path.join(__dirname, "../../resources/logger"),
package_path: path.join(__dirname, "../../resources/package"),
image_path: path.join(__dirname, "../../resources/image"),
@ -44,6 +46,8 @@ if (!app.isPackaged) {
video_config: path.join(__dirname, "../../../resources/config/video_config.json"),
img_base: path.join(__dirname, "../../../resources/config/img_base.json"),
scripts_path: path.join(__dirname, "../../../resources/scripts"),
db_path: path.join(__dirname, "../../../resources/scripts/db"),
project_path: path.join(__dirname, "../../../project"),
logger_path: path.join(__dirname, "../../../resources/logger"),
package_path: path.join(__dirname, "../../../resources/package"),
discordScript: path.join(__dirname, "../../../resources/scripts/discordScript.js"),
@ -67,6 +71,8 @@ if (!app.isPackaged) {
}
}
define["remotemj_api"] = "https://api.laitool.net/"
define["API"] = "f85d39ed5a40fd09966f13f12b6cf0f0"
export {
define
};

View File

@ -189,17 +189,34 @@ export const DEFINE_STRING = {
BATCH_PROCESS_IMAGE: "BATCH_PROCESS_IMAGE",
BATCH_PROCESS_IMAGE_RESULT: "BATCH_PROCESS_IMAGE_RESULT"
},
BOOK: {
GET_BOOK_TYPE: "GET_BOOK_TYPE",
ADD_OR_MODIFY_BOOK: "ADD_OR_MODIFY_BOOK",
GET_BOOK_DATA: "GET_BOOK_DATA",
GET_FRAME_DATA: "GET_FRAME_DATA",
GET_BOOK_TASK_DATA: "GET_BOOK_TASK_DATA"
},
SYSTEM: {
OPEN_FILE: "OPEN_FILE",
RETURN_LOGGER: "RETURN_LOGGER",
},
SETTING: {
GET_DATA_BY_TYPE_AND_PROPERTY: "GET_DATA_BY_TYPE_AND_PROPERTY",
SAVE_DATA_BY_TYPE_AND_PROPERTY: "SAVE_DATA_BY_TYPE_AND_PROPERTY",
DELETE_DATA_BY_TYPE_AND_PROPERTY: "DELETE_DATA_BY_TYPE_AND_PROPERTY",
GET_SOFTWARE_SETTING: "GET_SOFTWARE_SETTING",
SAVE_SOFT_WARE_SETTING: "SAVE_SOFT_WARE_SETTING",
GET_COMPONENT_SIZE: "GET_COMPONENT_SIZE",
GET_MJ_SETTING_TREE_DATA: "GET_MJ_SETTING_TREE_DATA",
SAVE_MJ_SETTING_TREE_DATA: "SAVE_MJ_SETTING_TREE_DATA",
MJ_REMOTE_ACCOUNT_SYNC: "MJ_REMOTE_ACCOUNT_SYNC",
GET_MJ_SETTING: "GET_MJ_SETTING",
UPDATE_MJ_SETTING: "UPDATE_MJ_SETTING"
},
PROMPT: {
GET_SORT_OPTIONS: "GET_SORT_OPTIONS",
SAVE_PROMPT_SORT_DATA: "SAVE_PROMPT_SORT_DATA",
GET_PROMPT_SORT_DATA: "GET_PROMPT_SORT_DATA"
GET_PROMPT_SORT_DATA: "GET_PROMPT_SORT_DATA",
OPEN_PROMPT_FILE_TXT: "OPEN_PROMPT_FILE_TXT"
}
}

154
src/define/enum/bookEnum.ts Normal file
View File

@ -0,0 +1,154 @@
export enum BookType {
// 原创
ORIGINAL = 'original',
// 反推
SD_REVERSE = 'sd_reverse',
// MJ 反推
MJ_REVERSE = 'mj_reverse'
}
export enum MJCategroy {
// 本地MJ
LOCAL_MJ = 'local_mj',
// 代理MJ
REMOTE_MJ = 'remote_mj',
// 浏览器模式
BROWSER_MJ = 'browser_mj',
// API模式
API_MJ = 'api_mj'
}
export enum MJAction {
// 生图
IMAGINE = 'IMAGINE',
// 反推describe
DESCRIBE = 'DESCRIBE'
}
export enum BookBackTaskType {
// 分镜计算
STORYBOARD = 'storyboard',
// 分割视频
SPLIT = 'split',
// 提取音频
AUDIO = 'audio',
// 识别字幕
RECOGNIZE = 'recognize',
// 抽帧
FRAME = 'frame',
// 反推
REVERSE = 'reverse',
// 生成图片
IMAGE = 'image',
// 高清
HD = 'hd',
// 合成视频
COMPOSING = 'composing',
// 推理
INFERENCE = 'inference',
// 翻译
TRANSLATE = 'translate'
}
export enum BookBackTaskStatus {
// 等待
WAIT = 'wait',
// 运行中
RUNNING = 'running',
// 暂停
PAUSE = 'pause',
// 完成
DONE = 'done',
// 失败
FAIL = 'fail'
}
/**
*
*/
export enum BookTaskStatus {
// 等待
WAIT = 'wait',
// 分镜中
STORYBOARD = 'storyboard',
// 分镜失败
STORYBOARD_FAIL = 'storyboard_fail',
// 分镜完成,等待分割视频
STORYBOARD_DONE = 'storyboard_done',
// 分割视频中
SPLIT = 'split',
// 分割视频失败
SPLIT_FAIL = 'split_fail',
// 分割视频完成,等待提取音频
SPLIT_DONE = 'split_done',
// 提取音频中
AUDIO = 'audio',
// 提取音频失败
AUDIO_FAIL = 'audio_fail',
// 提取音频完成,等待识别字幕
AUDIO_DONE = 'audio_done',
// 识别字幕中
RECOGNIZE = 'recognize',
// 识别字幕失败
RECOGNIZE_FAIL = 'recognize_fail',
// 识别字幕完成,等待抽帧
RECOGNIZE_DONE = 'recognize_done',
// 抽帧中
FRAME = 'frame',
// 抽帧完成,等待反推
FRAME_DONE = 'frame_done',
// 抽帧失败
FRAME_FAIL = 'frame_fail',
// 反推中
REVERSE = 'reverse',
// 反推失败
REVERSE_FAIL = 'reverse_fail',
// 反推完成,等待生成图片
REVERSE_DONE = 'reverse_done',
// 生成图片中
IMAGE = 'image',
// 图片生成完成,等待高清
IMAGE_DONE = 'image_done',
// 图片生成失败
IMAGE_FAIL = 'image_fail',
// 高清中
HD = 'hd',
// 高清失败
HD_FAIL = 'hd_fail',
// 高清完成,等待合成视频
HD_DONE = 'hd_done',
// 合成视频中
COMPOSING = 'composing',
// 合成视频完成
COMPOSING_DONE = 'composing_done',
// 合成视频失败
COMPOSING_FAIL = 'composing_fail'
}

21
src/define/enum/mjEnum.ts Normal file
View File

@ -0,0 +1,21 @@
export enum MJImageType {
//本地MJ
LOCAL_MJ = 'local_mj',
// 代理MJ
REMOTE_MJ = 'remote_mj',
// 浏览器模式
BROWSER_MJ = 'browser_mj',
// API模式
API_MJ = 'api_mj'
}
export enum MJRobotType {
// MJ
MJ = 'mj',
// niji
NIJI = 'niji'
}

View File

@ -0,0 +1,42 @@
export enum SoftwareThemeType {
// 暗
DARK = 'dark',
// 亮
LIGHT = 'light'
}
export enum ComponentSize {
// 极小
TINY = 'tiny',
// 小
SMALL = 'small',
// 中
MEDIUM = 'medium',
// 大
LARGE = 'large'
}
export enum LoggerType {
// SD反推
SD_REVERSE = 'sd_reverse',
// 原创
ORIGINAL = 'original',
// MJ反推
MJ_REVERSE = 'mj_reverse'
}
export enum LoggerStatus {
// 成功
SUCCESS = 'success',
// 失败
FAIL = 'fail',
// 进行中
DOING = 'doing'
}
export enum OtherData {
// 未知
UNKNOWN = 'unknown',
//默认
DEFAULT = 'default'
}

View File

@ -6,7 +6,8 @@ export const LOGGER_DEFINE = {
PROMPT: {
GET_PROMPT_SORT_OPTIONS: "获取所有的排序选项",
SAVE_PROMPT_SORT_DATA: "保存提示词排序的数据",
GET_PROMPT_SORT_DATA: "获取提示词排序的数据"
GET_PROMPT_SORT_DATA: "获取提示词排序的数据",
OPEN_PROMPT_FILE_TXT: "获取提示词文件数据"
},
GLOBAL: {

View File

@ -96,9 +96,9 @@ export class MjSetting {
disable: true
},
{
label: "代理MJ待开发",
label: "代理MJtoken",
value: "remote_mj",
disable: true
disable: false
},
{
label: "浏览器模式",

View File

@ -0,0 +1,27 @@
import { ipcMain } from "electron";
import { DEFINE_STRING } from '../../define/define_string'
import { ReverseBook } from "../ReverseManage/Book/ReverseBook";
import { BasicReverse } from "../Task/BasicReverse";
let reverseBook = new ReverseBook();
let basicReverse = new BasicReverse();
export function BookIpc() {
// 获取样式图片的子列表
ipcMain.handle(DEFINE_STRING.BOOK.GET_BOOK_TYPE, async (event) => reverseBook.GetBookType());
// 新增或者是修改小说数据
ipcMain.handle(DEFINE_STRING.BOOK.ADD_OR_MODIFY_BOOK, async (event, book) => reverseBook.AddOrModifyBook(book));
// 获取小说数据(通过传递的参数进行筛选)
ipcMain.handle(DEFINE_STRING.BOOK.GET_BOOK_DATA, async (event, bookQuery) => reverseBook.GetBookData(bookQuery));
//#region 一键反推
ipcMain.handle(DEFINE_STRING.BOOK.GET_BOOK_TASK_DATA, async (event, bookTaskCondition) => reverseBook.GetBookTaskData(bookTaskCondition));
// 获取抽帧数据
ipcMain.handle(DEFINE_STRING.BOOK.GET_FRAME_DATA, async (event, bookId) => basicReverse.GetFrameData(bookId));
//#endregion
}

View File

@ -4,7 +4,7 @@ import {
import { DEFINE_STRING } from '../../define/define_string'
import {
ImageGenerate
} from '../backPrompt/imageGenerate'
} from '../ReverseManage/imageGenerate'
let imageGenerate = new ImageGenerate(global);
function ImageGenerateIpc() {

View File

@ -11,7 +11,8 @@ import { SdIpc } from './sdIpc.js'
import { MainIpc } from './mainIpc.js'
import { GlobalIpc } from "./globalIpc.js";
import { ImageIpc } from "./imageIpc.js";
import { SystemIpc } from "./system.js";
import { SystemIpc } from "./systemIpc.js";
import { BookIpc } from "./bookIpc.js"
export function RegisterIpc(createWindow) {
PromptIpc()
@ -28,5 +29,6 @@ export function RegisterIpc(createWindow) {
GlobalIpc();
ImageIpc();
SystemIpc();
BookIpc();
}

View File

@ -12,6 +12,9 @@ function PromptIpc() {
// 获取已经保存的提示词数据
ipcMain.handle(DEFINE_STRING.PROMPT.GET_PROMPT_SORT_DATA, (event) => prompt.GetPromptSort())
// 获取提示词文件数据txt指定路径
ipcMain.handle(DEFINE_STRING.PROMPT.OPEN_PROMPT_FILE_TXT, (event, value) => prompt.OpenPromptFileTxt(value))
}
export {
PromptIpc

View File

@ -7,6 +7,10 @@ import {
Setting
} from '../setting/setting'
let setting = new Setting(global);
import { BasicSetting } from '../setting/basicSetting';
let basicSetting = new BasicSetting();
import { MJSetting } from '../setting/mjSetting';
let mjSetting = new MJSetting();
async function SettingIpc() {
@ -82,6 +86,36 @@ async function SettingIpc() {
//#endregion
//#region 基础设置
// 获取软件的基础设置(初始的时候执行一次)
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.GET_COMPONENT_SIZE, async (event) => basicSetting.GetComponentSize());
//#endregion
//#region MJ 设置
// 获取MJ基础设置信息
ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING, async (event, value) => mjSetting.GetMJSetting(value));
// 保存MJ的基础设置信息
ipcMain.handle(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, async (event, value) => mjSetting.UpdateMJSetting(value));
// 获取MJ的所有设置
ipcMain.handle(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA, async (event) => mjSetting.GetMJSettingTreeData());
// 保存MJ的所有设置
ipcMain.handle(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, async (event, value) => mjSetting.SaveMJSettingTreeData(value));
// MJ代理模式账号同步
ipcMain.handle(DEFINE_STRING.SETTING.MJ_REMOTE_ACCOUNT_SYNC, async (event) => mjSetting.MjRemoteAccountSync());
//#endregion
}
export {

View File

@ -1,17 +0,0 @@
import { ipcMain } from "electron";
import { DEFINE_STRING } from '../../define/define_string'
const { shell } = require('electron')
function SystemIpc() {
// 打开指定的文件
ipcMain.on(DEFINE_STRING.SYSTEM.OPEN_FILE, async (event, value) => {
await shell.openPath(value);
});
}
export {
SystemIpc
}

View File

@ -0,0 +1,40 @@
import { ipcMain } from "electron";
import { DEFINE_STRING } from '../../define/define_string'
import { CheckFileOrDirExist } from "../../define/Tools/file";
import { errorMessage, successMessage } from "../generalTools";
import path from 'path'
const { shell } = require('electron')
function SystemIpc() {
// 打开指定的文件
ipcMain.on(DEFINE_STRING.SYSTEM.OPEN_FILE, async (event, value) => {
await shell.openPath(value);
});
// 试用文件资源打开指定的文件夹
ipcMain.handle(DEFINE_STRING.OPEN_FOLDER, async (event, value) => {
try {
let openFolder = null
if (value.baseProject) {
openFolder = path.join(global.config.project_path, value.folderPath)
}
else {
openFolder = value.folderPath
}
// 判断文件夹是不是存在
let isExist = await CheckFileOrDirExist(openFolder)
if (!isExist) {
throw new Error("文件夹不存在,请检查")
}
shell.openPath(openFolder)
return successMessage(null, '打开成功');
} catch (error) {
return errorMessage("打开文件夹错误,错误信息如下:" + error.message, "SystemIpc_OPEN_FOLDER")
}
});
}
export {
SystemIpc
}

View File

@ -1,6 +1,6 @@
import { ipcMain } from "electron";
import { DEFINE_STRING } from '../../define/define_string'
import { VideoGenerate } from "../backPrompt/videoGenerate";
import { VideoGenerate } from "../ReverseManage/videoGenerate";
let videoGenerate = new VideoGenerate(global);
function VideoGenerateIpc() {

View File

@ -4,7 +4,7 @@ import {
import { DEFINE_STRING } from '../../define/define_string'
import {
Writing
} from '../backPrompt/writing'
} from '../ReverseManage/writing'
let writing = new Writing(global);
function WritingIpc() {

View File

@ -16,6 +16,8 @@ import { GPT } from "../Public/GPT";
import { TagDefine } from "../../define/tagDefine";
import { cloneDeep } from "lodash";
import { LOGGER_DEFINE } from "../../define/logger_define";
import { MJImageType } from "../../define/enum/mjEnum";
import { MJSettingService } from "../../define/db/service/SoftWare/mjSettingService";
const { v4: uuidv4 } = require('uuid');
/**
@ -226,7 +228,7 @@ export class MJOriginalImageGenerate {
try {
value = JSON.parse(value);
let mjSetting = await this.InitMjSetting();
let request_model = mjSetting.request_model;
let request_model = mjSetting.requestModel;
let result = [];
// 浏览器生图模式
if (request_model == "browser_mj") {
@ -260,7 +262,7 @@ export class MJOriginalImageGenerate {
result = await discordSimple.ExecuteScript(define.discordScript, `GetGeneratedMJImageAndSplit(${JSON.stringify(param)})`);
} else if (request_model == "api_mj") {
let mj_api = await this.InitMJAPIUrl(mjSetting.mj_api_url);
let mj_api = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl);
let once_get_task = mj_api.mj_url.once_get_task;
// 请求
@ -273,10 +275,10 @@ export class MJOriginalImageGenerate {
continue
}
let task_res = await this.discordAPI.GetMJAPITaskByID(element.mj_message.message_id, once_get_task, mjSetting.api_key);
let task_res = await this.discordAPI.GetMJAPITaskByID(element.mj_message.message_id, once_get_task, mjSetting.apiSetting.apiKey);
if (task_res.code == 0) {
task_res["id"] = element.id;
task_res["mj_api_url"] = mjSetting.mj_api_url;
task_res["mj_api_url"] = mjSetting.apiSetting.mjApiUrl;
this.sendChangeMessage()
}
// 判断进度是不是百分百
@ -380,14 +382,31 @@ export class MJOriginalImageGenerate {
* @param {*} element
* @param {*} mjSetting
*/
async MJImagineRequest(element, mjSetting, prompt) {
async MJImagineRequest(element, mjSetting, prompt, tasK_id = null, batch = null) {
try {
// 获取当前的API url
let apiUrl = await this.InitMJAPIUrl(mjSetting.mj_api_url);
if (mjSetting.apiSetting == null) {
throw new Error("没有API设置请先设置API设置");
}
let apiUrl;
if (mjSetting.requestModel == MJImageType.API_MJ) {
// 获取当前的API url
apiUrl = await this.InitMJAPIUrl(mjSetting.apiSetting.mjApiUrl);
} else if (mjSetting.requestModel == MJImageType.REMOTE_MJ) {
apiUrl = {
mj_url: {
imagine: define.remotemj_api + 'mj/submit/imagine',
once_get_task: define.remotemj_api + "mj/task/${id}/fetch"
}
}
} else {
throw new Error("未知的生图模式,请检查配置")
}
let imagine_url = apiUrl.mj_url.imagine;
let once_get_task = apiUrl.mj_url.once_get_task;
let task_count = mjSetting.task_count ? mjSetting.task_count : 3;
let mj_speed = mjSetting.mj_speed ? mjSetting.mj_speed : "relaxed";
let task_count = mjSetting.taskCount ? mjSetting.taskCount : 3;
let mj_speed = mjSetting.apiSetting.mjSpeed ? mjSetting.apiSetting.mjSpeed : "relaxed";
let res;
// 判断当前的API是哪个
if (imagine_url.includes("mjapi.deepwl.net")) {
@ -397,7 +416,7 @@ export class MJOriginalImageGenerate {
mode: mj_speed == "fast" ? "FAST" : "RELAX",
}
let headers = {
"Authorization": mjSetting.api_key
"Authorization": mjSetting.apiSetting.apiKey
}
res = await this.discordAPI.mjApiImagine(imagine_url, data, headers);
@ -408,7 +427,7 @@ export class MJOriginalImageGenerate {
} else if (imagine_url.includes("api.ephone.ai")) {
// ePhoneAPI
let headers = {
"Authorization": mjSetting.api_key
"Authorization": mjSetting.apiSetting.apiKey
}
let data = {
prompt: prompt,
@ -420,15 +439,71 @@ export class MJOriginalImageGenerate {
}
}
res = await this.discordAPI.mjApiImagine(imagine_url, data, headers);
} else if (imagine_url.includes(define.remotemj_api)) {
// 代理模式
let headers = {
"mj-api-secret": define.API
}
// 判断数据是不是存在
if (!mjSetting.remoteSetting.channelId) {
throw new Error("请先设置channelId")
}
if (!mjSetting.remoteSetting.accountId) {
throw new Error("请先同步账号")
}
let data = {
prompt: prompt,
botType: "MID_JOURNEY",
accountFilter: {
channelId: mjSetting.remoteSetting.channelId,
instanceId: mjSetting.remoteSetting.accountId,
remark: this.global.machineId,
modes: [
mj_speed == "fast" ? "FAST" : "RELAX"
]
}
}
res = await this.discordAPI.mjApiImagine(imagine_url, data, headers);
}
this.global.mjGenerateQuene.setCurrentCreateItem(null);
// 错误检查
if (res.code == 23) {
throw new Error("生图队列已满,请稍后尝试");
// 任务队列已满,及结束该任务,然后开始下一个任务,并将该任务重新排序
this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => {
return taskProgress.filter(item => item?.id != element.id)
});
this.sendChangeMessage({
code: 0,
status: "error",
message: "任务队列已满任务结束会重新排序并等待3分钟开始后面的任务",
id: element.id
})
await this.tools.delay(40000);
// 重新将当前任务加入队列
this.global.mjGenerateQuene.enqueue(async () => {
this.global.mjGenerateQuene.setCurrentCreateItem(element)
await this.MJImagineRequest(element, mjSetting, prompt)
}, tasK_id, batch)
this.global.mjGenerateQuene.startNextTask(task_count);
return;
}
if (res.code != 1 && res.code != 22) {
throw new Error("未知错误,可联系管理员排查" + res.description);
// 未知错误,将当前任务删除,开始下一个任务
this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => {
return taskProgress.filter(item => item?.id != element.id)
});
this.global.mjGenerateQuene.startNextTask(task_count);
this.sendChangeMessage({
code: 0,
status: "error",
message: "未知错误,可联系管理员排查," + res.description,
id: element.id
})
return;
}
// 创建成功,开始下一个
this.sendChangeMessage({
@ -440,16 +515,15 @@ export class MJOriginalImageGenerate {
image_show: null,
id: element.id,
progress: 0,
mj_api_url: mjSetting.mj_api_url
mj_api_url: mjSetting.apiSetting.mjApiUrl
});
this.global.mjGenerateQuene.setCurrentCreateItem(null);
// 开始监听当前ID是不是的生图任务完成
// 这边设置一个循环监听,每隔一段时间去请求一次
let timeoutId;
let startInterval = () => {
timeoutId = setTimeout(async () => {
// 执行你的操作
let task_res = await this.discordAPI.GetMJAPITaskByID(res.result, once_get_task, mjSetting.api_key)
let task_res = await this.discordAPI.GetMJAPITaskByID(res.result, once_get_task, mjSetting.apiSetting.apiKey)
console.log(task_res)
// 判断他的状态是不是成功
if (task_res.code == 0) {
@ -479,7 +553,7 @@ export class MJOriginalImageGenerate {
}
}
task_res['id'] = element.id;
task_res["mj_api_url"] = mjSetting.mj_api_url;
task_res["mj_api_url"] = mjSetting.apiSetting.mjApiUrl;
this.sendChangeMessage(task_res);
}, 5000);
}
@ -521,16 +595,19 @@ export class MJOriginalImageGenerate {
let output_crop_00001 = path.join(this.global.config.project_path, `tmp\\output_crop_00001`);
await this.tools.checkFolderExistsOrCreate(output_crop_00001);
// 获取MJ配置
let mjSetting = await this.InitMjSetting();
// 获取MJ配置从数据库中
let _mjSettingService = await MJSettingService.getInstance()
let mjSettings = _mjSettingService.GetMJSettingTreeData();
if (mjSettings.code == 0) {
throw new Error(mjSettings.message)
}
let mjSetting = mjSettings.data;
// 检查this.global中是不是又mj队列没有的话创建一个
if (!this.global.mjGenerateQuene) {
this.global.mjGenerateQuene = new AsyncQueue(this.global, 1, true);
}
let style_ids = await this.pm.GetConfigJson(JSON.stringify(["image_style", []]), false);
// 替换风格的逻辑
let current_task = null;
@ -542,17 +619,25 @@ export class MJOriginalImageGenerate {
// 拼接提示词
// 图生图的链接
// 获取风格词 + 命令后缀
let prompt = old_prompt + (mjSetting.image_suffix ? mjSetting.image_suffix : "");
let prompt = old_prompt + (mjSetting.imageSuffix ? mjSetting.imageSuffix : "");
// 判断当前生图模式
let request_model = mjSetting.request_model
let request_model = mjSetting.requestModel
switch (request_model) {
case "api_mj":
this.global.mjGenerateQuene.enqueue(async () => {
this.global.mjGenerateQuene.setCurrentCreateItem(element)
await this.MJImagineRequest(element, mjSetting, prompt)
await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch)
}, tasK_id, batch)
break;
case MJImageType.REMOTE_MJ:
this.global.mjGenerateQuene.enqueue(async () => {
this.global.mjGenerateQuene.setCurrentCreateItem(element)
await this.MJImagineRequest(element, mjSetting, prompt, tasK_id, batch)
}, tasK_id, batch)
break;
case "browser_mj":
this.global.mjGenerateQuene.enqueue(async () => {
try {
@ -575,7 +660,7 @@ export class MJOriginalImageGenerate {
}
// 判断该当前正在执行的人物队列数(小于设置的数量,开始一个任务)
this.global.mjGenerateQuene.startNextTask(mjSetting.task_count ? mjSetting.task_count : 3);
this.global.mjGenerateQuene.startNextTask(mjSetting.taskCount ? mjSetting.taskCount : 3);
this.global.requestQuene.setBatchCompletionCallback(batch, (failedTasks) => {
if (failedTasks.length > 0) {

View File

@ -1,6 +1,12 @@
import { errorMessage, successMessage } from "../generalTools";
import { LOGGER_DEFINE } from '../../define/logger_define'
import { Setting } from "../setting/setting";
import { isEmpty } from "lodash";
import fs from 'fs';
import readline from 'readline';
import { file } from '../../define/Tools/index'
import path from "path";
let fspromises = fs.promises;
export class Prompt {
constructor() {
@ -79,4 +85,42 @@ export class Prompt {
return errorMessage(error.toString(), LOGGER_DEFINE.PROMPT.GET_PROMPT_SORT_DATA)
}
}
/**
* 获取txt文件的数据将每行导出导致一个数组返回一个数组
* @param {string} value txt文件的地址
*/
async OpenPromptFileTxt(value) {
try {
if (isEmpty(value)) {
throw new Error("传入的文件地址不能为空")
}
// 检查文件是不是存在
if (!file.CheckFileOrDirExist(value)) {
throw new Error("传入的文件地址对应的文件不存在");
}
async function processLineByLine() {
const fileStream = fs.createReadStream(path.normalize(value));
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
const lines = [];
for await (const line of rl) {
lines.push(line);
}
rl.close(); // 确保关闭 readline 流
return lines;
}
let res = await processLineByLine()
// return successMessage(res, "获取数据成功", LOGGER_DEFINE.PROMPT.OPEN_PROMPT_FILE_TXT);
console.log(res);
return successMessage(res, "获取成功", LOGGER_DEFINE.PROMPT.OPEN_PROMPT_FILE_TXT)
} catch (error) {
return errorMessage(error.toString(), LOGGER_DEFINE.PROMPT.OPEN_PROMPT_FILE_TXT);
}
}
}

View File

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

View File

@ -0,0 +1,49 @@
import { successMessage, errorMessage } from "../../generalTools.js";
import { BookBasic } from "./BooKBasic.js";
import BooKService from "../../../define/db/service/Book/bookService";
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
import { define } from '../../../define/define.js'
import path from 'path'
export class ReverseBook extends BookBasic {
constructor() {
super()
}
/**
* 获取当前的小说数据
* @param {*} bookQuery
*/
async GetBookData(bookQuery) {
try {
let _bookService = await BooKService.getInstance();
// 添加小说
let res = await _bookService.GetBookData(bookQuery)
if (res.code == 0) {
throw new Error(res.message)
}
return res
} catch (error) {
return errorMessage(error.message, 'ReverseBook_GetBookData');
}
}
/**
* 获取小说的任务列表
* @param {*} bookTaskCondition 查询任务列表的条件
*/
async GetBookTaskData(bookTaskCondition) {
try {
let _bookTaskService = await BookTaskService.getInstance();
let res = await _bookTaskService.GetBookTaskData(bookTaskCondition)
if (res.code == 0) {
throw new Error(res.message)
}
return res;
} catch (error) {
return errorMessage("获取小说对应批次错误,错误信息入校:" + error.message, 'ReverseBook_GetBookTaskData');
}
}
}

View File

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

View File

View File

View File

@ -0,0 +1,41 @@
import { LoggerService } from '../../define/db/service/SoftWare/loggerService';
import { DEFINE_STRING } from '../../define/define_string';
import { LoggerStatus, OtherData } from '../../define/enum/softwareEnum';
import { successMessage } from '../generalTools';
export class TaskScheduler {
constructor() {
}
/**
* 添加日志到数据库然后返回日志信息到前端日志记录失败不会报错
* @param {*} bookId 小说ID必填
* @param {*} type 日志类型必填 LoggerType
* @param {*} content 日志记录内容必填
* @param {*} bookTaskId 小说子任务选填默认 OtherData.DEFAULT
* @param {*} status 状态选填默认 LoggerStatus.DOING
* @returns
*/
async AddLogToDB(bookId, type, content, bookTaskId = OtherData.DEFAULT, status = LoggerStatus.DOING) {
try {
let log =
{
bookId: bookId,
bookTaskId: bookTaskId,
type: type,
status: status,
content: content
}
let _loggerService = await LoggerService.getInstance();
let res = await _loggerService.AddLogger(log)
// 添加成功之后,将消息推动到前端
global.newWindow[0].win.webContents.send(DEFINE_STRING.SYSTEM.RETURN_LOGGER, successMessage(res))
return res
} catch (error) {
return errorMessage(error.message, 'TaskScheduler_AddLogToDB');
}
}
}

View File

@ -104,7 +104,7 @@ export class DiscordSimple {
async GetInputPosition() {
try {
await this.InitData();
await this.tools.delay(this.mjSetting.space_time ? this.mjSetting.space_time * 1000 : 10000)
await this.tools.delay(this.mjSetting.spaceTime ? this.mjSetting.spaceTime * 1000 : 10000)
let result = await this.ExecuteScript(this.script, 'GetMessageInputPosition()');
this.x = result.mouseX;
this.y = result.mouseY;
@ -654,7 +654,7 @@ export class DiscordSimple {
// 在将当前任务设置为空
global.mjGenerateQuene.setCurrentCreateItem(null);
// 开始下一个任务
global.mjGenerateQuene.startNextTask(this.mjSetting.task_count ? this.mjSetting.task_count : 3);
global.mjGenerateQuene.startNextTask(this.mjSetting.taskCount ? this.mjSetting.taskCount : 3);
}
@ -704,7 +704,7 @@ export class DiscordSimple {
global.mjGenerateQuene.setCurrentCreateItem(null);
}
global.mjGenerateQuene.startNextTask(this.mjSetting.task_count ? this.mjSetting.task_count : 3);
global.mjGenerateQuene.startNextTask(this.mjSetting.taskCount ? this.mjSetting.taskCount : 3);
} catch (error) {
this.sendChangeMessage({

View File

@ -1,6 +1,7 @@
import { DiscordSimple } from "./discordSimple";
import { Tools } from "../tools";
import { define } from "../../define/define";
import { MJSettingService } from "../../define/db/service/SoftWare/mjSettingService";
/**
* discord中的一些公用的方法
@ -15,16 +16,15 @@ export class DiscordWorker {
*/
async InitData() {
if (this.mj_config) return;
// 初始化配置文件,若是没有配置文件,则创建一个配置文件
let mj_config_default = {
serviceID: null,
channelID: null,
authorization: null,
userAgent: null
// 初始化MJ配置
let _mjSettingService = await MJSettingService.getInstance();
let mjSettings = _mjSettingService.GetMJSettingTreeData();
if (mjSettings.code == 0) {
throw new Error(mjSettings.message);
}
// 判断是不是有对应的mj的配置没有的话就返回默认值
let mj_config = await this.tools.getJsonFilePropertyValue(define.img_base, "mj_config", mj_config_default, false);
this.mj_config = mj_config;
let mjSetting = mjSettings.data;
this.mj_config = mjSetting;
}
/**
@ -57,23 +57,26 @@ export class DiscordWorker {
await mainSimple.WaitWindowFinishLoad(discordW);
}
// 切换到指定的界面
// 获取当前配置serverID和channelID是不是当前界面是一样的
// 获取当前配置serverID和channelId是不是当前界面是一样的
await this.InitData();
let url = discordW.webContents.getURL();
const regex = /\/channels\/(\d+)\/(\d+)/;
const match = url.match(regex);
let serviceID = null;
let channelID = null;
let serviceId = null;
let channelId = null;
if (match && match[1] && match[2]) {
serviceID = match[1];
channelID = match[2];
serviceId = match[1];
channelId = match[2];
}
if (!(serviceID && channelID && this.mj_config.serviceID === serviceID && this.mj_config.channelID === channelID)) {
if (!(serviceId &&
channelId &&
this.mj_config.browserSetting.serviceId === serviceId &&
this.mj_config.browserSetting.channelId === channelId)) {
// 重新加载url
// 重新拼接url
await discordW.webContents.loadURL(`https://discord.com/channels/${this.mj_config.serviceID}/${this.mj_config.channelID}`)
await discordW.webContents.loadURL(`https://discord.com/channels/${this.mj_config.browserSetting.serviceId}/${this.mj_config.browserSetting.channelId}`)
// 等待界面加载完毕
}
return discordW;

View File

@ -879,6 +879,7 @@ async function DeleteImageTaskList(value) {
async function GetMachineId() {
try {
let id = await machineId(true);
global.machineId = id;
return {
code: 1,
value: id

View File

@ -13,9 +13,10 @@ import { func } from './func.js'
import { AsyncQueue } from "./quene.js"
import { DEFINE_STRING } from '../define/define_string.js'
import { Tools } from './tools.js'
import { ImageGenerate } from './backPrompt/imageGenerate.js'
import { ImageGenerate } from './ReverseManage/imageGenerate.js'
import { Setting } from './setting/setting.js'
import { has, isEmpty } from 'lodash'
import { AutoSyncMJConfig2210 } from './setting/autoSync.js'
// ipc
import { DiscordIpc, RemoveDiscordIpc } from './IPCEvent/discordIpc.js'
@ -33,7 +34,6 @@ async function InitData(gl) {
gl.config = res;
gl.requestQuene = new AsyncQueue(gl, res.task_number);
gl.fileQueue = new AsyncQueue(gl, 1);
gl.logger = new Logger(define.logger_path);
return res;
}
@ -148,7 +148,9 @@ app.whenReady().then(async () => {
optimizer.watchWindowShortcuts(window)
})
//
global.logger = new Logger(define.logger_path);
// 同步数据
await AutoSyncMJConfig2210();
global.newWindow = [];
mainWindow = createWindow('ShowMessage', null)
@ -399,8 +401,6 @@ ipcMain.handle(DEFINE_STRING.GET_PERMISSION, async (event) => {
}
})
// 试用文件资源打开指定的文件夹
ipcMain.on(DEFINE_STRING.OPEN_FOLDER, (event, value) => shell.openPath(path.join(global.config.project_path, "tmp/" + value)));
// 监听字幕的保存
ipcMain.handle(DEFINE_STRING.SAVE_NEW_WORD, async (event, value) => {

View File

@ -10,7 +10,7 @@ export class Logger {
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(info => `${info.timestamp} [${info.level.toUpperCase()}] [${info.service}] ${info.message}`)
winston.format.printf(info => `${(new Date()).toLocaleString()} [${info.level.toUpperCase()}] [${info.service}] ${info.message}`)
),
transports: [
new DailyRotateFile({

View File

@ -0,0 +1,138 @@
import fs from 'fs';
import { version } from '../../../package.json'
import { define } from '../../define/define';
const fspromises = fs.promises;
import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService';
import { isEmpty } from 'lodash';
import { SoftwareService } from '../../define/db/service/SoftWare/softwareService';
//#region 2.2.10 版本 自动同步数据
/**
* 自动同步MJ配置数据
*/
export async function AutoSyncMJConfig2210() {
try {
// 判断版本
if (version != '2.2.10') {
return
}
// 同步MJ的配置到服务器中
let mjConfigJson = JSON.parse(await fspromises.readFile(define.img_base, 'utf-8'));
// 开始同步APIMJsetting
let _mjSettingService = await MJSettingService.getInstance();
if (!mjConfigJson.mj_config) {
return;
}
// 判断数据库中有没有API数据
let dbApiSetting = _mjSettingService.GetAPIMjSetting(null);
if (dbApiSetting.code == 1 && dbApiSetting.data.length <= 0) {
// 同步API请求配置
if (mjConfigJson.mj_config.mj_api_url &&
mjConfigJson.mj_config.mj_speed &&
mjConfigJson.mj_config.api_key) {
let apiSetting = {
mjApiUrl: mjConfigJson.mj_config.mj_api_url,
mjSpeed: mjConfigJson.mj_config.mj_speed,
apiKey: mjConfigJson.mj_config.api_key
};
let res = _mjSettingService.AddAPIMjSetting(apiSetting);
if (res.code == 1) {
global.logger.info("AutoSyncMJConfig2210", '自动同步MJ API 配置数据成功');
} else {
global.logger.error("AutoSyncMJConfig2210", '自动同步MJ API 配置数据失败,错误信息如下:' + '\n' + res.message);
}
}
}
// 判断数据库中是不是存在浏览器配置数据,不存在同步
let dbBrowserSetting = _mjSettingService.GetBrowserMJSetting(null);
if (dbBrowserSetting.code == 1 && dbBrowserSetting.data.length <= 0) {
// 同步浏览器配置,判断数据是不是存在
if (isEmpty(mjConfigJson.mj_config.serviceID) ||
isEmpty(mjConfigJson.mj_config.channelID) ||
isEmpty(mjConfigJson.mj_config.token) ||
(!mjConfigJson.mj_config.userAgent ||
isEmpty(mjConfigJson.mj_config.userAgent) ||
isEmpty(mjConfigJson.mj_config.userAgent.userAgent))
) {
return;
}
// 开始添加浏览器配置
let browserSetting = {
serviceId: mjConfigJson.mj_config.serviceID,
channelId: mjConfigJson.mj_config.channelID,
token: mjConfigJson.mj_config.token,
userAgent: mjConfigJson.mj_config.userAgent.userAgent
};
let res = _mjSettingService.AddBrowserMJSetting(browserSetting);
if (res.code == 1) {
global.logger.info("AutoSyncMJConfig2210", '自动同步MJ 浏览器配置数据成功');
} else {
global.logger.error("AutoSyncMJConfig2210", '自动同步MJ 浏览器配置数据失败,错误信息如下:' + '\n' + res.message);
}
}
// 判断基础数据,不存在同步
let mjSetting = _mjSettingService.GetMjSetting(null);
if (mjSetting.code == 1 && mjSetting.data.length <= 0) {
//判断数据然后选择同步
if (isEmpty(mjConfigJson.mj_config.request_model) ||
isEmpty(mjConfigJson.mj_config.select_robot) ||
isEmpty(mjConfigJson.mj_config.image_scale) ||
isEmpty(mjConfigJson.mj_config.image_model) ||
isEmpty(mjConfigJson.mj_config.image_suffix)
) {
return;
}
// 开始添加基础配置
let mjSettingData = {
requestModel: mjConfigJson.mj_config.request_model,
selectRobot: mjConfigJson.mj_config.select_robot,
imageScale: mjConfigJson.mj_config.image_scale,
imageModel: mjConfigJson.mj_config.image_model,
imageSuffix: mjConfigJson.mj_config.image_suffix,
taskCount: mjConfigJson.mj_config.task_count ? mjConfigJson.mj_config.task_count : 3,
spaceTime: mjConfigJson.mj_config.space_time ? mjConfigJson.mj_config.space_time : 5,
};
let res = _mjSettingService.AddMJSetting(mjSettingData);
if (res.code == 1) {
global.logger.info("AutoSyncMJConfig2210", '自动同步MJ 基础配置数据成功');
} else {
global.logger.error("AutoSyncMJConfig2210", '自动同步MJ 基础配置数据失败,错误信息如下:' + '\n' + res.message);
}
}
// 初始化默认数据
let _softwareService = await SoftwareService.getInstance();
let softs = await _softwareService.GetSoftwareData(null);
if (softs.code == 1 && softs.data.length <= 0) {
// 添加
let softData = {
theme: "light",
reverse_display_show: false,
reverse_show_book_striped: false,
reverse_data_table_size: "samll",
}
let res = await _softwareService.AddSfotware(softData);
if (res.code == 0) {
throw new Error(res.message)
}
global.logger.info("AutoSyncMJConfig2210", '自动同步软件配置数据成功');
}
return mjConfigJson;
} catch (error) {
// 同步数据不报错,只添加日志
global.logger.error("AutoSyncMJConfig2210", '自动同步MJ配置数据失败错误信息如下' + '\n' + error.toString());
}
}
//#endregion

View File

@ -0,0 +1,67 @@
import SoftwareService from "../../define/db/service/SoftWare/softwareService";
import { ComponentSize } from "../../define/enum/softwareEnum";
import { errorMessage, successMessage } from "../generalTools";
export class BasicSetting {
constructor() {
}
// 初始化数据
async init() {
this.setting = await SoftwareService.getInstance();
}
/**
* 获取修改尺寸的下拉菜单的尺寸
* @returns
*/
GetComponentSize() {
return successMessage([
{
value: ComponentSize.TINY,
key: ComponentSize.TINY,
label: "极小"
}, {
key: ComponentSize.SMALL,
value: ComponentSize.SMALL,
label: "小"
}, {
value: ComponentSize.MEDIUM,
key: ComponentSize.MEDIUM,
label: "中"
}, {
value: ComponentSize.LARGE,
key: ComponentSize.LARGE,
label: "大"
}
], "选择尺寸的下拉菜单消息", 'BasicSetting_GetComponentSize')
}
// 获取基础配置信息
async GetSoftwareSetting() {
try {
await this.init()
let res = await this.setting.GetSoftwareData();
return res;
} catch (error) {
return errorMessage(error.message, 'BasicSetting_GetSoftwareSetting');
}
}
/**
* 修改软件设置的所有的数据直接修改全部的数据
* @param {*} paramms
* @returns
*/
async SaveSoftWareSetting(paramms) {
try {
await this.init()
let res = await this.setting.UpdateSoftware(paramms);
return res;
} catch (error) {
return errorMessage(error.message, 'BasicSetting_SaveSoftWareSetting');
}
}
}

View File

@ -0,0 +1,5 @@
export class BookSetting {
constructor() {
}
}

View File

@ -0,0 +1,155 @@
import axios from 'axios';
import { MJSettingService } from '../../define/db/service/SoftWare/mjSettingService'
import { define } from '../../define/define';
import { errorMessage, successMessage } from '../generalTools';
export class MJSetting {
constructor() {
}
/**
* 获取MJ的基础设置数据
*/
async GetMJSetting(mjSettingQuery) {
try {
let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.GetMjSetting(mjSettingQuery);
return res
} catch (error) {
return errorMessage("获取MJ的基础配置错误错误信息如下" + error.toString(), "MJSetting_GetMJSetting");
}
}
/**
* 保存MJ的基础设置
* @param {*} mjSetting 保存的数据
*/
async UpdateMJSetting(mjSetting) {
try {
let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.UpdateMJSetting(mjSetting);
return res
} catch (error) {
return errorMessage("保存MJ的基础配置错误错误信息如下" + error.toString(), "MJSetting_UpdateMJSetting");
}
}
/**
* 获取MJ配置的所有数据
*/
async GetMJSettingTreeData() {
try {
let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.GetMJSettingTreeData();
return res
} catch (error) {
return errorMessage("获取MJ配置错误详细错误信息如下" + error.toString(), 'MJSetting_GetMJSettingTreeData');
}
}
/**
* 保存MJ设置的所有数据
* @param {*} mjSetting
*/
async SaveMJSettingTreeData(mjSetting) {
try {
let _mjSetting = await MJSettingService.getInstance()
let res = _mjSetting.SaveMJSettingTreeData(mjSetting);
return res
} catch (error) {
return errorMessage("保存MJ配置错误详细错误信息如下" + error.toString(), 'MJSetting_SaveMJSettingTreeData');
}
}
/**
* 同步MJ代理模式账号信息
* @param {*} value
* @returns
*/
async MjRemoteAccountSync() {
try {
// 获取账号数据
let _mjSettingService = await MJSettingService.getInstance()
let remoteMjSettings = _mjSettingService.GetRemoteMJSettings(null);
if (remoteMjSettings.data.length <= 0) {
throw new Error("没有找到保存的数据,请先保存")
}
let remoteMjSetting = remoteMjSettings.data[0]
// 判断是不是同步过就是有没有accountId
// 判断有没有accountId
if (remoteMjSetting.accountId) {
// 查找是不是有
let accountRes = await axios.get(define.remotemj_api + `mj/account/${remoteMjSetting.accountId}/fetch`, {
headers: {
"mj-api-secret": define.API
}
});
console.log(accountRes)
// 没有找到账号信息,重新添加
if (accountRes.status == 200 && accountRes.data == "") {
// 添加账号
// 找不到的话,直接添加账号
let accountRes = await axios.post(define.remotemj_api + `mj/account/create`, remoteMjSetting, {
headers: {
"mj-api-secret": define.API
}
});
console.log(accountRes);
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description);
}
// 添加成功,修改数据,将数据返回
let accountId = accountRes.data.result;
remoteMjSetting.accountId = accountId;
let save_res = _mjSettingService.UpdateRemoteMjSetting(remoteMjSetting);
if (save_res.code != 1) {
throw new Error(save_res.message)
}
return successMessage(remoteMjSetting, "MJ新增账号同步成功", "MJSetting_MjRemoteAccountSync")
} else {
// 能找到的话,要更新一下账号信息,并重连
remoteMjSetting["weight"] = 1
let accountRes = await axios.put(define.remotemj_api + `mj/account/${remoteMjSetting.accountId}/update-reconnect`, remoteMjSetting, {
headers: {
"mj-api-secret": define.API
}
});
console.log(accountRes)
if (accountRes.data.code == 0) {
throw new Error(accountRes.description)
}
return successMessage(remoteMjSetting, "MJ账号同步成功", "MJSetting_MjRemoteAccountSync")
}
} else {
// 没有accountId直接添加
// 添加账号
let accountRes = await axios.post(define.remotemj_api + `mj/account/create`, remoteMjSetting, {
headers: {
"mj-api-secret": define.API
}
});
console.log(accountRes);
if (accountRes.data.code != 1) {
throw new Error(accountRes.data.description);
}
// 添加成功,修改数据,将数据返回
let accountId = accountRes.data.result;
remoteMjSetting.accountId = accountId;
let save_res = _mjSettingService.UpdateRemoteMjSetting(remoteMjSetting);
if (save_res.code != 1) {
throw new Error(save_res.message)
}
return successMessage(remoteMjSetting, "MJ账号同步成功", "MJSetting_MjRemoteAccountSync")
}
} catch (error) {
return errorMessage("MJ代理模式账号同步错误详细错误信息如下" + error.toString(), 'MJSetting_MjRemoteAccountSync');
}
}
}

View File

@ -8,6 +8,7 @@ import { ClipSetting } from "../../define/setting/clipSetting";
import { ImageSetting } from "../../define/setting/imageSetting";
import { DEFINE_STRING } from "../../define/define_string";
import { TagDefine } from "../../define/tagDefine";
import { errorMessage } from "../generalTools";
let tagDefine = new TagDefine(global);
export class Setting {
@ -271,6 +272,8 @@ export class Setting {
let res = await axios.post('http://api.yu-zhile.com/GetMachineStatus', {
machineId: value
})
// let res = await axios.get('http://lapi.laitool.cn/api/Machine/GetMachineStatus?machineId=' + value);
if (res.status != 200) {
throw new Error("请求错误");
}
@ -340,6 +343,5 @@ export class Setting {
return ImageSetting.SaveDefineConfigJsonByProperty(value);
}
//#endregion
}

28
src/preload/book.js Normal file
View File

@ -0,0 +1,28 @@
import { ipcRenderer } from "electron"
import { DEFINE_STRING } from "../define/define_string"
const book = {
// 获取小说操作类型(原创/SD反推/MJ反推
GetBookType: async () => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_BOOK_TYPE),
// 新增或者是修改小说数据
AddOrModifyBook: async (book) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.ADD_OR_MODIFY_BOOK, book),
//#region 一键反推
// 获取小说数据(通过传递的参数进行筛选)
GetBookData: async (bookQuery) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_BOOK_DATA, bookQuery),
// 获取小说的任务列表(批次)
GetBookTaskData: async (bookTaskCondition) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_BOOK_TASK_DATA, bookTaskCondition),
// 获取小说的分镜
GetFrameData: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_FRAME_DATA, bookId),
//#endregion
}
export {
book
}

View File

@ -8,6 +8,7 @@ import { img } from './img.js';
import { system } from './system.js';
import { setting } from './setting.js'
import { prompt } from './prompt.js';
import { book } from './book.js'
// Custom APIs for renderer
let events = [];
@ -378,8 +379,6 @@ const api = {
SaveTrialEndTime: (value) => ipcRenderer.send(DEFINE_STRING.SAVE_TRIAL_END_TIME, value),
// 打开购买GPT地址
openGptBuyUrl: (value) => ipcRenderer.send(DEFINE_STRING.OPEN_GPT_BUY_URL, value),
// 打开指定的文件夹
OpenFolder: (value) => ipcRenderer.send(DEFINE_STRING.OPEN_FOLDER, value),
// 退出软件
QuitApp: () => ipcRenderer.send(DEFINE_STRING.QUIT_APP),
// 获取当前的生图方式包含sd,mj,d3等
@ -413,7 +412,7 @@ const api = {
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
contextBridge.exposeInMainWorld('mj', mj)
@ -423,6 +422,7 @@ if (process.contextIsolated) {
contextBridge.exposeInMainWorld("system", system)
contextBridge.exposeInMainWorld("setting", setting)
contextBridge.exposeInMainWorld("pmpt", prompt)
contextBridge.exposeInMainWorld("book", book)
contextBridge.exposeInMainWorld('darkMode', {
toggle: (value) => ipcRenderer.invoke('dark-mode:toggle', value),
})
@ -439,5 +439,6 @@ if (process.contextIsolated) {
window.system = system;
window.setting = setting;
window.pmpt = prompt;
window.book = book;
}

View File

@ -10,7 +10,10 @@ const prompt = {
SavePromptSort: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.PROMPT.SAVE_PROMPT_SORT_DATA, value)),
// 获取提示词排序数据
GetPromptSort: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.PROMPT.GET_PROMPT_SORT_DATA))
GetPromptSort: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.PROMPT.GET_PROMPT_SORT_DATA)),
// 获取提示词文件数据txt指定路径
OpenPromptFileTxt: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.PROMPT.OPEN_PROMPT_FILE_TXT, value)),
}
export {
prompt

View File

@ -11,6 +11,34 @@ const setting = {
// 删除动态配置的的指定主分类,指定的属性的数据
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),
// 获取软件的基础设置(初始的时候执行一次)
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),
//#region MJ的设置
// 获取MJ的基础设置数据
GetMjSetting: async (value = null) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING, value),
// 保存MJ的基础设置
UpdateMJSetting: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.UPDATE_MJ_SETTING, value),
// 获取MJ的所有设置
GetMJSettingTreeData: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.GET_MJ_SETTING_TREE_DATA),
// 保存MJ的所有设置
SaveMJSettingTreeData: async (value) => await ipcRenderer.invoke(DEFINE_STRING.SETTING.SAVE_MJ_SETTING_TREE_DATA, value),
// MJ代理模式账号同步
MjRemoteAccountSync: async () => await ipcRenderer.invoke(DEFINE_STRING.SETTING.MJ_REMOTE_ACCOUNT_SYNC),
//#endregion
}
export {
setting

View File

@ -5,6 +5,9 @@ import { DEFINE_STRING } from "../define/define_string"
const system = {
// 打开指定的文件
OpenFile: async (value, callback) => callback(ipcRenderer.send(DEFINE_STRING.SYSTEM.OPEN_FILE, value)),
// 打开指定的文件夹
OpenFolder: (value) => ipcRenderer.invoke(DEFINE_STRING.OPEN_FOLDER, value),
}
export {
system

View File

@ -1,5 +1,8 @@
<template>
<n-config-provider :hljs="hljs" :theme="themeData == 'dark' ? darkTheme : null">
<n-config-provider
:hljs="hljs"
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
>
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
@ -21,6 +24,8 @@ import {
darkTheme,
NNotificationProvider
} from 'naive-ui'
import { useSoftwareStore } from '../../stores/software'
hljs.registerLanguage('javascript', javascript)
export default defineComponent({
components: {
@ -30,20 +35,32 @@ export default defineComponent({
NNotificationProvider
},
setup() {
let themeData = ref('')
let softwareStore = useSoftwareStore()
onMounted(() => {
onMounted(async () => {
window.api.getSettingDafultData(async (value) => {
themeData.value = value.theme
await window.darkMode.toggle(value.theme)
})
let software = await window.setting.GetSoftwareSetting()
if (software.code == 0) {
throw new Error('初始化信息错误: ' + software.message)
}
if (software.data == null) {
throw new Error('初始化信息错误: 未获取到数据')
}
debugger
if (software.data.length == 0) {
throw new Error('初始化信息错误: 未获取到数据')
}
softwareStore.softWare = software.data[0]
await window.darkMode.toggle(softwareStore.softWare.theme)
})
return {
javascript,
hljs,
darkTheme,
themeData
softwareStore
}
}
})
@ -51,4 +68,25 @@ export default defineComponent({
<style lang="less">
@import './assets/css/styles.less';
/* Customize the scrollbar */
::-webkit-scrollbar {
width: 2px;
height: 4px;
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #ddd;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #ccc;
}
</style>

View File

@ -1,4 +1,6 @@
body {
min-width: 500px;
min-height: 500px;
display: flex;
flex-direction: column;
font-family:

View File

@ -175,7 +175,6 @@ export default defineComponent({
*/
async function GetVideoFile() {
await window.api.SelectFile(['mp4'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
@ -193,7 +192,7 @@ export default defineComponent({
message.error('选择分镜的视频地址')
return
}
if (
toRaw(frameValue.value)
.video_path.split('.')
@ -216,7 +215,10 @@ export default defineComponent({
}
function openExportFolder() {
window.api.OpenFolder("input_crop")
window.system.OpenFolder({
folderPath: 'tmp/input_crop',
baseProject: true
})
}
return {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
<template>
<div ref="artRef"></div>
</template>
<script>
import Artplayer from 'artplayer'
export default {
data() {
return {
instance: null
}
},
props: {
option: {
type: Object,
required: true
}
},
mounted() {
this.instance = new Artplayer({
...this.option,
container: this.$refs.artRef
})
this.$nextTick(() => {
this.$emit('get-instance', this.instance)
})
},
beforeDestroy() {
if (this.instance && this.instance.destroy) {
this.instance.destroy(false)
}
}
}
</script>

View File

@ -20,7 +20,7 @@
:expand-icon="expandIcon"
/>
</n-layout-sider>
<n-layout-content content-style="padding:30px">
<n-layout-content content-style="padding: 20px 5px 5px 20px; height:100%">
<!-- <Setting></Setting> -->
<router-view></router-view>
</n-layout-content>
@ -45,7 +45,13 @@ import {
NButton
} from 'naive-ui'
import { BookmarkOutline, CaretDownOutline } from '@vicons/ionicons5'
import {
CaretDownOutline,
PaperPlaneOutline,
SettingsOutline,
DuplicateOutline,
GridOutline
} from '@vicons/ionicons5'
import CheckMachineId from '../Components/CheckMachineId.vue'
import axios from 'axios'
import { DEFINE_STRING } from '../../../../define/define_string.js'
@ -77,7 +83,12 @@ export default defineComponent({
function renderMenuIcon(option) {
if (option.key === 'sheep-man') return true
if (option.key === 'food') return null
return h(NIcon, null, { default: () => h(BookmarkOutline) })
if (option.key == 'sdoriginal') return h(NIcon, null, { default: () => h(PaperPlaneOutline) })
if (option.key == 'setting') return h(NIcon, null, { default: () => h(SettingsOutline) })
if (option.key == 'reverse_management')
return h(NIcon, null, { default: () => h(GridOutline) })
if (option.key == 'backward_matrix')
return h(NIcon, null, { default: () => h(DuplicateOutline) })
}
onMounted(async () => {
@ -306,6 +317,21 @@ export default defineComponent({
]
},
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// name: 'reverse_management'
// }
// },
// {
// default: () => ''
// }
// ),
// key: 'reverse_management'
// },
// {
// label: "",
// key: "clip_options",
// children: [
@ -386,7 +412,8 @@ export default defineComponent({
{
to: {
name: 'sd_setting'
}
},
class: 'sd_setting'
},
{ default: () => 'SD设置' }
),

View File

@ -15,66 +15,65 @@
</template>
<script>
import { ref, h, onMounted, defineComponent, toRaw, watch, computed } from "vue";
import { NButton, NCheckbox, NInput, useMessage } from "naive-ui";
import { DEFINE_STRING } from "../../../../../define/define_string";
import { cloneDeep } from "lodash";
import { ref, h, onMounted, defineComponent, toRaw, watch, computed } from 'vue'
import { NButton, NCheckbox, NInput, useMessage } from 'naive-ui'
import { DEFINE_STRING } from '../../../../../define/define_string'
import { cloneDeep } from 'lodash'
export default defineComponent({
components: {
NButton,
NInput,
NCheckbox,
NCheckbox
},
props: ["type", "row", "index", "func"],
props: ['type', 'row', 'index', 'func'],
setup(props) {
let message = useMessage();
let type = ref(props.type);
let row = ref(props.row);
let input_status = ref("default");
let message = useMessage()
let type = ref(props.type)
let row = ref(props.row)
let input_status = ref('default')
//
watch(
() => props.type,
(newVal) => {
type.value = newVal;
type.value = newVal
},
{ deep: true }
);
)
//
watch(
() => props.row,
(newVal) => {
row.value = newVal;
row.value = newVal
},
{ deep: true }
);
)
watch(
() => props.row.mj_message,
(newVal) => {
if (newVal && newVal["hasBadPrompt"]) {
input_status.value = "error";
if (newVal && newVal['hasBadPrompt']) {
input_status.value = 'error'
}
},
{ deep: true }
);
)
onMounted(async () => {
if (row.value["mj_message"]?.hasBadPrompt) {
input_status.value = "error";
if (row.value['mj_message']?.hasBadPrompt) {
input_status.value = 'error'
}
});
})
async function onUpdateChecked(v) {
row.adetailer = v;
row.value.adetailer = v
}
return {
type,
row,
onUpdateChecked,
};
},
});
onUpdateChecked
}
}
})
</script>

View File

@ -28,10 +28,11 @@
</template>
<script>
import { h, defineComponent, onMounted, ref, toRaw, watch } from 'vue'
import { h, defineComponent, onMounted, ref, toRaw, watch, onUnmounted } from 'vue'
import { NButton, NDataTable, useMessage, NInput, NImage, useDialog } from 'naive-ui'
import { v4 as uuidv4 } from 'uuid'
import EditWord from './EditWord.vue'
import { checkStringValueDeleteSuffix } from '../../../../../main/generalTools'
const buttonArr = [
{
title: '下对齐',
@ -39,6 +40,7 @@ const buttonArr = [
color: '#8a2be0'
}
]
import InputDialogContent from './InputDialogContent.vue'
export default defineComponent({
components: {
@ -53,9 +55,10 @@ export default defineComponent({
let maxHeight = props.height - 80
let data = ref(props.initData)
const message = useMessage()
let selectKey = ref([])
let dialog = useDialog()
let selectKey = ref([])
let editWordRef = ref(null)
let wenkeRef = ref(null)
const createColumns = ({ AlignNextWord }) => {
return [
@ -158,18 +161,115 @@ export default defineComponent({
//
function setHeight() {
let div = document.getElementById('import_word_and_srt')
div.style.height = hh + 'px'
}
onMounted(async () => {
setHeight()
// ctrl + alt + w
window.addEventListener('keydown', ImportWenKeSrt)
})
onUnmounted(() => {
window.removeEventListener('keydown', ImportWenKeSrt)
})
/**
* 导入文刻软件里面的srt
*/
async function ImportWenKeSrt(e) {
if (!(e.ctrlKey && e.altKey && e.key == 'k')) {
return
}
let dialogWidth = 400
let dialogHeight = 150
dialog.create({
name: 'importWenkeWord',
title: '导入外部对齐文件',
showIcon: false,
closeOnEsc: false,
content: () =>
h(InputDialogContent, {
ref: wenkeRef,
initData: null,
placeholder: '请导入外部对齐文件'
}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
debugger
console.log(wenkeRef.value.word)
let word = wenkeRef.value.data
if (word == null || word == '') {
message.error('数据为空')
return
}
word = JSON.parse(word)
//
data.value = []
let word_arr = word.rows
let lastId = ''
let end_word = []
for (let i = 0; i < word_arr.length; i++) {
const element = word_arr[i]
// text
let row_text = ''
let start_time = 0
let end_time = 0
let subValue = []
if (element.texts) {
for (let j = 0; j < element.texts.length; j++) {
const text = element.texts[j]
row_text += text.text + ','
if (j == 0) {
start_time = text.start
}
if (j == element.texts.length - 1) {
end_time = text.start + text.duration
}
subValue.push({
id: uuidv4(),
srt_value: text.text,
start_time: text.start / 1000,
end_time: text.start / 1000 + text.duration / 1000
})
}
}
let id = uuidv4()
lastId = id
data.value.push({
no: i + 1,
id: id,
lastId: lastId,
word: checkStringValueDeleteSuffix(row_text, ','),
after_gpt: checkStringValueDeleteSuffix(row_text, ','),
start_time: start_time / 1000,
end_time: end_time / 1000,
timeLimit: `${start_time / 1000} -- ${end_time / 1000}`,
subValue: subValue
})
end_word.push(checkStringValueDeleteSuffix(row_text, ','))
}
//
let local_word = end_word.filter((item) => item != '' && item != null)
await window.api.saveWordTxt(toRaw(local_word), (value) => {
if (value.code == 0) {
message.error('文案写入失败' + value.message)
return
}
})
return true
}
})
}
/**
* 重新计算指定索引值的时间
* @param {data value 值的索引} index
* @param {int} index
*/
function modifyTime(index) {
let s_v = data.value[index].subValue
@ -423,7 +523,6 @@ export default defineComponent({
})
return
} else {
// config
await window.api.OriginalAddWebuiJson(JSON.stringify(data.value), async (value) => {
if (value.code == 0) {
@ -466,7 +565,6 @@ export default defineComponent({
})
await window.api.ImportSrtAndGetTime([toRaw(data.value), srt_path], (value) => {
if (value.code == 0) {
message.error(value.message)
return
@ -552,7 +650,8 @@ export default defineComponent({
SaveCopywritingInformation,
OpenOneDialog,
maxHeight,
hh
hh,
wenkeRef
}
}
})

View File

@ -85,44 +85,33 @@
size="small"
placeholder="请选择"
:options="request_model_options"
v-model:value="mjSetting.request_model"
v-model:value="mjSetting.requestModel"
style="width: 120px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">出图机器人</div>
<n-select
size="small"
placeholder="请选择"
:options="select_robot_options"
v-model:value="mjSetting.select_robot"
style="width: 80px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 100px">
<div style="margin-bottom: 3px">出图速度模式</div>
<n-select
size="small"
placeholder="请选择"
:options="mj_speed_options"
v-model:value="mjSetting.mj_speed"
style="width: 100px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">MJ并发数量</div>
<div style="margin-bottom: 3px">MJ并发</div>
<n-input-number
size="small"
style="width: 80px"
v-model:value="mjSetting.task_count"
v-model:value="mjSetting.taskCount"
:show-button="false"
:min="1"
:max="10"
:max="20"
/>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">间隔时间</div>
<n-input-number
size="small"
style="width: 80px"
v-model:value="mjSetting.spaceTime"
:show-button="false"
:min="1"
:max="30"
/>
</div>
@ -198,13 +187,11 @@ export default defineComponent({
let character_select_model = ref(window.config.character_select_model)
let character_select_model_options = ref([])
let mjSetting = ref({
select_robot: null,
task_count: 1,
request_model: null,
mj_speed: 'relaxed'
selectRobot: null,
taskCount: 3,
spaceTime: 1
})
let request_model_options = ref([])
let select_robot_options = ref([])
let mj_speed_options = ref([])
/**
@ -248,21 +235,19 @@ export default defineComponent({
* 初始化MJ的option
*/
async function InitMjOptions() {
// mj
await window.api.GetDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', false, null]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
//
if (value.data) {
mjSetting.value = value.data
}
}
)
// mj
let res = await window.setting.GetMjSetting()
if (res.code == 0) {
message.error(res.message)
return
}
if (res.data.length <= 0) {
message.error('当前没有MJ配置信息请先配置MJ信息')
return
}
mjSetting.value = Object.assign(mjSetting.value, res.data[0])
await window.mj.GetMJGenerateCategory((value) => {
if (value.code == 0) {
@ -274,16 +259,6 @@ export default defineComponent({
mjSetting.value.request_model = request_model_options.value[0].value
}
})
select_robot_options.value = [
{
label: 'MJ',
value: 'mj'
},
{
label: 'NIJI',
value: 'niji'
}
]
mj_speed_options.value = [
{
@ -348,17 +323,11 @@ export default defineComponent({
}
})
// MJ
await window.api.SaveDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', toRaw(mjSetting.value), false]),
(value) => {
if (value.code == 0) {
message.error(value.message)
return
}
}
)
// MJ
let saveMjRes = await window.setting.UpdateMJSetting(toRaw(mjSetting.value))
if (saveMjRes.code == 0) {
throw new Error(saveMjRes.message)
}
message.success('保存成功')
} catch (error) {
@ -425,7 +394,6 @@ export default defineComponent({
bad_prompt_ref,
mjSetting,
request_model_options,
select_robot_options,
mj_speed_options
}
}

View File

@ -563,7 +563,7 @@ export default defineComponent({
// maxHegiht
async function getMaxHeight() {
let height = window.innerHeight
maxHeight.value = height - 150
maxHeight.value = height - 120
}
//

View File

@ -15,11 +15,12 @@
<script>
import { ref, h, onMounted, defineComponent, onUnmounted, toRaw } from 'vue'
import { NImage, useMessage } from 'naive-ui'
import { NImage, useMessage, useDialog } from 'naive-ui'
import { DEFINE_STRING } from '../../../../define/define_string'
import MenuButton from './MenuButton.vue'
import DataTable from './DataTable.vue'
import { usePromptStore } from '../../../../stores/prompt'
import InputDialogContent from './Components/InputDialogContent.vue'
export default defineComponent({
components: {
@ -28,6 +29,7 @@ export default defineComponent({
MenuButton
},
setup() {
let dialog = useDialog()
let promptStore = usePromptStore()
let message = useMessage()
let data = ref([])
@ -35,9 +37,9 @@ export default defineComponent({
let AnalyzeCharacter = ref('')
let TagTreeData = ref([])
let promptError = true
let wenkeRef = ref(null)
async function InitData() {
//
//
// 稿
@ -125,7 +127,6 @@ export default defineComponent({
* 初始化数据
*/
async function InItPromptSort() {
await window.pmpt.GetPromptSort((value) => {
if (value.code == 0) {
message.error(value.message)
@ -135,10 +136,66 @@ export default defineComponent({
})
}
//
async function ImportWenKePrompt(e) {
if (!(e.ctrlKey && e.altKey && e.key == 'm')) {
return
}
//
window.api.SelectFile(['txt'], async (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
debugger
console.log(value.value)
//
await window.pmpt.OpenPromptFileTxt(value.value, (res) => {
debugger
console.log(res)
if (res.code == 0) {
message.error(res.message)
return
}
//
// data
if (res.data.length > data.value.length) {
dialog.warning({
title: '提示',
content: '导入的数据行数大于当前的数据行数,多余的数据会被删除,是否继续导入?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
debugger
//
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
const element = res.data[i]
//
data.value[i].gpt_prompt = element
}
}
})
} else {
//
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
const element = res.data[i]
//
data.value[i].gpt_prompt = element
}
}
})
})
}
onMounted(async () => {
await InitData()
await InitTags()
await InItPromptSort()
window.addEventListener('keydown', ImportWenKePrompt)
})
onUnmounted(() => {
window.removeEventListener('keydown', ImportWenKePrompt)
})
return {
@ -147,7 +204,8 @@ export default defineComponent({
TagTreeData,
InitData,
InitTags,
tags
tags,
wenkeRef
}
}
})

View File

@ -324,7 +324,7 @@ export default defineComponent({
)
} else if (value == 'resetPrompt') {
//
console.log(data)
await ResetPrompt()
} else if (value == 'resetImage') {
@ -349,7 +349,6 @@ export default defineComponent({
auto_save,
railStyle,
AutoSaveUpdate: (value) => {
auto_save.value = value
window.config.auto_save = value
},

View File

@ -0,0 +1,263 @@
<template>
<div style="margin: 30px 30px 30px 0">
<n-form
ref="bookRef"
:model="data"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<n-form-item label="书名" path="name">
<n-input v-model:value="data.name" placeholder="请输入书名" />
</n-form-item>
<n-form-item label="视频文件" path="oldVideoPath">
<n-input
disabled="true"
v-model:value="data.oldVideoPath"
placeholder="请选择反推的视频文件"
clearable
>
<template #suffix>
<n-button @click="ClearInputData('oldVideoPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button>
</template>
</n-input>
<n-button type="info" @click="SelectMP4File('oldVideoPath')" style="margin-left: 10px"
>选择视频</n-button
>
</n-form-item>
<n-form-item label="小说类型" path="type">
<n-select
v-model:value="data.type"
:disabled="reverseManageStore.selectBook.id != null"
:options="reverseManageStore.bookType"
style="width: 200px"
>
</n-select>
</n-form-item>
<n-form-item label="配音地址" path="audioPath">
<n-input
v-model:value="data.audioPath"
disabled="true"
placeholder="没有选择的话则使用原视频的"
>
<template #suffix>
<n-button @click="ClearInputData('audioPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button> </template
></n-input>
<n-button type="info" @click="SelectMP4File('audioPath')" style="margin-left: 10px"
>选择配音</n-button
>
</n-form-item>
<n-form-item label="SRT地址" path="srtPath">
<n-input
v-model:value="data.srtPath"
disabled="true"
placeholder="没有选择的话则使用原视频的"
>
<template #suffix>
<n-button @click="ClearInputData('srtPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button> </template
></n-input>
<n-button type="info" @click="SelectMP4File('srtPath')" style="margin-left: 10px"
>选择SRT</n-button
>
</n-form-item>
<n-form-item label="小说项目文件夹" path="bookFolderPath">
<n-input
v-model:value="data.bookFolderPath"
disabled="true"
placeholder="不用选择,添加小说自动生成"
>
</n-input>
<n-button type="info" @click="OpenFolder('bookFolderPath')" style="margin-left: 10px"
>打开</n-button
>
</n-form-item>
<n-form-item label="图片输出文件夹" path="imageFolder">
<n-input
v-model:value="data.imageFolder"
disabled="true"
placeholder="不用选择,添加小说自动生成"
>
</n-input>
<n-button type="info" @click="OpenFolder('imageFolder')" style="margin-left: 10px"
>打开</n-button
>
</n-form-item>
<div style="margin-left: 10px; display: flex; justify-content: flex-end">
<n-button type="success" @click="AddOrModifyBook">添加</n-button>
</div>
</n-form>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NForm, NFormItem, NInput, NSelect, NIcon } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage.js'
import { CloseSharp } from '@vicons/ionicons5'
import { cloneDeep } from 'lodash'
export default defineComponent({
components: {
NButton,
NForm,
NFormItem,
NInput,
NSelect,
NIcon,
CloseSharp
},
setup() {
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let bookRef = ref(null)
let data = ref(cloneDeep(reverseManageStore.selectBook))
onMounted(async () => {
//
let res = await reverseManageStore.SetBookType()
if (res.code == 0) {
message.error(res.message)
return
}
})
/**
* 选择 MP4 视频文件
*/
async function SelectMP4File(propertyName) {
let ext = ['mp4']
if (propertyName == 'audioPath') {
ext = ['mp3', 'wav']
} else if (propertyName == 'srtPath') {
ext = ['srt']
}
// MP4
await window.api.SelectFile(ext, (value) => {
debugger
if (value.code == 0) {
message.error(value.message)
return
}
if (value.value == null) {
message.error('没有选中的数据')
return
}
if (propertyName == 'oldVideoPath') {
data.value.oldVideoPath = value.value
} else if (propertyName == 'audioPath') {
data.value.UpdateSelectBook = value.value
} else if (propertyName == 'srtPath') {
data.value.srtPath = value.value
} else {
message.error('没有找到对应的属性')
}
})
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
name: ruleObj('书名必填'),
oldVideoPath: ruleObj('反推的视频文件地址必填'),
type: ruleObj('小说类型必填')
}
/**
* 添加或者是修改数据通过ID判断
*/
async function AddOrModifyBook(e) {
//
e.preventDefault()
bookRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
debugger
let res = await reverseManageStore.SaveSelectBook(toRaw(data.value))
// ID
if (res.code == 0) {
message.error(res.message)
return
}
message.success('添加/修改成功')
data.value = reverseManageStore.selectBook
})
}
//MP4
function ClearInputData(propertyName) {
if (propertyName == 'oldVideoPath') {
reverseManageStore.UpdateSelectBook({ oldVideoPath: null })
} else if (propertyName == 'audioPath') {
reverseManageStore.UpdateSelectBook({ audioPath: null })
} else if (propertyName == 'srtPath') {
reverseManageStore.UpdateSelectBook({ srtPath: null })
} else {
message.error('没有找到对应的属性')
}
}
/**
* 打开指定的文件夹
* @param param
*/
async function OpenFolder(param) {
let res = null
debugger
if (param == 'imageFolder') {
res = await window.system.OpenFolder({
folderPath: data.value.imageFolder,
baseProject: false
})
} else if (param == 'bookFolderPath') {
res = await window.system.OpenFolder({
folderPath: data.value.bookFolderPath,
baseProject: false
})
} else {
message.error('未知的参数')
return
}
if (res.code == 0) {
message.error(res.message)
return
}
}
return {
reverseManageStore,
rules,
ClearInputData,
SelectMP4File,
AddOrModifyBook,
bookRef,
OpenFolder,
data
}
}
})
</script>

View File

@ -0,0 +1,89 @@
<template>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
type="primary"
@click="EditBook"
>编辑</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="info"
>任务</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="warning"
@click="EditBook"
>重置</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
style="margin-left: 5px"
strong
secondary
type="error"
>删除
</n-button>
</template>
<script>
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, useDialog } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import { BookType } from '../../../../../define/enum/bookEnum'
import AddBook from './AddBook.vue'
export default defineComponent({
components: {
NButton
},
props: ['book'],
setup(props) {
let message = useMessage()
let dialog = useDialog()
let book = ref(props.book)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
onMounted(async () => {})
/**
* 编辑小说数据
*/
async function EditBook(e) {
e.stopPropagation()
//
debugger
reverseManageStore.SetSelectBook(toRaw(book.value))
//
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '新增小说',
content: () => h(AddBook),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
return {
book,
reverseManageStore,
softwareStore,
EditBook
}
}
})
</script>

View File

@ -0,0 +1,146 @@
<template>
<div style="display: flex; justify-content: space-between">
<n-button :render-icon="renderIcon" type="info" @click="AddBookDialog">新增</n-button>
<div style="display: flex; justify-content: flex-end; margin-right: 10px; align-items: center">
<n-popover trigger="hover">
<template #trigger>
<n-switch
v-model:value="softwareStore.softWare.reverse_show_book_striped"
@update:value="DataTableStripedUpdate"
/>
</template>
<span>显示斑马纹</span>
</n-popover>
<n-popover trigger="hover">
<template #trigger>
<n-button text style="font-size: 20px; margin-left: 10px">
<n-icon>
<ReloadSharp />
</n-icon>
</n-button>
</template>
<span>刷新数据</span>
</n-popover>
<n-dropdown trigger="click" :options="softwareStore.componentSize" @select="SelectDropdown">
<n-button text style="font-size: 20px; margin-left: 10px; font-weight: bold">
Size</n-button
>
</n-dropdown>
<n-button text style="margin-left: 10px; font-size: 20px" @click="SwitchShowTemp">
<n-icon>
<SwapHorizontalSharp />
</n-icon>
</n-button>
</div>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, h, toRaw, computed } from 'vue'
import { useMessage, NButton, NIcon, useDialog, NPopover, NSwitch, NDropdown } from 'naive-ui'
import { AddSharp, ReloadSharp, ResizeSharp, SwapHorizontalSharp } from '@vicons/ionicons5'
import AddBook from './AddBook.vue'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage.js'
import { BookType } from '../../../../../define/enum/bookEnum'
export default defineComponent({
components: {
NButton,
AddSharp,
NIcon,
ReloadSharp,
NPopover,
NSwitch,
NDropdown,
ResizeSharp,
SwapHorizontalSharp
},
setup() {
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let book = ref(null)
onMounted(async () => {
//
await softwareStore.GetComponentSize()
})
async function SwitchShowTemp() {
//
// 1
softwareStore.softWare.reverse_display_show = !softwareStore.softWare.reverse_display_show
}
//
async function AddBookDialog() {
//
reverseManageStore.SetSelectBook({
name: null,
id: null,
type: BookType.MJ_REVERSE
})
//
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '新增小说',
content: () => h(AddBook),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
/**
* 修改设置
*/
async function DataTableStripedUpdate() {
//
debugger
//
let res = await softwareStore.SaveSoftware()
console.log(res)
if (res.code == 0) {
message.error(res.message)
return
}
}
//
async function SelectDropdown(key) {
debugger
console.log(key)
softwareStore.softWare.reverse_data_table_size = key
//
let res = await softwareStore.SaveSoftware()
if (res.code == 0) {
message.error(res.message)
return
}
message.success('切换成功')
}
return {
SwitchShowTemp,
renderIcon() {
return h(NIcon, null, {
default: () => h(AddSharp, { size: '40', color: 'white' }, {})
})
},
AddBookDialog,
book,
reverseManageStore,
softwareStore,
DataTableStripedUpdate,
SelectDropdown
}
}
})
</script>

View File

@ -0,0 +1,60 @@
<template>
<div>
<n-button strong secondary @click="RetuenMain"> 返回 </n-button>
<n-dropdown trigger="hover" :options="AutoOptions" @select="SelectAutoAction">
<n-button color="#ee7959" @click="AutoAction" style="margin-left: 5px"> 自动开始 </n-button>
</n-dropdown>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NCheckbox, NDropdown } from 'naive-ui'
import { useRouter } from 'vue-router'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
export default defineComponent({
components: {
NButton,
NCheckbox,
NDropdown
},
setup() {
let router = useRouter()
let reverseManageStore = useReverseManageStore()
//
onMounted(async () => {})
//
function RetuenMain() {
router.push('/reverse_management')
}
//
async function AutoAction() {
//
let res_frame = await window.book.GetFrameData(reverseManageStore.selectBook.id)
}
//
async function SelectAutoAction() {}
return {
RetuenMain,
AutoAction,
reverseManageStore,
AutoOptions: [
{
label: '停止任务',
value: 'auto_stop'
},
{
label: '继续任务',
value: 'auto_continue'
}
]
}
}
})
</script>

View File

@ -0,0 +1,18 @@
<template>
<div>ManageBookReverseTable</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage } from 'naive-ui'
export default defineComponent({
components: {},
setup() {
onMounted(async () => {})
return {}
}
})
</script>

View File

@ -0,0 +1,87 @@
<template>
<div class="artplayer-app" style="height: 100%">
<Artplayer @get-instance="getInstance" :option="option" :style="palyarStyle" />
<n-log
style="height: 60%; background-color: #f8f8f8"
ref="logInst"
:log="logger"
:loading="loading"
trim
/>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, nextTick, watchEffect } from 'vue'
import { useMessage, NLog } from 'naive-ui'
import Artplayer from '../../Components/Artplayer.vue'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { DEFINE_STRING } from '../../../../../define/define_string'
export default defineComponent({
components: { Artplayer, NLog },
setup() {
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let option = {
container: '.artplayer-app',
id: reverseManageStore.selectBook.id,
url: reverseManageStore.selectBook.oldVideoPath,
playbackRate: true,
aspectRatio: true,
mutex: true,
setting: true,
hotkey: true,
autoSize: true,
fullscreen: true
}
let palyarStyle = {
width: '300px',
height: '300px',
margin: '0 auto'
}
let logger = ref('')
const logInst = ref(null)
let loading = ref(false)
onMounted(async () => {
//
window.api.setEventListen([DEFINE_STRING.SYSTEM.RETURN_LOGGER], (value) => {
debugger
if (value.code == 0) {
message.error('添加日志输出失败,但是不影响使用')
logger.value += value.message + '\n'
return
}
let temp_logger = value.data
//
let log = `[${temp_logger.type}] [${temp_logger.date.toLocaleString()}] [${
temp_logger.status
}] [${temp_logger.content}]`
logger.value += log + '\n'
})
//
watchEffect(() => {
if (logger.value) {
nextTick(() => {
logInst.value?.scrollTo({ position: 'bottom', silent: true })
})
}
})
})
return {
reverseManageStore,
option,
getInstance(art) {
// console.info(art)
},
palyarStyle,
logger,
logInst,
loading
}
}
})
</script>

View File

@ -0,0 +1,207 @@
<template>
<div style="margin-bottom: 10px">
<ManageBookButton />
</div>
<div style="margin-right: 10px">
<n-data-table
:columns="columns"
:size="softwareStore.softWare.reverse_data_table_size"
:data="data"
:pagination="pagination"
:bordered="false"
:remote="true"
:striped="softwareStore.softWare.reverse_show_book_striped"
:scroll-x="1000"
:row-props="rowProps"
:max-height="maxHeight"
/>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, reactive, computed, h } from 'vue'
import { useMessage, NButton, NDataTable, NTag, NEllipsis } from 'naive-ui'
import ManageBookButton from './Components/ManageBookButton.vue'
import { useSoftwareStore } from '../../../../stores/software'
import { useReverseManageStore } from '../../../../stores/reverseManage.js'
import { BookType } from '../../../../define/enum/bookEnum'
import BookListAction from './Components/BookListAction.vue'
import { useRouter } from 'vue-router'
export default defineComponent({
components: {
NButton,
ManageBookButton,
NDataTable,
NEllipsis
},
setup() {
let message = useMessage()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let data = computed(() => reverseManageStore.GetBookData())
const router = useRouter()
let maxHeight = ref(0)
//
const paginationReactive = (() => {
return reactive({
page: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 20, 50, 100],
onChange: async (page) => {
//
paginationReactive.page = page
await GetBookByCondition()
},
onUpdatePageSize: async (pageSize) => {
paginationReactive.pageSize = pageSize
paginationReactive.page = 1
await GetBookByCondition()
}
})
})()
let pagination = computed(() => {
return paginationReactive
})
async function GetBookByCondition() {
try {
debugger
let res = await reverseManageStore.GetBookDataFromDB({
page: paginationReactive.page,
pageSize: paginationReactive.pageSize
})
if (res.code == 0) {
message.error(res.message)
return
}
let res_count = res.data.book_length / pagination.value.pageSize
if (!Number.isInteger(res_count)) {
res_count = Math.ceil(res_count)
}
pagination.value.pageCount = res_count
//
let bookTask = await reverseManageStore.GetBookTaskDataFromDB({
bookId: reverseManageStore.selectBook.id
})
if (bookTask.code == 0) {
message.error(bookTask.message)
return
}
} catch (error) {
message.error('获取小说数据失败')
}
}
async function InitData() {
try {
//
debugger
await GetBookByCondition()
} catch (error) {
message.error(error.message)
}
}
onMounted(async () => {
await InitData()
getMaxHeight()
//
window.addEventListener('resize', getMaxHeight)
})
// maxHegiht
function getMaxHeight() {
let height = window.innerHeight
maxHeight.value = height - 180
}
const createColumns = () => {
return [
{
title: 'No.',
key: 'no',
width: 50
},
{
title: '小说名',
key: 'name',
render: (row) => {
return h(
'div',
{
style:
'overflow: hidden; max-width : 100px; white-space: nowrap; text-overflow: ellipsis;'
},
{ default: () => row.name }
)
},
width: 100
},
{
title: '类型',
key: 'type',
width: 80,
render: (row) => {
return h(
NTag,
{ type: 'success', size: softwareStore.softWare.reverse_data_table_size },
{
default: () => getTyleLabel(row.type)
}
)
}
},
{
title: '原视频',
key: 'oldVideoPath'
},
{
title: '操作',
key: 'action',
width: 310,
fixed: 'right',
render: (row) => {
return h(BookListAction, { book: row })
}
}
]
}
function getTyleLabel(value) {
if (value == BookType.MJ_REVERSE) {
return 'MJ反推'
} else if (value == BookType.SD_REVERSE) {
return 'SD反推'
} else if (value == BookType.ORIGINAL) {
return '原创'
} else {
return '未知'
}
}
return {
softwareStore,
reverseManageStore,
data,
pagination,
maxHeight,
columns: createColumns(),
rowProps: (row) => {
return {
style: 'cursor: pointer;',
onClick: () => {
debugger
message.info(row.id)
reverseManageStore.selectBook = row
router.push({ name: 'manage_book', params: { id: row.id } })
}
}
}
}
}
})
</script>

View File

@ -0,0 +1,37 @@
<template>
<div style="height: 100%; display: flex; width: 100%; overflow: auto">
<div v-if="true" class="left_container" style="flex: 10; min-width: 600px">
<ManageBookDetailButton />
<ManageBookReverseTable style="margin-top: 10px" />
</div>
<div >
<n-divider vertical style="height: 100%"></n-divider>
</div>
<div class="right_container" style="flex: 3; min-width: 250px">
<ManageBookShowLogger />
</div>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NDivider } from 'naive-ui'
import ManageBookDetailButton from './Components/ManageBookDetailButton.vue'
import ManageBookReverseTable from './Components/ManageBookReverseTable.vue'
import ManageBookShowLogger from './Components/ManageBookShowLogger.vue'
export default defineComponent({
components: {
ManageBookDetailButton,
ManageBookReverseTable,
ManageBookShowLogger,
NDivider
},
setup() {
onMounted(async () => {})
return {}
}
})
</script>

View File

@ -0,0 +1,21 @@
<template>
<div>按钮</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NDataTable } from 'naive-ui'
export default defineComponent({
components: {
NButton,
NDataTable
},
setup() {
onMounted(async () => {})
return {}
}
})
</script>

View File

@ -0,0 +1,48 @@
<template>
<div style="height: 100%">
<ManageBook style="height: 100%" v-if="softwareStore.softWare.reverse_display_show" />
<n-split v-else direction="horizontal" :min="0.4" :max="0.8" :default-size="0.6" height="100%">
<template #1> <ManageBook style="height: 100%" /> </template>
<template #2>
<ManageBookTask style="height: 100%" />
</template>
</n-split>
<n-float-button :right="30" :bottom="30" shape="circle">
<n-badge :value="100" :max="99" :offset="[6, -8]">
<n-icon :size="large">
<Layers />
</n-icon>
</n-badge>
</n-float-button>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, onBeforeMount } from 'vue'
import { useMessage, NSplit, NSpin, NFloatButton, NIcon, NBadge } from 'naive-ui'
import ManageBook from './ManageBook.vue'
import ManageBookTask from './ManageBookTask.vue'
import { useSoftwareStore } from '../../../../stores/software'
import { useReverseManageStore } from '../../../../stores/reverseManage.js'
import { Layers } from '@vicons/ionicons5'
export default defineComponent({
components: { NSplit, ManageBook, ManageBookTask, NSpin, NFloatButton, NIcon, Layers, NBadge },
setup() {
let message = useMessage()
let isShowTask = ref(false)
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
onMounted(() => {})
return {
isShowTask,
softwareStore,
reverseManageStore
}
}
})
</script>

View File

@ -1,153 +1,271 @@
<template>
<n-button type="info" round @click="OpenDiscordWindow">打开登录MJ</n-button>
<n-button type="info" round @click="GetChannelRobots" style="margin-left: 10px"
>获取频道机器人</n-button
>
<n-button type="info" round @click="SaveMjSetting" style="margin-left: 10px">保存MJ配置</n-button>
<n-divider />
<n-form ref="formRef" label-placement="top" :model="mjSetting" :rules="rules">
<div style="display: flex">
<n-form-item label="服务器ID" style="width: 400px" path="serviceID">
<n-input v-model:value="mjSetting.serviceID" placeholder="登录MJ后切换服务器自动获取" />
</n-form-item>
<n-form-item label="频道ID" style="width: 400px; margin-left: 10px" path="channelID">
<n-input v-model:value="mjSetting.channelID" placeholder="登录MJ后切换频道自动获取" />
</n-form-item>
</div>
<!-- <div style="display: flex">
<n-form-item label="MJ机器ID" path="mj.botId">
<n-input v-model:value="mjSetting.mj.botId" placeholder="MJ机器ID" />
</n-form-item>
<n-form-item label="MJ命令ID" style="margin-left: 10px" path="mj.commandId">
<n-input v-model:value="mjSetting.mj.commandId" placeholder="MJ命令ID" />
</n-form-item>
<n-form-item label="MJ命令名称" style="margin-left: 10px" path="mj.commandName">
<n-input v-model:value="mjSetting.mj.commandName" placeholder="MJ命令名称" />
</n-form-item>
<n-form-item label="MJ版本ID" style="margin-left: 10px" path="mj.versionId">
<n-input v-model:value="mjSetting.mj.versionId" placeholder="MJ版本ID" />
</n-form-item>
</div>
<n-spin :show="show" size="large">
<div style="overflow: auto; height: 100%">
<n-card title="基础设置" size="medium" hoverable style="min-width: 850px">
<n-form :model="mjSetting" ref="sampleRef" :rules="sampleRules">
<div style="display: flex; align-items: center">
<n-form-item label="出图模式" style="width: 150px" path="requestModel">
<n-select
:options="request_model_options"
v-model:value="mjSetting.requestModel"
placeholder="请选择出图模式"
></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>
<div style="display: flex">
<n-form-item label="NIJI机器ID" path="niji.botId">
<n-input v-model:value="mjSetting.niji.botId" placeholder="NIJI机器ID" />
</n-form-item>
<n-form-item label="NIJI命令ID" style="margin-left: 10px" path="niji.commandId">
<n-input v-model:value="mjSetting.niji.commandId" placeholder="NIJI命令ID" />
</n-form-item>
<n-form-item label="NIJI命令名称" style="margin-left: 10px" path="niji.commandName">
<n-input v-model:value="mjSetting.niji.commandName" placeholder="NIJI命令名称" />
</n-form-item>
<n-form-item label="NIJI版本ID" style="margin-left: 10px" path="niji.versionId">
<n-input v-model:value="mjSetting.niji.versionId" placeholder="NIJI版本ID" />
</n-form-item>
</div> -->
<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-form-item label="用户token" style="width: 810px" path="token">
<n-input v-model:value="mjSetting.token" placeholder="登录MJ后切换服务器自动获取" />
</n-form-item>
<n-form-item label="用户Agent" style="width: 810px" path="userAgent.userAgent">
<n-input
v-model:value="mjSetting.userAgent.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.userAgent.customize" style="width: 100px">
自定义
</n-checkbox>
</template>
开启自定义需要手动填写userAgent可以填入浏览器的userAgent
</n-tooltip>
</n-form-item>
<div style="display: flex; align-items: center">
<n-form-item label="选择生图机器人" path="select_robot" style="width: 120px">
<n-select
:options="select_robot_options"
v-model:value="mjSetting.select_robot"
@update:value="UpdateSelectRobot"
></n-select>
</n-form-item>
<n-form-item label="机器人模型" style="width: 120px; margin-left: 10px" path="image_scale">
<n-select
placeholder="请选择机器人模型"
:options="image_model_options"
v-model:value="mjSetting.image_model"
></n-select>
</n-form-item>
<n-form-item label="生图尺寸" style="width: 120px; margin-left: 10px" path="image_scale">
<n-select
placeholder="请选择生图尺寸"
:options="image_scale_options"
v-model:value="mjSetting.image_scale"
></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="task_count">
<n-input-number
v-model:value="mjSetting.task_count"
:show-button="false"
placeholder="MJ并发出图数量"
:min="1"
:max="10"
></n-input-number>
</n-form-item>
<n-form-item label="间隔时间(s)" style="width: 100px; margin-left: 10px" path="space_time">
<n-input-number
v-model:value="mjSetting.space_time"
:show-button="false"
placeholder="请输入间隔时间(s)"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<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>
<div style="display: flex">
<n-form-item label="出图模式" style="width: 150px" path="request_model">
<n-select
:options="request_model_options"
v-model:value="mjSetting.request_model"
placeholder="请选择出图模式"
></n-select>
</n-form-item>
<n-form-item label="选择出图的API" style="width: 160px; margin-left: 10px" path="mj_api_url">
<n-select
:options="mj_api_options"
v-model:value="mjSetting.mj_api_url"
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="mj_speed">
<n-select
:options="mj_speed_options"
v-model:value="mjSetting.mj_speed"
placeholder="选择出图速度模式"
/>
</n-form-item>
<n-form-item label="输入API密钥" style="width: 160px; margin-left: 10px" path="mj_speed">
<n-input
type="password"
placeholder="请输入密钥"
v-model:value="mjSetting.api_key"
></n-input>
</n-form-item>
</div>
</n-form>
<template #description> 正在添加或同步MJ账号信息 </template>
</n-spin>
</template>
<script>
import { defineComponent, ref, onMounted, computed, toRaw } from 'vue'
import { defineComponent, ref, onMounted, computed, toRaw, h } from 'vue'
import {
NButton,
useMessage,
useDialog,
NDataTable,
NForm,
NFormItem,
@ -157,11 +275,14 @@ import {
NSelect,
NTooltip,
NIcon,
NInputNumber
NInputNumber,
NCard,
NSpin
} from 'naive-ui'
import { DEFINE_STRING } from '../../../../define/define_string'
import { Reload } from '@vicons/ionicons5'
import { isEmpty, max, min } from 'lodash'
import { MJImageType } from '../../../../define/enum/mjEnum'
export default defineComponent({
components: {
NButton,
@ -175,11 +296,15 @@ export default defineComponent({
NTooltip,
NIcon,
Reload,
NInputNumber
NInputNumber,
NCard,
NSpin
},
setup() {
let message = useMessage()
let formRef = ref(null)
let dialog = useDialog()
let sampleRef = ref(null)
let show = ref(false)
let select_robot_options = ref([
{
label: 'MJ',
@ -203,35 +328,48 @@ export default defineComponent({
])
let mjSetting = ref({
serviceID: null,
channelID: null,
mj: {
botId: null,
commandId: null,
commandName: null,
versionId: null
},
niji: {
botId: null,
commandId: null,
commandName: null,
versionId: null
},
token: null,
userAgent: {
id: null,
imageModel: null,
imageScale: null,
imageSuffix: null,
requestModel: null,
type: null,
selectRobot: null,
spaceTime: 6,
taskCount: 3,
createTime: null,
updateTime: null,
version: null,
remoteSetting: {
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 6,
remark: null, //
remixAutoSubmit: false,
timeoutMinutes: 6,
userAgent: null,
customize: false
userToken: null
},
select_robot: null,
image_scale: null,
image_model: null,
image_suffix: null,
task_count: 3,
space_time: 5,
request_model: null,
mj_api_url: null,
mj_speed: null,
api_key: null
apiSetting: {
id: null,
mjApiUrl: null,
mjSpeed: null,
apiKey: null
},
browserSetting: {
id: null,
serviceId: null,
channelId: null,
mjBotId: null,
nijBotId: null,
token: null,
userAgent: null,
userAgentCustom: false
}
})
let image_scale_options = ref([])
@ -241,42 +379,43 @@ export default defineComponent({
let mj_api_options = ref([])
let image_suffix = computed(() => {
let text = image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_model
return item.value == mjSetting.value.imageModel
})
if (text == -1) {
return
}
let sc = image_scale_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_scale
return item.value == mjSetting.value.imageScale
})
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
mjSetting.value.image_suffix = dd
mjSetting.value.imageSuffix = dd
return dd
})
//
async function InitData() {
// mj
await window.api.GetDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', false, null]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
//
if (value.data) {
mjSetting.value = Object.assign(mjSetting.value, value.data)
if (mjSetting.value.select_robot != 'mj' && mjSetting.value.select_robot != 'niji') {
mjSetting.value.select_robot = null
}
}
}
)
debugger
//
let res = await window.setting.GetMJSettingTreeData()
if (res.code == 0) {
message.error(res.message)
return
}
if (!res.data.apiSetting) {
delete res.data.apiSetting
}
if (!res.data.remoteSetting) {
delete res.data.remoteSetting
}
if (!res.data.browserSetting) {
delete res.data.browserSetting
}
mjSetting.value = Object.assign(mjSetting.value, res.data)
console.log(res)
await window.mj.GetMJImageScale((value) => {
if (value.code == 0) {
@ -284,8 +423,8 @@ export default defineComponent({
return
}
image_scale_options.value = value.data
if (image_scale_options.value.length > 0 && mjSetting.value.image_scale == null) {
mjSetting.value.image_scale = image_scale_options.value[0].value
if (image_scale_options.value.length > 0 && mjSetting.value.imageScale == null) {
mjSetting.value.imageScale = image_scale_options.value[0].value
}
})
@ -296,8 +435,8 @@ export default defineComponent({
}
image_model_options.value = value.data
tmp_image_model_options = value.data
if (image_model_options.value.length > 0 && mjSetting.value.image_model == null) {
mjSetting.value.image_model = image_model_options.value[0].value
if (image_model_options.value.length > 0 && mjSetting.value.imageModel == null) {
mjSetting.value.imageModel = image_model_options.value[0].value
}
})
@ -307,8 +446,8 @@ export default defineComponent({
return
}
request_model_options.value = value.data.filter((item) => !item.disable)
if (request_model_options.value.length > 0 && mjSetting.value.request_model == null) {
mjSetting.value.request_model = request_model_options.value[0].value
if (request_model_options.value.length > 0 && mjSetting.value.requestModel == null) {
mjSetting.value.requestModel = request_model_options.value[0].value
}
})
@ -318,15 +457,16 @@ export default defineComponent({
return
}
mj_api_options.value = value.data.filter((item) => item.mj_url)
if (mj_api_options.value.length > 0 && mjSetting.value.mj_api_url == null) {
mjSetting.value.mj_api_url = mj_api_options.value[0].value
if (mj_api_options.value.length > 0 && mjSetting.value.apiSetting.mjApiUrl == null) {
mjSetting.value.apiSetting.mjApiUrl = mj_api_options.value[0].value
}
})
}
onMounted(async () => {
//
//
window.api.setEventListen([DEFINE_STRING.DISCORD.OPERATE_REFRASH_DISCORD_URL], (value) => {
debugger
if (value.code == 0) {
message.error(value.message)
return
@ -334,12 +474,12 @@ export default defineComponent({
//
console.log(value)
if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.URL) {
mjSetting.value.serviceID = value.data.serviceID
mjSetting.value.channelID = value.data.channelID
mjSetting.value.browserSetting.serviceId = value.data.serviceID
mjSetting.value.browserSetting.channelId = value.data.channelID
} else if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.TOKEN) {
mjSetting.value.token = value.data.authorization
if (!mjSetting.value.userAgent.customize) {
mjSetting.value.userAgent.userAgent = value.data.userAgent
mjSetting.value.browserSetting.token = value.data.authorization
if (!mjSetting.value.browserSetting.userAgentCustom) {
mjSetting.value.browserSetting.userAgent = value.data.userAgent
}
} else {
message.error('未知的数据类型')
@ -348,8 +488,8 @@ export default defineComponent({
await InitData()
if (mjSetting.value.mj_speed == null) {
mjSetting.value.mj_speed = mj_speed_options.value[0].value
if (mjSetting.value.apiSetting.mjSpeed == null) {
mjSetting.value.apiSetting.mjSpeed = mj_speed_options.value[0].value
}
})
@ -365,135 +505,98 @@ export default defineComponent({
})
}
/**
* 获取频道机器人
*/
async function GetChannelRobots() {
// IDIDtokenAgent
if (
isEmpty(mjSetting.value.serviceID) &&
isEmpty(mjSetting.value.channelID) &&
isEmpty(mjSetting.value.token) &&
isEmpty(mjSetting.value.userAgent.userAgent)
) {
message.error('请先填写或获取完整的数据(服务器ID频道ID用户token用户Agent)')
return
}
const headers = {
authorization: mjSetting.value.token
}
await fetch(
`https://discord.com/api/v9/guilds/${mjSetting.value.serviceID}/application-command-index`,
{
method: 'GET',
headers: headers
}
)
.then((response) => response.json())
.then((data) => {
// (nijimj)
// mjniji
if (data.applications && data.application_commands) {
let mj_inedx = data.applications.findIndex((item) => {
return item.name.toLowerCase().startsWith('midjourney')
})
if (mj.index != -1) {
mjSetting.value.mj.botId = data.applications[mj_inedx].id
let f = data.application_commands.find((a) => {
return a.name == 'imagine' && a.application_id == data.applications[mj_inedx].id
})
mjSetting.value.mj.commandId = f?.id
mjSetting.value.mj.commandName = 'imagine'
mjSetting.value.mj.versionId = f?.version
}
let niji_inedx = data.applications.findIndex((item) => {
return item.name.toLowerCase().startsWith('niji')
})
if (mj.index != -1) {
mjSetting.value.niji.botId = data.applications[niji_inedx].id
let f = data.application_commands.find((a) => {
return a.name == 'imagine' && a.application_id == data.applications[niji_inedx].id
})
mjSetting.value.niji.commandId = f?.id
mjSetting.value.niji.commandName = 'imagine'
mjSetting.value.niji.versionId = f?.version
}
}
})
.catch((error) => {
window.api.showGlobalNotificationDialog({
code: 0,
message: '获取频道机器人请求失败,错误信息如下: ' + error.message.toString()
})
return
})
//
let sampleRules = {
imageModel: [{ required: true, message: '请选择机器人模型', trigger: 'blur' }],
imageScale: [{ required: true, message: '请选择生图尺寸', trigger: 'blur' }],
requestModel: [{ required: true, message: '请选择出图模式', trigger: 'blur' }],
selectRobot: [{ required: true, message: '请选择生图机器人', trigger: 'blur' }]
}
/**
* 保存MJ配置
*/
async function SaveMjSetting(e) {
//
debugger
e.preventDefault()
formRef.value?.validate(async (errors) => {
sampleRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
mjSetting.value.image_suffix = image_suffix.value
await window.api.SaveDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', toRaw(mjSetting.value), false]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
message.success(value.message)
mjSetting.value.imageSuffix = image_suffix.value
//
let request_model = mjSetting.value.requestModel
if (request_model == MJImageType.API_MJ) {
// API
if (
mjSetting.value.apiSetting == null ||
mjSetting.value.apiSetting.mjApiUrl == null ||
mjSetting.value.apiSetting.mjSpeed == null ||
mjSetting.value.apiSetting.apiKey == null
) {
message.error('请检查API模式设置的必填字段')
return
}
)
})
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
serviceID: ruleObj('必填服务器ID'),
channelID: ruleObj('必填频道ID'),
'mj.botId': ruleObj('必填MJ机器人ID'),
'mj.commandId': ruleObj('必填MJ命令ID'),
'mj.commandName': ruleObj('必填Mj命令名称'),
'mj.versionId': ruleObj('必填MJ版本ID'),
'niji.botId': ruleObj('必填NIJI机器人ID'),
'niji.commandId': ruleObj('必填NIJI命令ID'),
'niji.commandName': ruleObj('必填NIJI命令名称'),
'niji.versionId': ruleObj('必填NIJI版本ID'),
token: ruleObj('必填用户token'),
'userAgent.userAgent': ruleObj('必填用户Agent'),
select_robot: ruleObj('必填选择生图机器人'),
image_scale: ruleObj('必填生图尺寸'),
image_model: ruleObj('必填机器人模型'),
image_suffix: ruleObj('必填命令后缀'),
task_count: ruleObj('必填生图任务量'),
space_time: ruleObj('必填间隔时间(s)'),
request_model: ruleObj('必填出图模式'),
mj_api_url: ruleObj('必填选择出图的API'),
mj_speed: ruleObj('必填选择出图速度模式')
if (request_model == MJImageType.REMOTE_MJ) {
if (mjSetting.value.remoteSetting == null) {
message.error('请先添加代理模式的配置')
return
}
// if (mjSetting.value.remoteSetting.accountId == null) {
// 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
}
}
if (request_model == MJImageType.BROWSER_MJ) {
//
if (
mjSetting.value.browserSetting == null ||
mjSetting.value.browserSetting.serviceId == null ||
mjSetting.value.browserSetting.channelId == null ||
mjSetting.value.browserSetting.token == null ||
mjSetting.value.browserSetting.userAgent == null
) {
message.error('请检查浏览器模式设置的必填字段')
return
}
}
//
let res = await window.setting.SaveMJSettingTreeData(toRaw(mjSetting.value))
if (res.code == 0) {
window.api.showGlobalMessageDialog({ code: 0, message: res.message })
return
}
mjSetting.value = res.data
//
if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) {
window.api.showGlobalMessageDialog({
code: 1,
message: `数据保存成功,
当前生图模式为代理模式若有修改配置请手动同步账号数据但是不要频繁同步有封号风险 `
})
} else {
window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' })
}
})
}
/**
@ -508,10 +611,10 @@ export default defineComponent({
//
if (
image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_model
return item.value == mjSetting.value.imageModel
}) == -1
) {
mjSetting.value.image_model =
mjSetting.value.imageModel =
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
}
}
@ -520,8 +623,9 @@ export default defineComponent({
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = mj_api_options.value.filter((item) => item.value == mjSetting.value.mj_api_url)
let tmp_gb = mj_api_options.value.filter(
(item) => item.value == mjSetting.value.apiSetting.mjApiUrl
)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
@ -534,14 +638,59 @@ export default defineComponent({
}
}
/**
* 账号同步
*/
async function AccountSync() {
dialog.warning({
title: '警告',
content: () =>
h('div', {}, [
h(
'span',
{},
{
default: () => '同步数据的信息是保存后的数据'
}
),
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账号同步成功可以开始使用')
}
})
}
return {
OpenDiscordWindow,
mjSetting,
select_robot_options,
GetChannelRobots,
SaveMjSetting,
rules,
formRef,
sampleRef,
image_scale_options,
image_model_options,
UpdateSelectRobot,
@ -549,7 +698,10 @@ export default defineComponent({
request_model_options,
mj_api_options,
mj_speed_options,
openGptBuyUrl
openGptBuyUrl,
sampleRules,
AccountSync,
show
}
}
})

View File

@ -198,6 +198,7 @@ import AddGptOption from './Components/AddGptOption.vue'
import { FolderOpenSharp as FolderOpen } from '@vicons/ionicons5'
import AddGptPrompts from './Components/AddGptPrompts.vue'
import { isEmpty } from 'lodash'
import { useSoftwareStore } from '../../../../stores/software'
export default defineComponent({
components: {
@ -216,6 +217,7 @@ export default defineComponent({
},
setup() {
let formRef = ref(null)
let softwareStore = useSoftwareStore()
let message = useMessage()
let formValue = ref({
draft_path: window.config.draft_path,
@ -230,7 +232,7 @@ export default defineComponent({
translation_app_id: window.config.translation_app_id,
translation_secret: window.config.translation_secret,
translation_auto: window.config.translation_auto,
theme: window.config.theme,
theme: softwareStore.softWare.theme,
character_select_model: window.config.character_select_model,
window_wh_bm_remember: window.config.window_wh_bm_remember
})
@ -240,12 +242,10 @@ export default defineComponent({
let character_select_model_options = ref([])
let dialog = useDialog()
let loading = ref(false)
/**
* 加载GPT的配置信息
*/
async function InitGptOptions() {
await window.api.getGptBusinessOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
@ -327,9 +327,9 @@ export default defineComponent({
/**
* 保存配置信息
*/
function handleValidateButtonClick(e) {
async function handleValidateButtonClick(e) {
e.preventDefault()
formRef.value?.validate((errors) => {
formRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
@ -345,6 +345,8 @@ export default defineComponent({
window.api.showGlobalMessageDialog({ code: 0, message: value.message })
}
})
softwareStore.SetSoftware({ theme: formValue.value.theme })
await softwareStore.SaveSoftware()
})
}
@ -368,7 +370,6 @@ export default defineComponent({
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = gpt_options.value.filter((item) => item.value == formValue.value.gpt_business)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
@ -387,7 +388,6 @@ export default defineComponent({
* @param {*} value 主题名称
*/
async function ChangeMode(value) {
console.log(value)
const isDarkMode = await window.darkMode.toggle(value)
}
@ -486,7 +486,8 @@ export default defineComponent({
loading,
SelectProjectFolder,
AddGptPrompt,
character_select_model_options
character_select_model_options,
softwareStore
}
}
})

View File

@ -26,6 +26,8 @@ const routes = [
{ path: "/ShowMessage", name: "ShowMessage", component: () => import('./components/Home/ShowMessage.vue') },
{ path: "/sdoriginal", name: "sdoriginal", component: () => import('./components/Original/MainPage.vue') },
{ path: "/mj_setting", name: "mj_setting", component: () => import('./components/Setting/MJSetting.vue') },
{ path: '/reverse_management', name: "reverse_management", component: () => import('./components/ReverseManage/ReverseManage.vue') },
{ path: '/manage_book/:id', name: "manage_book", component: () => import('./components/ReverseManage/ManageBookDetail.vue') },
]
},
{ path: "/ReDrawImage", component: () => import('./components/Home/ReDrawImageWD.vue'), },

Some files were not shown because too many files have changed in this diff Show More