Laitool v3.0.1-preview.1

This commit is contained in:
2024-08-03 12:46:12 +08:00
parent c8a46d59fb
commit 7312053a20
196 changed files with 19822 additions and 8733 deletions
-3
View File
@@ -1,3 +0,0 @@
import fs from 'node:fs';
const fspromises = fs.promises;
+11
View File
@@ -0,0 +1,11 @@
/**
* 检查字符串中是不是包含中文或者标点符号
* @param str 需要判断的字符串
* @returns 返回的数据,有中文或者标点符号返回true,否则返回false
*/
export function ContainsChineseOrPunctuation(str: string): boolean {
return /[\u4e00-\u9fa5]|[\u3000-\u301e\u2013\u2014\u2018\u2019\u201c\u201d\u2026\u203b\uff08\uff09\uff1a\uff1b\uff1f\uff01\uff0c\u3001\uff0e\u3002\uff1f\uff01\u2018\u2019\u201c\u201d]/.test(
str
)
}
@@ -34,7 +34,7 @@ export async function CheckFolderExistsOrCreate(folderPath) {
* @param {*} subPath
* @returns
*/
export function JoinPath(rootPath, subPath) {
export function JoinPath(rootPath: string, subPath: string): string {
// 判断第二个地址是不是存在,不存在返回null,存在返回拼接后的地址
if (subPath && !isEmpty(subPath)) {
return path.resolve(rootPath, subPath)
@@ -46,8 +46,9 @@ export function JoinPath(rootPath, subPath) {
/**
*
* @param {*} folderPath
* @param {*} isDeleteOut false
*/
export async function DeleteFolderAllFile(folderPath) {
export async function DeleteFolderAllFile(folderPath: string, isDeleteOut: boolean = false): Promise<void> {
try {
let folderIsExist = await CheckFileOrDirExist(folderPath)
if (!folderIsExist) {
@@ -55,17 +56,22 @@ export async function DeleteFolderAllFile(folderPath) {
}
// 开始删除
let files = await fspromises.readdir(folderPath)
files.forEach(async (file) => {
const curPath = path.join(folderPath, file)
if ((await fspromises.stat(curPath)).isDirectory()) {
for (const file of files) {
const curPath = path.join(folderPath, file);
const stat = await fspromises.stat(curPath);
if (stat.isDirectory()) {
// 判断是不是文件夹
await DeleteFolderAllFile(curPath) // 递归删除文件夹内容
fspromises.rmdir(curPath) // 删除空文件夹
await DeleteFolderAllFile(curPath); // 递归删除文件夹内容
await fspromises.rmdir(curPath); // 删除空文件夹
} else {
// 删除文件
fspromises.unlink(curPath)
await fspromises.unlink(curPath);
}
})
}
// 判断是不是要删除最外部的文件夹
if (isDeleteOut) {
await fspromises.rmdir(folderPath)
}
} catch (error) {
throw error
}
@@ -142,7 +148,7 @@ export async function IsDirectory(path) {
* @param {*} source_path /
* @param {*} target_path /
*/
export async function BackupFileOrFolder(source_path, target_path) {
export async function BackupFileOrFolder(source_path: string, target_path: string): Promise<void> {
try {
// 判断父文件夹是否存在,不存在创建
const parent_path = path.dirname(target_path)
@@ -158,7 +164,7 @@ export async function BackupFileOrFolder(source_path, target_path) {
await fspromises.rename(source_path, target_path)
} else {
// 复制文件
await fspromises.copyFile(source, target)
await fspromises.copyFile(source_path, target_path)
}
} catch (error) {
throw new Error(error)
@@ -171,7 +177,7 @@ export async function BackupFileOrFolder(source_path, target_path) {
* @param {*} extensions
* @returns
*/
export async function GetFilesWithExtensions(folderPath, extensions) {
export async function GetFilesWithExtensions(folderPath: string, extensions: string[]): Promise<string[]> {
try {
// 判断当前是不是文件夹
if (!(await IsDirectory(folderPath))) {
@@ -213,3 +219,20 @@ export async function GetFilesWithExtensions(folderPath, extensions) {
throw new Error(error)
}
}
/**
*
* @param filePath
* @returns kb单位
*/
export async function GetFileSize(filePath: string): Promise<number> {
try {
if (!(await CheckFileOrDirExist(filePath))) {
throw new Error("获取文件大小,指定的文件不存在");
}
const stats = await fspromises.stat(filePath);
return stats.size / 1024
} catch (error) {
throw error
}
}
-72
View File
@@ -1,72 +0,0 @@
import sharp from "sharp";
import { CheckFileOrDirExist } from "./file"
/**
* 将指定的图片的尺寸修改,返回修改后的图片数据(base64或buffer)
* @param {*} image_path
* @param {*} width
* @param {*} height
* @param {*} type
* @returns 返回修改后的图片数据(base64或buffer)
*/
export async function ResizeImage(image_path, width, height, type) {
try {
// 检查 type 参数
if (type !== 'base64' && type !== 'buffer') {
throw new Error('type 参数必须是 "base64" 或 "buffer"');
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error("输入的文件地址不是图片文件地址");
}
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error("文件不存在");
}
// 修改图片尺寸
const image = sharp(image_path);
image.resize(width, height);
let data = await image.toBuffer();
if (type === 'base64') {
return data.toString('base64');
} else {
return data;
}
} catch (error) {
throw error;
}
}
/**
* 获取指定图片文件的宽高
* @param {*} image_path 图片文件的路径
* @returns 返回以一个对象,包含width和height属性
*/
export async function GetImageSize(image_path) {
try {
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error("文件不存在");
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error("输入的文件地址不是图片文件地址");
}
// 获取图片的宽高
const metadata = await sharp(image_path).metadata();
return {
width: metadata.width,
height: metadata.height
}
} catch (error) {
throw error;
}
}
+282
View File
@@ -0,0 +1,282 @@
import path from 'path'
import sharp from 'sharp'
import { CheckFileOrDirExist } from './file'
import fs from 'fs'
import https from 'https'
import Compressor from 'compressorjs';
/**
* 将指定的图片的尺寸修改,返回修改后的图片数据(base64或buffer)
* @param {*} image_path
* @param {*} width
* @param {*} height
* @param {*} type
* @returns 返回修改后的图片数据(base64或buffer)
*/
export async function ResizeImage(image_path: string, width: number | sharp.ResizeOptions, height: number, type: string) {
try {
// 检查 type 参数
if (type !== 'base64' && type !== 'buffer') {
throw new Error('type 参数必须是 "base64" 或 "buffer"')
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error('输入的文件地址不是图片文件地址')
}
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error('文件不存在')
}
// 修改图片尺寸
const image = sharp(image_path)
image.resize(width, height)
let data = await image.toBuffer()
if (type === 'base64') {
return data.toString('base64')
} else {
return data
}
} catch (error) {
throw error
}
}
/**
* 获取指定图片文件的宽高
* @param {*} image_path 图片文件的路径
* @returns 返回以一个对象,包含width和height属性
*/
export async function GetImageSize(image_path: string) {
try {
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error('文件不存在')
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error('输入的文件地址不是图片文件地址')
}
// 获取图片的宽高
const metadata = await sharp(image_path).metadata()
return {
width: metadata.width,
height: metadata.height
}
} catch (error) {
throw error
}
}
/**
* 根据文件扩展名获取MIME类型
* @param filePath 文件路径
* @returns MIME类型字符串
*/
export function GetMimeType(filePath: string): string {
const extension = path.extname(filePath).toLowerCase();
const mimeTypes: { [key: string]: string } = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp',
// 添加更多文件类型和对应的MIME类型
};
return mimeTypes[extension] || 'application/octet-stream';
}
/**
* 将本地文件地址或网络图片地址转换为包含MIME类型的base64字符串
* @param url 本地文件路径或网络图片URL
* @returns Promise<string> 返回一个Promise,解析为包含MIME类型的base64字符串
*/
export function GetImageBase64(url: string): Promise<string> {
if (!url) {
return Promise.reject('URL不能为空');
}
if (url.startsWith('http://') || url.startsWith('https://')) {
return new Promise((resolve, reject) => {
https.get(url, (response) => {
const mimeType = response.headers['content-type'] || 'application/octet-stream';
const data: any[] = [];
response.on('data', (chunk) => data.push(chunk));
response.on('end', () => {
const buffer = Buffer.concat(data);
const base64Data = `data:${mimeType};base64,${buffer.toString('base64')}`;
resolve(base64Data);
});
}).on('error', (err) => reject(err));
});
} else {
return new Promise((resolve, reject) => {
fs.readFile(url, (err, data) => {
if (err) {
reject(err);
} else {
const mimeType = GetMimeType(url);
const base64Data = `data:${mimeType};base64,${data.toString('base64')}`;
resolve(base64Data);
}
});
});
}
}
/**
* 压缩图片到指定的大小
* @param file 图片的Blob对象
* @param maxSizeInBytes 最大文件大小,单位字节
* @returns 返回一个Promise,解析为压缩后的Blob对象
*/
export function CompressImageToSize(base64: string, maxSizeInBytes: number): Promise<Blob> {
let mimeType = this.getMimeType(base64);
let byteCharacters = atob(base64.split(',')[1]);
let byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
let byteArray = new Uint8Array(byteNumbers);
let imageBlob = new Blob([byteArray], { type: mimeType });
return new Promise((resolve, reject) => {
const compress = (quality: number) => {
new Compressor(imageBlob as Blob, {
quality,
success(result) {
if (result.size <= maxSizeInBytes || quality <= 0.1) {
resolve(result);
} else {
// 递归降低质量
compress(quality - 0.1);
}
},
error(err) {
reject(err);
},
});
};
// 从较高的质量开始
compress(0.9);
});
}
/**
* 生成图片蒙板
* 将选中的区域涂白,其他区域涂黑(这个颜色可以变)
* @param inputPath 输入的文件路径
* @param outputPath 输出的文件路径
* @param region 范围对象,包含x, y, width, height属性
* @param markColor 标记颜色,默认为黑色 { r: 255, g: 255, b: 255 }
* @param backColor 背景颜色,默认为白色 { r: 0, g: 0, b: 0 }
*/
export async function ProcessImage(inputPath: string,
outputPath: string,
region: { width: any; height: any; x: any; y: any },
markColor: { r: number; g: number; b: number } = { r: 255, g: 255, b: 255 },
backColor: { r: number; g: number; b: number } = { r: 0, g: 0, b: 0 },
): Promise<void> {
try {
// 读取图片并进行处理
const image = sharp(inputPath);
// 获取图片的元数据
const { width, height } = await image.metadata();
// 创建一个新的空白图片,背景为白色
const whiteBackground = await sharp({
create: {
width,
height,
channels: 3, // RGB channels
background: backColor // White color
}
}).png().toBuffer();
// 创建一个黑色的矩形
const blackRegion = await sharp({
create: {
width: region.width,
height: region.height,
channels: 3, // RGB channels
background: markColor // Black color
}
}).png().toBuffer();
// 在白色背景上叠加黑色矩形
await sharp(whiteBackground)
.composite([
{
input: blackRegion,
left: region.x,
top: Math.floor(region.y)
}
])
.toFile(outputPath);
} catch (err) {
throw err;
}
}
/**
* 将图片的base64写到本地文件
* @param base64 base64字符串
* @param outFilePath 写出的文件路径
*/
export async function Base64ToFile(base64: string, outFilePath: string): Promise<void> {
try {
let base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
let dataBuffer = Buffer.from(base64Data, 'base64')
let out_folder = path.dirname(outFilePath)
await this.tools.checkFolderExistsOrCreate(out_folder)
await fs.promises.writeFile(outFilePath, dataBuffer)
// await this.tools.writeArrayToFile(dataBuffer, out_file);
} catch (error) {
throw new Error('将base64转换为文件失败,失败信息如下:' + error.toString())
}
}
/**
* 将图片分割为4份
* @param inputPath 输入的文件路径
* @param reName 重命名的名字,用做新文件名的前缀
* @param outputDir 输出的文件夹路径
* @returns
*/
export async function ImageSplit(inputPath: string, reName: string, outputDir: string) {
try {
const metadata = await sharp(inputPath).metadata()
const smallWidth = metadata.width / 2
const smallHeight = metadata.height / 2
let times = new Date().getTime()
let imgs = []
for (let i = 0; i < 4; i++) {
const xOffset = i % 2 === 0 ? 0 : smallWidth
const yOffset = Math.floor(i / 2) * smallHeight
let out_file = path.join(outputDir, `/${reName}_${times}_${i}.png`)
await sharp(inputPath)
.extract({
left: xOffset,
top: yOffset,
width: smallWidth,
height: smallHeight
})
.resize(smallWidth, smallHeight)
.toFile(out_file)
imgs.push(out_file)
}
return imgs
} catch (err) {
throw err
}
}
@@ -1,9 +1,11 @@
import * as image from './image';
import * as common from './common';
import * as file from './file'
import * as validate from './validate';
export {
image,
common,
file
file,
validate
};
@@ -43,3 +43,12 @@ export function MillisecondsToTimeString(milliseconds) {
timeString = timeString.replace(/(\.\d+)\./g, '$1')
return timeString
}
/**
* Promise
* @param time
* @returns viod
*/
export async function TimeDelay(time: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, time));
}
+15
View File
@@ -0,0 +1,15 @@
/**
* 校验是不是可以进行JSON解析
* @param str 要解析的字符串
* @returns 可以解析返回true,否则返回false
*/
export function ValidateJson(str: string): boolean {
try {
JSON.parse(str);
return true
} catch (e) {
return false;
}
}
-29
View File
@@ -28,35 +28,6 @@ let apiUrl = [
mj_url: null,
buy_url: null
},
{
label: 'DrawAPI(MJ)',
value: '2cabf684-ac48-4733-a427-8c41626f7d8f',
gpt_url: null,
mj_url: {
imagine: 'https://mjapi.deepwl.net/api/mj/submit/imagine',
describe: 'https://mjapi.deepwl.net/api/mj/submit/describe',
update_file: 'https://mjapi.deepwl.net/api/mj/submit/upload-discord-images',
once_get_task: 'https://mjapi.deepwl.net/api/mj/query/task/${id}',
get_task_list: 'https://mjapi.deepwl.net/api/mj/task/list-by-condition'
},
d3_url: null,
buy_url: 'https://mjapi.deepwl.net/#/home'
},
{
label: 'ePhoneAPI',
value: 'b8866543-8c27-4888-869c-00aa1eb31272',
gpt_url: 'https://api.ephone.ai/v1/chat/completions',
mj_url: {
imagine: 'https://api.ephone.ai/mj/submit/imagine',
describe: 'https://api.ephone.ai/mj/submit/describe',
update_file: 'https://api.ephone.ai/mj/submit/upload-discord-images',
once_get_task: 'https://api.ephone.ai/mj/task/${id}/fetch'
},
d3_url: {
image: 'https://api.ephone.ai/v1/images/generations'
},
buy_url: 'https://ephone.ai/register?aff=55XT'
},
{
label: 'KIMI',
value: 'b5c8c8c5-f3c4-4c88-b25c-7f5a3d5f9d1f',
@@ -13,6 +13,8 @@ export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
executeType: TaskExecuteType // 任务执行类型,手动还是自动
createTime: Date
updateTime: Date
startTime: number
endTime: number
static schema: ObjectSchema = {
name: 'BookBackTaskList',
@@ -27,7 +29,9 @@ export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
errorMessage: 'string?',
executeType: { type: 'string', default: TaskExecuteType.AUTO },
createTime: 'date',
updateTime: 'date'
updateTime: 'date',
startTime: 'int',
endTime: 'int'
},
primaryKey: 'id'
}
+21 -2
View File
@@ -1,4 +1,5 @@
import Realm, { ObjectSchema } from 'realm'
// @ts-ignore
import Realm from 'realm'
import { BookType } from '../../../enum/bookEnum'
export class BookModel extends Realm.Object<BookModel> {
@@ -11,12 +12,21 @@ export class BookModel extends Realm.Object<BookModel> {
oldVideoPath: string | null
srtPath: string | null
audioPath: string | null
draftSrtStyle: string | null // 草稿字幕样式
backgroundMusic: string | null // 背景音乐ID
friendlyReminder: string | null // 友情提示
updateTime: Date
createTime: Date
version: string
imageStyle: string[] | null // 软件内置的样式
autoAnalyzeCharacter: string | null // 自动分析角色设置
customizeImageStyle: string[] | null // 自定义的样式
videoConfig: string | null // 合成视频设置
prefixPrompt: string | null // 前缀
suffixPrompt: string | null // 后缀
subtitlePosition: string | null
static schema: ObjectSchema = {
static schema: Realm.ObjectSchema = {
name: 'Book',
properties: {
id: 'string',
@@ -27,10 +37,19 @@ export class BookModel extends Realm.Object<BookModel> {
oldVideoPath: 'string?',
srtPath: 'string?',
audioPath: 'string?',
draftSrtStyle : 'string?',
backgroundMusic: 'string?',
friendlyReminder: 'string?',
imageFolder: 'string?',
updateTime: 'date',
createTime: 'date',
version: 'string',
imageStyle: 'string?[]',
autoAnalyzeCharacter: 'string?',
customizeImageStyle: 'string?[]',
videoConfig: "string?",
prefixPrompt: "string?",
suffixPrompt: "string?",
subtitlePosition: 'string?'
},
// 主键为_id
+60 -6
View File
@@ -1,5 +1,40 @@
import Realm, { ObjectSchema } from 'realm'
import { BookTaskStatus, BookType } from '../../../enum/bookEnum'
import { BookImageCategory, BookTaskStatus, BookType } from '../../../enum/bookEnum'
export class ImageDefineModel extends Realm.Object<ImageDefineModel> {
label: string
key: string
value: string
children: string
type: string
prompt: string
image_url: string
cref_cw: number
lora: string
chinese_prompt: string
lora_weight: number
show_image: string
isShow: true
static schema: ObjectSchema = {
name: 'ImageDefine',
properties: {
label: 'string',
key: 'string',
value: 'string',
children: 'string',
type: 'string',
prompt: 'string',
image_url: 'string',
cref_cw: 'int',
lora: 'string',
chinese_prompt: 'string',
lora_weight: 'int',
show_image: 'string',
isShow: 'bool'
},
primaryKey: 'key'
}
}
export class BookTaskModel extends Realm.Object<BookTaskModel> {
id: string
@@ -9,14 +44,24 @@ export class BookTaskModel extends Realm.Object<BookTaskModel> {
generateVideoPath: string | null
srtPath: string | null
audioPath: string | null
draftSrtStyle: string | null // 草稿字幕样式
backgroundMusic: string | null // 背景音乐ID
friendlyReminder: string | null // 友情提示
imageFolder: string | null
styleList: Realm.List<string> | null
prefix: string | null
imageStyle: string[] | null // 软件内置的样式
autoAnalyzeCharacter: string | null // 自动分析角色设置
customizeImageStyle: string[] | null // 自定义的样式
videoConfig: string | null // 合成视频设置
prefixPrompt: string | null // 前缀
suffixPrompt: string | null // 后缀
styleList: string[] | null
status: BookTaskStatus
errorMsg: string | null
isAuto: boolean // 是否自动
updateTime: Date
createTime: Date
imageCategory: BookImageCategory // 图片出图方式
subImageFolder: string[] | null // 出图的子文件夹
static schema: ObjectSchema = {
name: 'BookTask',
@@ -28,14 +73,23 @@ export class BookTaskModel extends Realm.Object<BookTaskModel> {
generateVideoPath: 'string?',
srtPath: 'string?',
audioPath: 'string?',
draftSrtStyle: 'string?',
backgroundMusic: 'string?',
friendlyReminder: 'string?',
imageFolder: 'string?',
styleList: 'string[]',
prefix: 'string?',
subImageFolder: "string?[]",
imageStyle: 'string?[]',
autoAnalyzeCharacter: 'string?',
customizeImageStyle: 'string?[]',
videoConfig: "string?",
prefixPrompt: "string?",
suffixPrompt: "string?",
status: 'string',
errorMsg: 'string?',
isAuto: 'bool',
updateTime: 'date',
createTime: 'date'
createTime: 'date',
imageCategory: 'string',
},
// 主键为_id
primaryKey: 'id'
+30 -4
View File
@@ -5,8 +5,8 @@ import {
BookTaskStatus,
BookType,
MJAction,
MJCategroy
} from '../../../enum/bookEnum'
import { MJImageType } from '../../../enum/mjEnum'
export class Subtitle extends Realm.Object<Subtitle> {
startTime: number
@@ -29,7 +29,7 @@ export class MJMessage extends Realm.Object<MJMessage> {
id: string
mjApiUrl: string | null
progress: number
category: MJCategroy
category: MJImageType
imageClick: string | null // 图片点击(显示的小的)
imageShow: string | null // 图片实际的地址
messageId: string // 消息ID(可以是MJ中的,也可以是API中的)
@@ -105,6 +105,26 @@ export class SDConfig extends Realm.Object<SDConfig> {
}
}
// 放反推的提示词的对象
export class ReversePrompt extends Realm.Object<ReversePrompt> {
id: string
bookTaskDetailId: string
prompt: string
promptCN: string
isSelect: boolean
static schema: ObjectSchema = {
name: 'ReversePrompt',
properties: {
id: 'string',
bookTaskDetailId: "string",
prompt: 'string',
promptCN: 'string',
isSelect: 'bool'
},
primaryKey: 'id'
}
}
export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
id: string
no: number
@@ -119,16 +139,19 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
startTime: number | null // 开始时间
endTime: number | null // 结束时间
timeLimit: string | null // 事件实现(0 -- 3000
subValue: Realm.List<Subtitle> | null // 包含的字幕数据
subValue: string | null // 包含的字幕数据
characterTags: string[] | null // 角色标签
gptPrompt: string | null // GPT提示词
mjMessage: MJMessage | null // MJ消息
outImagePath: string | null // 输出图片地址
subImagePath: string[] | null // 子图片地址
imageLock: boolean // 图片锁
prompt: string | null // 提示
adetailer: boolean // 是否开启修脸
sdConifg: SDConfig | null // SD配置
reversePrompt: ReversePrompt[] | null // 反推的提示词(数组)
subtitlePosition: string | null // 字幕位置
status: BookTaskStatus
createTime: Date
updateTime: Date
@@ -148,16 +171,19 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
startTime: 'int?',
endTime: 'int?',
timeLimit: 'string?',
subValue: { type: 'list', objectType: 'Subtitle' },
subValue: 'string?',
reversePrompt: { type: 'list', objectType: 'ReversePrompt' },
characterTags: { type: 'list', objectType: 'string' },
gptPrompt: 'string?',
mjMessage: 'MJMessage?',
outImagePath: 'string?',
subImagePath: 'string[]',
imageLock: 'bool',
prompt: 'string?',
adetailer: 'bool',
sdConifg: 'SDConfig?',
subtitlePosition: 'string?',
status: "string",
createTime: 'date',
updateTime: 'date'
},
+5 -1
View File
@@ -11,6 +11,8 @@ export class SoftwareModel extends Realm.Object<SoftwareModel> {
ttsSetting: string | null // TTS设置的json字符串
writeSetting: string | null // 文案的相关配置的json字符串
aiSetting: string | null // AI相关的配置的json字符串
watermarkSetting: string | null // 水印相关的配置的json字符串
translationSetting: string | null // 翻译相关的配置的json字符串
static schema: ObjectSchema = {
name: 'Software',
@@ -23,7 +25,9 @@ export class SoftwareModel extends Realm.Object<SoftwareModel> {
globalSetting: 'string',
ttsSetting: 'string?', // 可空
writeSetting: 'string?',
aiSetting: 'string?'
aiSetting: 'string?',
watermarkSetting: 'string?',
translationSetting: 'string?'
},
// 主键为_id
primaryKey: 'id'
@@ -1,21 +1,16 @@
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 {
BookBackTaskStatus,
BookBackTaskType,
BookTaskStatus,
TaskExecuteType
} from '../../../enum/bookEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
import { BaseRealmService } from './bookBasic'
import { isEmpty } from 'lodash'
import { DefaultObject } from 'realm/dist/public-types/schema.js'
import { BookModel } from '../../model/Book/book.js'
import { OtherData } from '../../../enum/softwareEnum.js'
import { BookBackTaskList } from '../../model/Book/BookBackTaskListModel.js'
import { Book } from '../../../../model/book.js'
import { GeneralResponse } from '../../../../model/generalResponse.js'
const { v4: uuidv4 } = require('uuid')
export class BookBackTaskListService extends BaseRealmService {
@@ -44,7 +39,7 @@ export class BookBackTaskListService extends BaseRealmService {
* bookId 和 status 必填一个
* @param query bookIdbookTaskIdnametypestatus
*/
GetBookBackTaskList(query) {
GetBookBackTaskList(query: Book.QueryBookBackTaskCondition) {
try {
if (query == null) {
throw new Error('查询后台队列任务失败,没有查询条件')
@@ -53,33 +48,36 @@ export class BookBackTaskListService extends BaseRealmService {
throw new Error('查询后台队列任务失败,没有查询条件')
}
// 构建查询条件
// 下面时可空的条件
let queryString = ''
if (query.bookId) {
queryString = `bookId = ${query.bookId}`
}
if (query.bookTaskId) {
queryString += ` && bookTaskId = ${query.bookTaskId}`
}
if (query.name) {
queryString += ` && name = ${query.name}`
}
if (query.type) {
queryString += ` && type = ${query.type}`
}
if (query.status) {
queryString += ` && status = ${query.status}`
}
if (query.executeType) {
queryString += ` && executeType = ${query.executeType}`
}
// 获取数据
let tasks = this.realm
.objects('BookBackTaskList')
.filtered(queryString)
.sorted('createTime', true)
// 构建查询条件
if (query.id) {
tasks.filtered('id = $0', query.id)
}
if (query.bookId) {
tasks.filtered('bookId = $0', query.bookId)
}
if (query.bookTaskId) {
tasks.filtered('bookTaskId = $0', query.bookTaskId)
}
if (query.name) {
tasks.filtered('name = $0', query.name)
}
if (query.type) {
tasks.filtered('type = $0', query.type)
}
if (query.status) {
tasks.filtered('status = $0', query.status)
}
if (query.executeType) {
tasks.filtered('executeType = $0', query.executeType)
}
let res
if (query.count) {
res = tasks.slice(0, query.count)
@@ -107,12 +105,12 @@ export class BookBackTaskListService extends BaseRealmService {
let tasks = this.realm
.objects<BookBackTaskList>('BookBackTaskList')
.filtered(
'status == $0 && executeType == $1',
'(status == $0 || status == $1) && executeType == $2',
BookBackTaskStatus.WAIT,
BookBackTaskStatus.RECONNECT,
executeType ? executeType : TaskExecuteType.AUTO
)
.sorted('createTime', false)
if (count != null) {
tasks = tasks.slice(0, count) as unknown as Realm.Results<BookBackTaskList>
}
@@ -169,9 +167,8 @@ export class BookBackTaskListService extends BaseRealmService {
}
// 开始往数据库中写数据
let name = `${book.name}-${bookTask ? bookTask.name : 'default'}-${
bookTaskDetail ? bookTaskDetail.name : 'default'
}-${taskType}`
let name = `${book.name}-${bookTask ? bookTask.name : 'default'}-${bookTaskDetail ? bookTaskDetail.name : 'default'
}-${taskType}`
let bookBackTask = {
id: uuidv4(),
@@ -183,15 +180,14 @@ export class BookBackTaskListService extends BaseRealmService {
executeType: executeType,
status: BookBackTaskStatus.WAIT,
createTime: new Date(),
updateTime: new Date()
}
updateTime: new Date(),
startTime: 0,
endTime: 0
} as TaskModal.Task
this.realm.write(() => {
this.realm.create('BookBackTaskList', bookBackTask)
})
// 添加成功之后,调用开始执行任务的方法
await global.taskManager.ExecuteAutoTask()
return successMessage(
bookBackTask,
'新增后台队列任务到数据库成功',
@@ -210,7 +206,7 @@ export class BookBackTaskListService extends BaseRealmService {
* (对于后台的队列任务只能修改状态)和错误信息
* @param bookBackTask 修改的数据
*/
UpdateTaskStatus(bookBackTask) {
UpdateTaskStatus(bookBackTask: Book.UpdateBookTaskListStatus): GeneralResponse.SuccessItem {
try {
// 判断数据是不是存在
if (isEmpty(bookBackTask.id) || isEmpty(bookBackTask.status)) {
@@ -219,7 +215,7 @@ export class BookBackTaskListService extends BaseRealmService {
// 开始修改
this.transaction(() => {
// 获取指定ID的队列任务
let _bookBackTask = this.realm.objectForPrimaryKey('BookBackTaskList', bookBackTask.id)
let _bookBackTask = this.realm.objectForPrimaryKey('BookBackTaskList', bookBackTask.id) as TaskModal.Task
// 判断数据是不是存在
if (_bookBackTask == null) {
throw new Error('修改后台队列任务失败,数据不存在')
@@ -229,6 +225,16 @@ export class BookBackTaskListService extends BaseRealmService {
if (bookBackTask.errorMessage) {
_bookBackTask.errorMessage = bookBackTask.errorMessage
}
// 根据状态修改结束和完成时间
if (bookBackTask.status == BookBackTaskStatus.RUNNING) {
_bookBackTask.startTime = new Date().getTime()
} else if (bookBackTask.status == BookBackTaskStatus.DONE || bookBackTask.status == BookBackTaskStatus.FAIL || bookBackTask.status == BookBackTaskStatus.PAUSE) {
_bookBackTask.endTime = new Date().getTime()
} else if (bookBackTask.status == BookBackTaskStatus.RECONNECT) {
_bookBackTask.startTime = 0;
_bookBackTask.endTime = 0;
}
})
return successMessage(
bookBackTask,
+81 -2
View File
@@ -7,12 +7,13 @@ import path from 'path'
import {
BookTaskDetailModel,
MJMessage,
ReversePrompt,
SDConfig,
Subtitle,
WebuiConfig
} from '../../model/Book/bookTaskDetail'
import { BookBackTaskList } from '../../model/Book/BookBackTaskListModel'
import { TaskExecuteType } from '../../../enum/bookEnum'
import { BookTaskStatus, TaskExecuteType } from '../../../enum/bookEnum'
import { version } from '../../../../../package.json'
let dbPath = path.resolve(define.db_path, 'book.realm')
@@ -77,6 +78,83 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
newBookTask[i].subtitlePosition = null // 设置字幕位置的默认值
}
}
if (oldRealm.schemaVersion < 9) {
const oldBookTask = oldRealm.objects('BookBackTaskList')
const newBookTask = newRealm.objects('BookBackTaskList')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].startTime = 0
newBookTask[i].endTime = 0
}
}
if (oldRealm.schemaVersion < 10) {
const oldBookTask = oldRealm.objects('BookTaskDetail')
const newBookTask = newRealm.objects('BookTaskDetail')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].status = BookTaskStatus.WAIT
}
}
if (oldRealm.schemaVersion < 11) {
const oldBookTask = oldRealm.objects('BookTaskDetail')
const newBookTask = newRealm.objects('BookTaskDetail')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].reversePrompt = null
}
}
if (oldRealm.schemaVersion < 13) {
const oldBookTask = oldRealm.objects('ReversePrompt')
const newBookTask = newRealm.objects('ReversePrompt')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].promptCN = null;
newBookTask[i].isSelect = false;
}
}
if (oldRealm.schemaVersion < 15) {
const oldBookTask = oldRealm.objects('BookTaskDetail')
const newBookTask = newRealm.objects('BookTaskDetail')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].imageCategory = null;
}
}
if (oldRealm.schemaVersion < 16) {
const oldBookTask = oldRealm.objects('BookTask')
const newBookTask = newRealm.objects('BookTask')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].subImageFolder = null;
}
}
if (oldRealm.schemaVersion < 17) {
const oldBookTask = oldRealm.objects('BookTaskDetail')
const newBookTask = newRealm.objects('BookTaskDetail')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].imageLock = false;
}
}
if (oldRealm.schemaVersion < 19) {
const oldBookTask = oldRealm.objects('Book')
const newBookTask = newRealm.objects('Book')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].draftSrtStyle = null;
newBookTask[i].backgroundMusic = null;
newBookTask[i].friendlyReminder = null;
}
}
if (oldRealm.schemaVersion < 20) {
const oldBookTask = oldRealm.objects('BookTask')
const newBookTask = newRealm.objects('BookTask')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].draftSrtStyle = null;
newBookTask[i].backgroundMusic = null;
newBookTask[i].friendlyReminder = null;
}
}
if (oldRealm.schemaVersion < 21) {
const oldBookTask = oldRealm.objects('BookTaskDetail')
const newBookTask = newRealm.objects('BookTaskDetail')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].subValue = '[]'
}
}
}
export class BaseRealmService extends BaseService {
@@ -114,10 +192,11 @@ export class BaseRealmService extends BaseService {
SDConfig,
WebuiConfig,
BookTaskModel,
ReversePrompt,
BookTaskDetailModel
],
path: this.dbpath,
schemaVersion: 8,
schemaVersion: 21,
migration: migration
}
this.realm = await Realm.open(config)
+36 -13
View File
@@ -3,13 +3,16 @@ 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'
import { BookImageCategory, BookTaskStatus, BookType } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/Public/generalTools'
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../Tools/file'
const { v4: uuidv4 } = require('uuid')
import { BookTaskService } from './bookTaskService'
import { BaseRealmService } from './bookBasic.js'
import { isEmpty } from 'lodash'
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
import { version } from '../../../../../package.json'
import { Book } from '../../../../model/book.js'
export class BookService extends BaseRealmService {
static instance: BookService | null = null
@@ -36,14 +39,14 @@ export class BookService extends BaseRealmService {
* 获取小说信息,没有找到返回null
* @param bookId
*/
GetBookDataById(bookId) {
GetBookDataById(bookId): Book.SelectBook | null {
try {
if (isEmpty(bookId)) {
throw new Error('获取小说信息失败,缺少小说ID')
}
let books = this.realm.objects<BookModel>('Book').filtered('id = $0', bookId)
if (books.length <= 0) {
return successMessage(null, '通过ID获取小说数据成功', 'ReverseBook_GetBookDataById')
return null
} else {
// 对返回的数据进行处理
let resBooks = Array.from(books).map((book) => {
@@ -63,8 +66,7 @@ export class BookService extends BaseRealmService {
}
return bookObj
})
return successMessage(resBooks[0], '通过ID获取小说数据成功', 'ReverseBook_GetBookDataById')
return resBooks[0]
}
} catch (error) {
throw error
@@ -120,8 +122,10 @@ export class BookService extends BaseRealmService {
: '',
imageFolder: book.imageFolder
? path.resolve(define.project_path, book.imageFolder.replace(/\\/g, '/'))
: ''
}
: '',
imageStyle: book.imageStyle ? Array.from(book.imageStyle) : [],
customizeImageStyle: book.customizeImageStyle ? Array.from(book.imageStyle) : [],
} as Book.SelectBook
return bookObj
})
@@ -186,14 +190,31 @@ export class BookService extends BaseRealmService {
await CopyFileOrFolder(book.oldVideoPath, oldVideoPath)
}
let ffmpegOptions = new FfmpegOptions();
let res = await ffmpegOptions.FfmpegCompressVideo(oldVideoPath, 800, "2000k")
// 创建对应的文件夹
await CheckFolderExistsOrCreate(bookFolderPath)
await CheckFolderExistsOrCreate(imageFolder)
await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹
// 修改数据
book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
let imageCategory = BookImageCategory.MJ
if (book.type == BookType.SD_REVERSE) {
imageCategory = BookImageCategory.SD
} else if (book.type == BookType.MJ_REVERSE) {
imageCategory = BookImageCategory.MJ
} else if (book.type == BookType.ORIGINAL) {
imageCategory = BookImageCategory.MJ
} else {
throw new Error('未知的小说类型')
}
this.realm.write(() => {
book.version = version
this.realm.create('Book', book)
// 添加一个任务
let bookTask = {
id: uuidv4(),
@@ -210,7 +231,9 @@ export class BookService extends BaseRealmService {
errorMsg: null,
isAuto: false,
updateTime: new Date(),
createTime: new Date()
createTime: new Date(),
version: version,
imageCategory: imageCategory
}
// 添加任务
@@ -265,7 +288,7 @@ export class BookService extends BaseRealmService {
// 检查小说ID对应的数据是不是存在
let bookRes = this.GetBookDataById(bookId)
if (bookRes.data == null) {
if (bookRes == null) {
throw new Error('修改小说数据失败,小说ID对应的数据不存在')
}
@@ -279,11 +302,11 @@ export class BookService extends BaseRealmService {
})
bookRes = this.GetBookDataById(bookId)
if (bookRes.data == null) {
if (bookRes == null) {
throw new Error('获取修改后的小说数据失败,小说ID对应的数据不存在')
}
return successMessage(bookRes.data, '修改小说数据成功', 'ReverseBook_UpdateBookData')
return successMessage(bookRes, '修改小说数据成功', 'ReverseBook_UpdateBookData')
} catch (error) {
throw error
}
@@ -4,19 +4,21 @@ 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 { successMessage } from '../../../../main/Public/generalTools'
import { BaseRealmService } from './bookBasic'
import { endsWith, isEmpty } from 'lodash'
import { cloneDeep, endsWith, isEmpty } from 'lodash'
import { book } from '../../../../preload/book.js'
import { DefaultObject } from 'realm/dist/public-types/schema.js'
import { JoinPath } from '../../../Tools/file.js'
import { BookTaskDetailModel } from '../../model/Book/bookTaskDetail.js'
import { JoinPath } from '../../../Tools/file'
import { BookTaskDetailModel, ReversePrompt } from '../../model/Book/bookTaskDetail.js'
const { v4: uuidv4 } = require('uuid')
import { Book } from "../../../../model/book"
import { GeneralResponse } from '../../../../model/generalResponse.js'
let dbPath = path.resolve(define.db_path, 'book.realm')
// 版本迁移
const migration = (oldRealm: Realm, newRealm: Realm) => {}
const migration = (oldRealm: Realm, newRealm: Realm) => { }
export class BookTaskDetailService extends BaseRealmService {
static instance: BookTaskDetailService | null = null
@@ -43,7 +45,7 @@ export class BookTaskDetailService extends BaseRealmService {
* 更具条件查询执行的小说的分镜信息
* @param condition 查询的条件,idnamebookIdbookTaskId
*/
GetBookTaskData(condition) {
GetBookTaskData(condition: Book.QueryBookTaskDetailCondition) {
try {
if (condition == null) {
throw new Error('查询小说分镜信息,查询条件不能为空')
@@ -62,6 +64,7 @@ export class BookTaskDetailService extends BaseRealmService {
tasksToDelete = tasksToDelete.filtered('name==$0', condition.name)
}
let resData = Array.from(tasksToDelete).map((item) => {
let resObj = {
...item,
@@ -71,9 +74,17 @@ export class BookTaskDetailService extends BaseRealmService {
outImagePath: JoinPath(define.project_path, item.outImagePath),
subImagePath: (item.subImagePath as string[])?.map((subImage) => {
return JoinPath(define.project_path, subImage)
})
}),
characterTags: item.characterTags ? item.characterTags.map((tag) => tag) : null,
subValue: item.subValue,
reversePrompt: item.reversePrompt.map((reversePrompt) => {
return {
...reversePrompt
}
}),
mjMessage: item.mjMessage ? item.mjMessage.toJSON() : null,
}
return resObj
return cloneDeep(resObj)
})
return successMessage(
resData,
@@ -89,7 +100,7 @@ export class BookTaskDetailService extends BaseRealmService {
* 通过ID获取指定的小说任务分镜详细数据
* @param bookTaskDetailId
*/
public GetBookTaskDetailDataById(bookTaskDetailId: string) {
public GetBookTaskDetailDataById(bookTaskDetailId: string): Book.SelectBookTaskDetail {
try {
if (bookTaskDetailId == null) {
throw new Error('获取小说任务详细信息失败,缺少ID')
@@ -97,17 +108,9 @@ export class BookTaskDetailService extends BaseRealmService {
let bookTaskDetails = this.GetBookTaskData({ id: bookTaskDetailId })
if (bookTaskDetails.data.length <= 0) {
return successMessage(
null,
'未找到对应的小说任务详细信息',
'BookTaskDetailService_GetBookTaskDetailDataById'
)
return null;
} else {
return successMessage(
bookTaskDetails.data[0],
'获取小说任务详细信息成功',
'BookTaskDetailService_GetBookTaskDetailDataById'
)
return bookTaskDetails.data[0]
}
} catch (error) {
throw error
@@ -142,6 +145,7 @@ export class BookTaskDetailService extends BaseRealmService {
bookTaskDetail.name = name
bookTaskDetail.id = uuidv4()
bookTaskDetail.imageLock = false
bookTaskDetail.createTime = new Date()
bookTaskDetail.updateTime = new Date()
bookTaskDetail.adetailer = false // 先写死false
@@ -165,7 +169,7 @@ export class BookTaskDetailService extends BaseRealmService {
* @param bookTaskDetailId
* @param updateData
*/
UpdateBookTaskDetail(bookTaskDetailId: string, updateData) {
UpdateBookTaskDetail(bookTaskDetailId: string, updateData: Book.SelectBookTaskDetail) {
try {
this.transaction(() => {
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
@@ -188,6 +192,53 @@ export class BookTaskDetailService extends BaseRealmService {
}
}
UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage): void {
try {
this.transaction(() => {
let mjMessageRes = this.realm.objectForPrimaryKey('MJMessage', bookTaskDetailId)
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
if (bookTaskDetail.mjMessage == null) {
// 新增
mjMessage.id = bookTaskDetailId
bookTaskDetail.mjMessage = mjMessage
} else {
for (const key in mjMessage) {
mjMessageRes[key] = mjMessage[key]
}
}
})
} catch (error) {
throw error
}
}
/**
* 更新指定ID的反推提示词数据
* @param bookTaskDetailId 分镜数据的ID
* @param reversePromptId 反推出来的提示词ID
* @param updateData 要更新的数据
*/
UpdateBookTaskDetailReversePrompt(bookTaskDetailId: string, reversePromptId: string, reversePrompt: Book.ReversePrompt): GeneralResponse.SuccessItem {
try {
this.transaction(() => {
let bookTaskDetails = this.realm.objects<ReversePrompt>("ReversePrompt");
bookTaskDetails = bookTaskDetails.filtered("id = $0 && bookTaskDetailId = $1", reversePromptId, bookTaskDetailId);
if (bookTaskDetails.length <= 0) {
throw new Error("未找到执行的翻译数据,无法写回")
}
let bookTaskDetail = bookTaskDetails[0];
// 直接写入
for (const key in reversePrompt) {
bookTaskDetail[key] = reversePrompt[key]
}
})
return successMessage(null, `${reversePromptId} 更新完成`, "BookTaskDetailService_UpdateBookTaskDetailReversePrompt")
} catch (error) {
throw error
}
}
/**
* 删除满足条件的对象吗,必传小说ID和小说任务ID
* @param condition bookIdbookTaskIdnameid
@@ -223,4 +274,18 @@ export class BookTaskDetailService extends BaseRealmService {
throw error
}
}
/**
* 删除指定ID的小说任务详细数据中的所有的反推提示词数据
* @param bookTaskDetailId 小说分镜的ID
*/
DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): void {
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId);
if (bookTaskDetail == null) {
throw new Error('删除小说任务详细信息的反推提示词失败,未找到对应的分镜信息')
}
this.transaction(() => {
this.realm.delete(bookTaskDetail.reversePrompt)
})
}
}
+115 -21
View File
@@ -1,24 +1,29 @@
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 { BookBackTaskStatus, BookTaskStatus } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/generalTools.js'
import { BookBackTaskStatus, BookImageCategory, BookTaskStatus } from '../../../enum/bookEnum.js'
import { successMessage } from '../../../../main/Public/generalTools'
import { BaseRealmService } from './bookBasic'
import { isEmpty } from 'lodash'
import { JoinPath } from '../../../Tools/file.js'
import { JoinPath } from '../../../Tools/file'
import { BookBackTaskList } from '../../model/Book/BookBackTaskListModel.js'
const { v4: uuidv4 } = require('uuid')
import { Book } from '../../../../model/book'
import { TagDefine } from '../../../tagDefine.js'
import { ImageStyleDefine } from "../../../../define/iamgeStyleDefine"
import { cloneDeep } from 'lodash'
import { GeneralResponse } from '../../../../model/generalResponse'
let dbPath = path.resolve(define.db_path, 'book.realm')
export class BookTaskService extends BaseRealmService {
static instance: BookTaskService | null = null
realm: Realm
tagDefine: TagDefine
private constructor() {
super()
this.tagDefine = new TagDefine()
}
/**
@@ -38,7 +43,7 @@ export class BookTaskService extends BaseRealmService {
* 查询满足条件的小说子任务信息
* @param bookTaskCondition 查询条件 idbookIdnamenopage, pageSize
*/
GetBookTaskData(bookTaskCondition) {
GetBookTaskData(bookTaskCondition: Book.QueryBookTaskCondition): GeneralResponse.ErrorItem | GeneralResponse.SuccessItem {
try {
// 获取所有的小说数据,并进行时间降序排序
let bookTasks = this.realm.objects<BookTaskModel>('BookTask')
@@ -62,7 +67,7 @@ export class BookTaskService extends BaseRealmService {
}
let bookTask_length = bookTasks.length
bookTasks = bookTasks.sorted('updateTime', true)
// bookTasks = bookTasks.sorted('updateTime', true)
// 判断是不是有page和pageSize,有的话对查询返回的信息做分页
if (bookTaskCondition.page && bookTaskCondition.pageSize) {
bookTasks = bookTasks.slice(
@@ -73,22 +78,24 @@ export class BookTaskService extends BaseRealmService {
// 做一下数据转换
// 将realm对象数组转换为普通对象数组
// 将realm对象数组转换为普通对象数组,并处理异步操作
let res_bookTasks = Array.from(bookTasks).map((bookTask) => {
// 这里可以直接操作普通对象
let bookObj = {
// 直接操作普通对象
return {
...bookTask,
styleList: bookTask.styleList ? Array.from(bookTask.styleList) : [],
imageStyle: bookTask.imageStyle ? Array.from(bookTask.imageStyle) : [],
customizeImageStyle: bookTask.customizeImageStyle ? Array.from(bookTask.customizeImageStyle) : [],
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
imageFolder: JoinPath(define.project_path, bookTask.imageFolder),
imageCategory: bookTask.imageCategory ? bookTask.imageCategory : BookImageCategory.MJ, // 默认使用MJ出图
} as Book.SelectBookTask;
})
return successMessage(
{
bookTasks: res_bookTasks,
bookTasks: JSON.parse(JSON.stringify(res_bookTasks)),
total: bookTask_length
},
'查询小说任务成功',
@@ -103,7 +110,7 @@ export class BookTaskService extends BaseRealmService {
* 通过ID获取小说批次任务的数据
* @param bookTaskId
*/
GetBookTaskDataById(bookTaskId: string) {
GetBookTaskDataById(bookTaskId: string): Book.SelectBookTask {
try {
if (bookTaskId == null) {
throw new Error('小说任务ID不能为空')
@@ -111,13 +118,9 @@ export class BookTaskService extends BaseRealmService {
let bookTasks = this.GetBookTaskData({ id: bookTaskId })
if (bookTasks.data.bookTasks.length <= 0) {
return successMessage(null, '未找到对应的小说任务', 'BookTaskService_GetBookTaskDataById')
throw new Error('未找到对应的小说任务')
} else {
return successMessage(
bookTasks.data.bookTasks[0],
'查询小说任务成功',
'BookTaskService_GetBookTaskDataById'
)
return bookTasks.data.bookTasks[0]
}
} catch (error) {
throw error
@@ -183,6 +186,28 @@ export class BookTaskService extends BaseRealmService {
}
}
/**
* 修改小说批次任务数据
* @param bookTaskId 小说批次任务ID
* @param data 要修改的数据
*/
UpdetedBookTaskData(bookTaskId: string, data: Book.SelectBookTask): void {
try {
this.transaction(() => {
let updateData = this.realm.objectForPrimaryKey('BookTask', bookTaskId)
if (updateData == null) {
throw new Error('未找到对应的小说任务详细信息')
}
// 开始修改
for (let key in data) {
updateData[key] = data[key]
}
})
} catch (error) {
throw error
}
}
// 添加一条数据
AddOrModifyBookTask(bookTask) {
try {
@@ -220,4 +245,73 @@ export class BookTaskService extends BaseRealmService {
throw error
}
}
private resetBookTask(bookTaskId: string) {
let modifyBookTask = this.realm.objectForPrimaryKey('BookTask', bookTaskId)
modifyBookTask.status = BookTaskStatus.WAIT
modifyBookTask.errorMsg = "";
modifyBookTask.updateTime = new Date()
modifyBookTask.imageStyle = []
modifyBookTask.autoAnalyzeCharacter = undefined
modifyBookTask.customizeImageStyle = []
modifyBookTask.videoConfig = undefined
modifyBookTask.prefixPrompt = undefined
modifyBookTask.suffixPrompt = undefined
modifyBookTask.subImageFolder = []
let bookTaskDetails = this.realm.objects('BookTaskDetail').filtered('bookTaskId = $0', bookTaskId)
// 开始删除数据
bookTaskDetails.forEach(bookTaskDetail => {
// 删除MJMessage
if (bookTaskDetail.mjMessage) {
this.realm.delete(bookTaskDetail.mjMessage)
}
if (bookTaskDetail.reversePrompt) {
(bookTaskDetail.reversePrompt as any[]).forEach(item => {
this.realm.delete(item)
})
}
if (bookTaskDetail.sdConifg) {
this.realm.delete(bookTaskDetail.sdConifg)
}
this.realm.delete(bookTaskDetail)
})
}
/**
* 删除对应的小说批次数据
* @param bookTaskId 小说批次ID
*/
ResetBookTask(bookTaskId: string): void {
try {
// 开始重置数据,先重置小说批次数据,在重置其他
this.transaction(() => {
this.resetBookTask(bookTaskId)
})
} catch (error) {
throw error
}
}
/**
* 删除对应的小说批次数据
* @param bookTaskId 要删除的批次的ID
*/
DeleteBookTask(bookTaskId: string): void {
try {
this.transaction(() => {
// 先调用清除数据的方法
this.resetBookTask(bookTaskId)
// 删除批次数据
let bookTask = this.realm.objectForPrimaryKey('BookTask', bookTaskId)
if (bookTask == null) {
throw new Error('未找到对应的小说任务,无法执行删除操作')
}
this.realm.delete(bookTask)
})
} catch (error) {
throw error
}
}
}
@@ -2,9 +2,9 @@ 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 { SoftwareModel } from '../../model/SoftWare/software'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
import { BaseSoftWareService } from './softwareBasic.js'
import { isEmpty } from 'lodash'
const { v4: uuidv4 } = require('uuid')
@@ -2,13 +2,14 @@ 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 { SoftwareModel } from '../../model/SoftWare/software'
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
import { errorMessage, successMessage } from '../../../../main/generalTools.js'
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
import { BaseSoftWareService } from './softwareBasic.js'
import { isEmpty, isNumber } from 'lodash'
const { v4: uuidv4 } = require('uuid')
import { version } from '../../../../../package.json'
import { GeneralResponse } from '../../../../model/generalResponse'
export class MJSettingService extends BaseSoftWareService {
static instance: MJSettingService | null = null
@@ -561,7 +562,7 @@ export class MJSettingService extends BaseSoftWareService {
// 判断API设置的数据是不是存在
let apiSetting = mjSetting.apiSetting ? mjSetting.apiSetting : null
if (apiSetting != null) {
let apiSettingRes: { code: number; data: any; message: any }
let apiSettingRes: GeneralResponse.ErrorItem | GeneralResponse.SuccessItem
if (isEmpty(apiSetting.id)) {
// 新增
apiSettingRes = this.AddAPIMjSetting(apiSetting)
@@ -577,7 +578,7 @@ export class MJSettingService extends BaseSoftWareService {
// 判断浏览器模式的数据是不是存在
let browserSetting = mjSetting.browserSetting ? mjSetting.browserSetting : null
if (browserSetting != null) {
let browserSettingRes: { code: number; data: any; message: any }
let browserSettingRes: GeneralResponse.ErrorItem | GeneralResponse.SuccessItem
if (isEmpty(browserSetting.id)) {
// 新增
browserSettingRes = this.AddBrowserMJSetting(browserSetting)
@@ -591,7 +592,7 @@ export class MJSettingService extends BaseSoftWareService {
}
// 添加MJ的基础配置信息
let mjSettingRes: { code: number; data: any; message: any }
let mjSettingRes: GeneralResponse.ErrorItem | GeneralResponse.SuccessItem
if (isEmpty(mjSetting.id)) {
// 新增
mjSettingRes = this.AddMJSetting(mjSetting)
@@ -131,6 +131,22 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
}
})
}
if (oldRealm.schemaVersion < 18) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('Software')
for (let software of newSoftwares) {
software.watermarkSetting = null // 水印的默认设置
}
})
}
if (oldRealm.schemaVersion < 19) {
newRealm.write(() => {
const newSoftwares = newRealm.objects('Software')
for (let software of newSoftwares) {
software.translationSetting = null // 翻译的默认设置
}
})
}
}
export class BaseSoftWareService extends BaseService {
@@ -169,7 +185,7 @@ export class BaseSoftWareService extends BaseService {
MjSettingModel
],
path: dbPath,
schemaVersion: 17, // 当前版本号
schemaVersion: 19, // 当前版本号
migration: migration
}
// 判断当前全局是不是又当前这个
@@ -1,10 +1,5 @@
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 { successMessage } from '../../../../main/Public/generalTools'
import { BaseSoftWareService } from './softwareBasic.js'
const { v4: uuidv4 } = require('uuid')
@@ -63,12 +58,26 @@ export class SoftwareService extends BaseSoftWareService {
*/
GetSoftwareData() {
try {
let software = this.realm.objects('Software')
let softwares = this.realm.objects('Software')
let res = Array.from(softwares).map((software) => {
// 这里可以直接操作普通对象
let bookObj = {
id: software.id,
theme: software.theme,
reverse_show_book_striped: software.reverse_show_book_striped,
reverse_data_table_size: software.reverse_data_table_size,
reverse_display_show: software.reverse_display_show,
}
return bookObj
})
return successMessage(
software.toJSON(),
res,
'获取软件配置信息成功',
'SoftwareService_GetSoftwareData'
)
} catch (error) {
global.logger.error(
'SoftwareService_GetSoftwareData',
@@ -82,17 +91,15 @@ export class SoftwareService extends BaseSoftWareService {
* 获取当前软件指定属性的数据
* @param property 属性名称
*/
GetSoftWarePropertyData(property: string) {
GetSoftWarePropertyData(property: string): string {
try {
let software = this.realm.objects('Software')
if (software.length <= 0) {
throw new Error('数据库中没有软件配置信息')
}
let softwareData = software.toJSON()[0]
let res = softwareData[property]
return successMessage(res, '获取软件配置信息成功', 'SoftwareService_GetSoftWarePropertyData')
let res = softwareData[property] as string
return res
} catch (error) {
global.logger.error(
'SoftwareService_GetSoftWarePropertyData',
+6 -1
View File
@@ -15,6 +15,8 @@ if (!app.isPackaged) {
scripts_path: path.join(__dirname, '../../resources/scripts'),
db_path: path.join(__dirname, '../../resources/scripts/db'),
project_path: path.join(__dirname, '../../project'),
tts_path: path.join(__dirname, '../../tts'),
logger_path: path.join(__dirname, '../../resources/logger'),
package_path: path.join(__dirname, '../../resources/package'),
image_path: path.join(__dirname, '../../resources/image'),
@@ -82,6 +84,7 @@ if (!app.isPackaged) {
scripts_path: path.join(__dirname, '../../../resources/scripts'),
db_path: path.join(__dirname, '../../../resources/scripts/db'),
project_path: path.join(__dirname, '../../../project'),
tts_path: path.join(__dirname, '../../../tts'),
logger_path: path.join(__dirname, '../../../resources/logger'),
package_path: path.join(__dirname, '../../../resources/package'),
discordScript: path.join(__dirname, '../../../resources/scripts/discordScript.js'),
@@ -141,5 +144,7 @@ if (!app.isPackaged) {
define['remotemj_api'] = 'https://api.laitool.net/'
define['serverUrl'] = 'http://lapi.laitool.cn'
define['hkServerUrl'] = 'https://api.laitool.cc/'
define['bakServerUrl'] = 'https://bakapi.laitool.cc/'
define['API'] = 'f85d39ed5a40fd09966f13f12b6cf0f0'
export { define }
export { define }
@@ -1,4 +1,5 @@
export const DEFINE_STRING = {
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS',
GET_FILE_BASE64: 'GET_FILE_BASE64',
@@ -21,7 +22,6 @@ export const DEFINE_STRING = {
SAVE_KEY_FRAME_SETTING: 'SAVE_KEY_FRAME_SETTING',
MODIFY_SAMPLE_SETTING: 'MODIFY_SAMPLE_SETTING',
GET_SETTING_Dafault_DATA: 'GET_SETTING_Dafault_DATA',
GET_DRAFT_FILE_LIST: 'GET_DRAFT_FILE_LIST',
GET_FRAME: 'GET_FRAME',
PYTHON_ERROR: 'PYTHON_ERROR',
PYTHON_CLOSE: 'PYTHON_CLOSE',
@@ -144,9 +144,16 @@ export const DEFINE_STRING = {
NORMAL_PERMISSION: 'NORMAL_PERMISSION',
AUTO_SAVE_IMAGE_PERMISSION: 'AUTO_SAVE_IMAGE_PERMISSION'
},
TRANSLATE: {
TRANSLATE_NOW_RETURN: 'TRANSLATE_NOW_RETURN',
GET_TRANSLATE_SETTING: 'GET_TRANSLATE_SETTING',
RESET_TRANSLATE_SETTING: 'RESET_TRANSLATE_SETTING',
SAVE_TRANSLATE_SETTING: 'SAVE_TRANSLATE_SETTING'
},
SD: {
LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
TXT2IMG: 'TXT2IMG'
TXT2IMG: 'TXT2IMG',
SD_MERGE_PROMPT: "SD_MERGE_PROMPT"
},
MJ: {
SAVE_WORD_SRT: 'SAVE_WORD_SRT',
@@ -167,7 +174,10 @@ export const DEFINE_STRING = {
GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE',
GET_MJ_IMAGE_ROBOT_MODEL: 'GET_MJ_IMAGE_ROBOT_MODEL',
MACTH_USER_RETURN: 'MACTH_USER_RETURN',
AUTO_MATCH_USER: 'AUTO_MATCH_USER'
AUTO_MATCH_USER: 'AUTO_MATCH_USER',
MJ_MERGE_PROMPT: "MJ_MERGE_PROMPT",
ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK: "ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK",
MJ_IMAGE: "MJ_IMAGE"
},
DISCORD: {
OPERATE_REFRASH_DISCORD_URL: 'OPERATE_REFRASH_DISCORD_URL',
@@ -195,6 +205,8 @@ export const DEFINE_STRING = {
BATCH_PROCESS_IMAGE_RESULT: 'BATCH_PROCESS_IMAGE_RESULT'
},
BOOK: {
MAIN_DATA_RETURN: 'MAIN_DATA_RETURN', // 监听任务返回
GET_BOOK_TYPE: 'GET_BOOK_TYPE',
ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK',
GET_BOOK_DATA: 'GET_BOOK_DATA',
@@ -204,7 +216,39 @@ export const DEFINE_STRING = {
SAVE_BOOK_SUBTITLE_POSITION: 'SAVE_BOOK_SUBTITLE_POSITION',
OPEN_BOOK_SUBTITLE_POSITION_SCREENSHOT: 'OPEN_BOOK_SUBTITLE_POSITION_SCREENSHOT',
GET_CURRENT_FRAME_TEXT: 'GET_CURRENT_FRAME_TEXT',
GET_VIDEO_FRAME_TEXT: 'GET_VIDEO_FRAME_TEXT'
GET_VIDEO_FRAME_TEXT: 'GET_VIDEO_FRAME_TEXT',
GET_BOOK_TASK_DETAIL: 'GET_BOOK_TASK_DETAIL',
REVERSE_PROMPT_TO_GPT_PROMPT: 'REVERSE_PROMPT_TO_GPT_PROMPT',
SINGLE_REVERSE_TO_GPT_PROMPT: 'SINGLE_REVERSE_TO_GPT_PROMPT',
SAVE_IMAGE_STYLE: 'SAVE_IMAGE_STYLE',
IMAGE_LOCK_OPERATION: "IMAGE_LOCK_OPERATION",
DOWNLOAD_IMAGE_AND_SPLIT: "DOWNLOAD_IMAGE_AND_SPLIT",
ONE_TO_FOUR_BOOK_TASK: "ONE_TO_FOUR_BOOK_TASK",
RESET_BOOK_TASK: "RESET_BOOK_TASK",
DELETE_BOOK_TASK: "DELETE_BOOK_TASK",
GENERATE_IMAGE_ALL: "GENERATE_IMAGE_ALL",
CHECK_IMAGE_FILE_SIZE: "CHECK_IMAGE_FILE_SIZE",
HD_IMAGE: "HD_IMAGE",
USE_BOOK_VIDEO_DATA_TO_BOOK_TASK: "USE_BOOK_VIDEO_DATA_TO_BOOK_TASK",
ADD_JIANYING_DRAFT: "ADD_JIANYING_DRAFT",
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',
GET_FRAME: 'GET_FRAME',
FRAMING: 'FRAMING',
GET_COPYWRITING: 'GET_COPYWRITING',
GET_COPYWRITING_RETURN: 'GET_COPYWRITING_RETURN',
REMOVE_WATERMARK: 'REMOVE_WATERMARK',
REMOVE_WATERMARK_RETURN: 'REMOVE_WATERMARK_RETURN',
SPLI_TAUDIO: 'SPLI_TAUDIO',
SPLI_TAUDIO_RETURN: 'SPLI_TAUDIO_RETURN',
ADD_REVERSE_PROMPT: 'ADD_REVERSE_PROMPT',
REMOVE_REVERSE_DATA: 'REMOVE_REVERSE_DATA'
},
SYSTEM: {
OPEN_FILE: 'OPEN_FILE',
@@ -225,7 +269,9 @@ export const DEFINE_STRING = {
GET_REMOTE_MJ_SETTINGS: 'GET_REMOTE_MJ_SETTINGS',
ADD_REMOTE_MJ_SETTING: 'ADD_REMOTE_MJ_SETTING',
UPDATE_REMOTE_MJ_SETTING: 'UPDATE_REMOTE_MJ_SETTING',
DELETE_REMOTE_MJ_SETTING: 'DELETE_REMOTE_MJ_SETTING'
DELETE_REMOTE_MJ_SETTING: 'DELETE_REMOTE_MJ_SETTING',
GET_WATER_MARK_SETTING: 'GET_WATER_MARK_SETTING',
SAVE_WATER_MARK_SETTING: 'SAVE_WATER_MARK_SETTING'
},
PROMPT: {
GET_SORT_OPTIONS: 'GET_SORT_OPTIONS',
@@ -235,11 +281,16 @@ export const DEFINE_STRING = {
},
TTS: {
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
GENERATE_AUDIO: 'GENERATE_AUDIO',
SAVE_TTS_CONFIG: 'SAVE_TTS_CONFIG'
},
WRITE: {
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',
ACTION_START: 'ACTION_START'
},
DB: {
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA"
}
}
+70 -5
View File
@@ -7,6 +7,16 @@ export enum BookType {
MJ_REVERSE = 'mj_reverse'
}
// 出图方式
export enum BookImageCategory {
// MJ
MJ = 'mj',
// SD
SD = 'sd',
// D3
D3 = 'd3'
}
export enum MJCategroy {
@@ -39,10 +49,16 @@ export enum BookBackTaskType {
RECOGNIZE = 'recognize',
// 抽帧
FRAME = 'frame',
// 反推
REVERSE = 'reverse',
// 生成图片
IMAGE = 'image',
// MJ反推
MJ_REVERSE = BookType.MJ_REVERSE,
// SD反推
SD_REVERSE = BookType.SD_REVERSE,
// MJ生成图片
MJ_IMAGE = 'mj_image',
// SD 生成图片
SD_IMAGE = 'sd_image',
// D3 生成图片
D3_IMAGE = 'd3_image',
// 高清
HD = 'hd',
// 合成视频
@@ -63,7 +79,9 @@ export enum BookBackTaskStatus {
// 完成
DONE = 'done',
// 失败
FAIL = 'fail'
FAIL = 'fail',
// 重连
RECONNECT = 'reconnect'
}
export enum TaskExecuteType {
@@ -74,6 +92,16 @@ export enum TaskExecuteType {
OPERATE = 'operate'
}
// 弹窗类型
export enum DialogType {
// 单独弹窗
DIALOG = 'dialog',
// 消息提示
MESSAGE = 'message',
// 右上角通知
NOTIFICATION = 'notification'
}
/**
* 小说任务状态
*/
@@ -162,3 +190,40 @@ export enum BookTaskStatus {
// 合成视频失败
COMPOSING_FAIL = 'composing_fail'
}
export enum TagDefineType {
// 默认风格
DEFAULT_STYLE = "default_style",
// 角色标签
CHARACTER_MAIN = "character_main",
// 角色小标签
CHARACTER_SUB = "min",
// 风格主标签
STYLE_MAIN = "style_main",
// 场景主标签
SCENE_MAIN = "scene_main",
}
export enum MergeType {
BOOKTASK = 'bookTask', // 整个小说批次分镜合并
BOOKTASKDETAIL = 'bookTaskDetail' // 单个分镜合并
}
export enum OperateBookType {
BOOK = 'book', // 这个小说的所有批次
BOOKTASK = 'bookTask', // 整个小说批次分镜合并
BOOKTASKDETAIL = 'bookTaskDetail', // 单个分镜合并
UNDERBOOKTASK = 'underBookTask' // 执行小说批次任务的指定ID以及后面的所有的东西
}
export enum CopyImageType {
// 所有,包括原图
ALL = 'all',
// 出原图外其他,一个个对应
ONE = 'one',
// 不包含图
NONE = 'none'
}
View File
+28
View File
@@ -19,3 +19,31 @@ export enum MJRobotType {
// niji
NIJI = 'niji'
}
export enum MJSpeed {
// 快速
FAST = 'fast',
// 休闲
RELAX = 'relaxed'
}
export enum MJRespoonseType {
// 创建
CREATED = "created",
// 更新
UPDATED = "updated",
// 完成
FINISHED = "finished",
// 删除
DELETE = "delete"
}
export enum MJAction {
// 出图
IMAGINE = 'IMAGINE',
// 反推
DESCRIBE = 'DESCRIBE'
}
+25
View File
@@ -45,6 +45,31 @@ export enum SoftColor {
// 棕黄色
BROWN_YELLOW = '#e18a3b',
// 橘色
ORANGE = '#ee7959',
// 朱颜酡
ZHUYANTUO = '#f29a76',
// 错误红色
ERROR_RED = '#c8161d'
}
export enum ResponseMessageType {
GET_TEXT = 'getText', // 获取文案
REMOVE_WATERMARK = "REMOVE_WATERMARK",// 删除水印
MJ_REVERSE = 'MJ_REVERSE',// MJ反推,返回反推结果
PROMPT_TRANSLATE = 'PROMPT_TRANSLATE',// 提示词翻译
MJ_IMAGE = 'MJ_IMAGE',// MJ 生成图片
HD_IMAGE = 'HD_IMAGE',// HD 生成图片
}
export enum LaiAPIType {
// 主要的
MAIN = "main",
// 香港代理
HK_PROXY = "hk-proxy",
// 备用站点
BAK_MAIN = 'bak-main'
}
+6
View File
@@ -0,0 +1,6 @@
export enum TaskQueueType {
// 内存添加
CACHE_ADD = 'cache_add',
// 数据库添加
DB_ADD = 'db_add'
}
+23
View File
@@ -0,0 +1,23 @@
// 翻译类型(主要用于后端逻辑处理)
export enum TranslateType {
// 反推提示词翻译
REVERSE_PROMPT_TRANSLATE = 'reverse_prompt_translate',
// GPT提示词翻译
GPT_PROMPT_TRANSLATE = 'gpt_prompt_translate',
}
// 翻译API类型
export enum TranslateAPIType {
// 百度翻译
BAIDU = 'baidu',
// 腾讯翻译
TENCENT = 'tencent',
// 火山翻译
VOLCENGINE = 'volcengine',
// 阿里翻译
ALI = 'ali',
}
+17
View File
@@ -8,6 +8,23 @@ export enum SubtitleSavePositionType {
// 分镜视频
STORYBOARD_VIDEO = 'storyboard_video',
// 设置,只是框选
SETTING = 'setting',
// 其他类型
OTHER = 'other'
}
// 图片去除水印方法,返回数据的格式
export enum WaterMarkResponseDateType {
// 返回的数据类型
ArrayBuffer = "arrayBuffer",
// 直接将文件写道本地
File = "file"
}
export enum RemoveWatermarkType {
LOCAL_LAMA = 'local_lama',
IOPAINT = 'iopaint'
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,7 +2,7 @@
let fspromises = require('fs').promises;
import { get, cloneDeep } from 'lodash';
import { define } from '../define';
import { errorMessage } from '../../main/generalTools';
import { errorMessage } from '../../main/Public/generalTools';
export class DynamicSetting {
constructor(global) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { successMessage } from "../../main/generalTools";
import { successMessage } from "../../main/Public/generalTools";
export class MjSetting {
constructor(golbal) {
+1 -1
View File
@@ -2,7 +2,7 @@ import { get } from "lodash";
import { define } from "../define";
let fspromises = require("fs").promises;
import { Tools } from "../../main/tools";
import { errorMessage } from "../../main/generalTools";
import { errorMessage } from "../../main/Public/generalTools";
let tools = new Tools();
// Create a shared object
+183 -182
View File
@@ -1,195 +1,196 @@
let fspromises = require('fs').promises;
import { get, cloneDeep } from 'lodash';
import { define } from './define';
import path from 'path';
import { Tools } from '../main/tools';
const { v4: uuidv4 } = require('uuid');
let fspromises = require('fs').promises
import { get, cloneDeep } from 'lodash'
import { define } from './define'
import path from 'path'
import { Tools } from '../main/tools'
const { v4: uuidv4 } = require('uuid')
export class TagDefine {
constructor(global) {
this.global = global;
this.tools = new Tools();
}
constructor(global) {
this.global = global
this.tools = new Tools()
}
/**
* 获取tag选择模式(标签和下拉select)
*/
async getTagSelectModel() {
return {
code: 1,
data:
[
{ label: "标签", value: "tag" },
{ label: "下拉", value: "drop" },
]
/**
* 获取tag选择模式(标签和下拉select)
*/
async getTagSelectModel() {
return {
code: 1,
data: [
{ label: '标签', value: 'tag' },
{ label: '下拉', value: 'drop' }
]
}
}
/**
* 通过指定的类型,获取数据
* @param {*} type default:在代码中写死的 dynamic:用户自定义的 all:写死的和自定义的合并返回
* @param {*} property 要返回的属性的名称,若是传入null,返回整个属性的数据
* @param {*} defaultData 默认数据,默认值为null
* @returns
*/
async getTagDataByTypeAndProperty(type, property, defaultData = null) {
try {
let res = []
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'))
let data = get(tag_setting, property, {})
// 若是传入的属性名为null,直接返回当前tags里面的所有的数据
if (property == null) {
data = tag_setting
}
if (type == 'default') {
// res = get(this, property, defaultData);
} else if (type == 'dynamic') {
res = data
} else if (type == 'all') {
let tmp_arr = cloneDeep(get([], property, defaultData))
tmp_arr = tmp_arr.concat(data)
res = tmp_arr
} else {
throw new Error(`不存在的类型 : ${value}`)
}
if (property) {
res.forEach((item) => {
if (item.show_image && item.show_image != '') {
item.show_image = path.join(define.image_path, item.show_image)
}
})
} else {
// 返回之前,判断里面是不是有预览图片路径
if (res.hasOwnProperty('character_tags')) {
res.character_tags.forEach((item) => {
if (item.show_image && item.show_image != '') {
item.show_image = path.join(define.image_path, item.show_image)
}
})
}
}
/**
* 通过指定的类型,获取数据
* @param {*} type default:在代码中写死的 dynamic:用户自定义的 all:写死的和自定义的合并返回
* @param {*} property 要返回的属性的名称,若是传入null,返回整个属性的数据
* @param {*} defaultData 默认数据,默认值为null
* @returns
*/
async getTagDataByTypeAndProperty(type, property, defaultData = null) {
try {
let res = [];
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'));
let data = get(tag_setting, property, {});
// 若是传入的属性名为null,直接返回当前tags里面的所有的数据
if (property == null) {
data = tag_setting;
}
if (type == "default") {
// res = get(this, property, defaultData);
} else if (type == "dynamic") {
res = data;
} else if (type == "all") {
let tmp_arr = cloneDeep(get([], property, defaultData));
tmp_arr = tmp_arr.concat(data);
res = tmp_arr;
}
else {
throw new Error(`不存在的类型 : ${value}`);
}
// 返回之前,判断里面是不是有预览图片路径
if (res.hasOwnProperty("character_tags")) {
res.character_tags.forEach(item => {
if (item.show_image && item.show_image != "") {
item.show_image = path.join(define.image_path, item.show_image);
}
});
}
if (res.hasOwnProperty("scene_tags")) {
res.scene_tags.forEach(item => {
if (item.show_image && item.show_image != "") {
item.show_image = path.join(define.image_path, item.show_image);
}
});
}
if (res.hasOwnProperty("style_tags")) {
res.style_tags.forEach(item => {
if (item.show_image && item.show_image != "") {
item.show_image = path.join(define.image_path, item.show_image);
}
});
}
return {
code: 1,
data: res
}
} catch (error) {
return {
code: 0,
message: error.toString()
if (res.hasOwnProperty('scene_tags')) {
res.scene_tags.forEach((item) => {
if (item.show_image && item.show_image != '') {
item.show_image = path.join(define.image_path, item.show_image)
}
})
}
}
/**
* 保存gpt指定的属性数据,判断value中的ID是不是存在,存在直接覆盖,不存在追加
* @param {*} value
* @param {*} property
*/
async saveTagPropertyData(value) {
try {
let property = value[1];
value = JSON.parse(value[0]);
let tmp_key = uuidv4();
// 特殊操作。为角色和场景的时候,需要copy图片
if (property == "character_tags" || property == "scene_tags" || property == "style_tags") {
let show_image = value.show_image;
if (show_image && show_image != "") {
let file_name = `c_s/${value.key ? value.key : tmp_key}.png`
let new_image_path = path.join(define.image_path, file_name);
await this.tools.copyFileOrDirectory(show_image, new_image_path);
value.show_image = file_name;
value.children?.forEach(item => {
item.show_image = file_name;
});
}
}
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'));
let tag = get(tag_setting, property, []);
if (value.key) {
// 判断当前ID的数据是否存在,存在覆盖,不存在追加
let index = tag.findIndex(item => item.key == value.key);
value.value = value.key;
if (index < 0) {
// 判断相同名字的数据是不是存在,存在报错
if (tag.some(item => item.label == value.label)) {
throw new Error("已存在相同名称的数据,请修改名称后再保存");
}
tag.push(value);
} else {
tag[index] = value;
}
} else {
// 判断相同名字的数据是不是存在,存在报错
if (tag.some(item => item.label == value.label)) {
throw new Error("已存在相同名称的数据,请修改名称后再保存");
}
value.key = tmp_key;
value.value = value.key;
tag.push(value);
}
tag_setting[property] = tag;
// 写入文件
await fspromises.writeFile(define.tag_setting, JSON.stringify(tag_setting));
return {
code: 1,
message: "保存成功"
}
} catch (error) {
return {
code: 0,
message: error.toString()
if (res.hasOwnProperty('style_tags')) {
res.style_tags.forEach((item) => {
if (item.show_image && item.show_image != '') {
item.show_image = path.join(define.image_path, item.show_image)
}
})
}
}
return {
code: 1,
data: res
}
} catch (error) {
return {
code: 0,
message: error.toString()
}
}
}
/**
* 删除自定义GPT指定属性中的指定ID的数据
* @param {*} id
* @param {*} property
*/
async deleteTagPropertyData(value) {
try {
let property = value[1];
let id = value[0];
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'));
let tags = tag_setting[property] ? tag_setting[property] : [];
// 判断当前ID的数据是否存在,存在删除
let index = tags.findIndex(item => item.key == id);
if (index >= 0) {
tags.splice(index, 1);
}
// 将修改后的数据保存
tag_setting[property] = tags;
// 写入文件
await fspromises.writeFile(define.tag_setting, JSON.stringify(tag_setting));
return {
code: 1,
message: "删除成功"
}
/**
* 保存gpt指定属性数据,判断value中的ID是不是存在,存在直接覆盖,不存在追加
* @param {*} value
* @param {*} property
*/
async saveTagPropertyData(value) {
try {
let property = value[1]
value = JSON.parse(value[0])
let tmp_key = uuidv4()
} catch (error) {
return {
code: 0,
message: error.toString()
}
// 特殊操作。为角色和场景的时候,需要copy图片
if (property == 'character_tags' || property == 'scene_tags' || property == 'style_tags') {
let show_image = value.show_image
if (show_image && show_image != '') {
let file_name = `c_s/${value.key ? value.key : tmp_key}.png`
let new_image_path = path.join(define.image_path, file_name)
await this.tools.copyFileOrDirectory(show_image, new_image_path)
value.show_image = file_name
value.children?.forEach((item) => {
item.show_image = file_name
})
}
}
}
}
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'))
let tag = get(tag_setting, property, [])
if (value.key) {
// 判断当前ID的数据是否存在,存在覆盖,不存在追加
let index = tag.findIndex((item) => item.key == value.key)
value.value = value.key
if (index < 0) {
// 判断相同名字的数据是不是存在,存在报错
if (tag.some((item) => item.label == value.label)) {
throw new Error('已存在相同名称的数据,请修改名称后再保存')
}
tag.push(value)
} else {
tag[index] = value
}
} else {
// 判断相同名字的数据是不是存在,存在报错
if (tag.some((item) => item.label == value.label)) {
throw new Error('已存在相同名称的数据,请修改名称后再保存')
}
value.key = tmp_key
value.value = value.key
tag.push(value)
}
tag_setting[property] = tag
// 写入文件
await fspromises.writeFile(define.tag_setting, JSON.stringify(tag_setting))
return {
code: 1,
message: '保存成功'
}
} catch (error) {
return {
code: 0,
message: error.toString()
}
}
}
/**
* 删除自定义GPT指定属性中的指定ID的数据
* @param {*} id
* @param {*} property
*/
async deleteTagPropertyData(value) {
try {
let property = value[1]
let id = value[0]
// 获取自定义的GPT数据
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'))
let tags = tag_setting[property] ? tag_setting[property] : []
// 判断当前ID的数据是否存在,存在删除
let index = tags.findIndex((item) => item.key == id)
if (index >= 0) {
tags.splice(index, 1)
}
// 将修改后的数据保存
tag_setting[property] = tags
// 写入文件
await fspromises.writeFile(define.tag_setting, JSON.stringify(tag_setting))
return {
code: 1,
message: '删除成功'
}
} catch (error) {
return {
code: 0,
message: error.toString()
}
}
}
}
+8 -6
View File
@@ -17,7 +17,7 @@ type configure = {
proxy?: string
rate?: string
pitch?: string
volume?: string
volumn?: string
}
export class EdgeTTS {
@@ -28,7 +28,7 @@ export class EdgeTTS {
private proxy: string | null | undefined
private rate: string
private pitch: string
private volume: string
private volumn: string
constructor({
voice = 'zh-CN-XiaoyiNeural',
@@ -38,7 +38,7 @@ export class EdgeTTS {
proxy,
rate = 'default',
pitch = 'default',
volume = 'default'
volumn = 'default'
}: configure = {}) {
this.voice = voice
this.lang = lang
@@ -47,7 +47,7 @@ export class EdgeTTS {
this.proxy = proxy
this.rate = rate
this.pitch = pitch
this.volume = volume
this.volumn = volumn
}
async _connectWebSocket(): Promise<WebSocket> {
@@ -138,7 +138,9 @@ export class EdgeTTS {
end: Math.floor((element['Data']['Offset'] + element['Data']['Duration']) / 10000)
})
})
} catch {}
} catch {
throw new Error('解析元数据失败')
}
}
}
})
@@ -148,7 +150,7 @@ export class EdgeTTS {
` +
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="${this.lang}">
<voice name="${this.voice}">
<prosody rate="${this.rate}" pitch="${this.pitch}" volume="${this.volume}">
<prosody rate="${this.rate}" pitch="${this.pitch}" volumn="${this.volumn}">
${text}
</prosody>
</voice>