1. 添加软件高清倍率设置,实现自定义高清倍率(支持两倍、三倍和四倍,默认是两倍)
2. (聚合推文)新增导出草稿。可以依赖做好的草稿文件,只替换图片文件
3. (聚合推文)新增批量生成草稿
4. (聚合推文)修改小说批次任务进行详细界面操作为双击
This commit is contained in:
lq1405 2024-10-23 22:59:29 +08:00
parent f4d042f699
commit 0c5988ed41
22 changed files with 1438 additions and 1227 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "laitool", "name": "laitool",
"version": "3.1.7", "version": "3.1.8",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "laitool", "name": "laitool",
"version": "3.1.7", "version": "3.1.8",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@alicloud/alimt20181012": "^1.2.0", "@alicloud/alimt20181012": "^1.2.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "laitool", "name": "laitool",
"version": "3.1.7", "version": "3.1.8",
"description": "An AI tool for image processing, video processing, and other functions.", "description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "laitool.cn", "author": "laitool.cn",

Binary file not shown.

View File

@ -12,6 +12,7 @@ export class BookModel extends Realm.Object<BookModel> {
oldVideoPath: string | null oldVideoPath: string | null
srtPath: string | null srtPath: string | null
audioPath: string | null audioPath: string | null
draftDepend?: string // 草稿依赖
draftSrtStyle: string | null // 草稿字幕样式 draftSrtStyle: string | null // 草稿字幕样式
backgroundMusic: string | null // 背景音乐ID backgroundMusic: string | null // 背景音乐ID
friendlyReminder: string | null // 友情提示 friendlyReminder: string | null // 友情提示
@ -38,6 +39,7 @@ export class BookModel extends Realm.Object<BookModel> {
oldVideoPath: 'string?', oldVideoPath: 'string?',
srtPath: 'string?', srtPath: 'string?',
audioPath: 'string?', audioPath: 'string?',
draftDepend: "string?",
draftSrtStyle: 'string?', draftSrtStyle: 'string?',
backgroundMusic: 'string?', backgroundMusic: 'string?',
friendlyReminder: 'string?', friendlyReminder: 'string?',

View File

@ -43,6 +43,7 @@ export class BookTaskModel extends Realm.Object<BookTaskModel> {
name: string name: string
generateVideoPath: string | null generateVideoPath: string | null
srtPath: string | null srtPath: string | null
draftDepend?: string // 草稿依赖
audioPath: string | null audioPath: string | null
draftSrtStyle: string | null // 草稿字幕样式 draftSrtStyle: string | null // 草稿字幕样式
backgroundMusic: string | null // 背景音乐ID backgroundMusic: string | null // 背景音乐ID
@ -72,6 +73,7 @@ export class BookTaskModel extends Realm.Object<BookTaskModel> {
name: 'string', name: 'string',
generateVideoPath: 'string?', generateVideoPath: 'string?',
srtPath: 'string?', srtPath: 'string?',
draftDepend: "string?",
audioPath: 'string?', audioPath: 'string?',
draftSrtStyle: 'string?', draftSrtStyle: 'string?',
backgroundMusic: 'string?', backgroundMusic: 'string?',

View File

@ -176,6 +176,27 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
newBookTask[i].messageName = '' newBookTask[i].messageName = ''
} }
} }
// if (oldRealm.schemaVersion < 25) {
// const oldBookTask = oldRealm.objects('BookTaskDetail')
// const newBookTask = newRealm.objects('BookTaskDetail')
// for (let i = 0; i < oldBookTask.length; i++) {
// newBookTask[i].draftDepend = undefined
// }
// }
if (oldRealm.schemaVersion < 26) {
const oldBookTask = oldRealm.objects('BookTask')
const newBookTask = newRealm.objects('BookTask')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].draftDepend = ''
}
}
if (oldRealm.schemaVersion < 27) {
const oldBookTask = oldRealm.objects('Book')
const newBookTask = newRealm.objects('Book')
for (let i = 0; i < oldBookTask.length; i++) {
newBookTask[i].draftDepend = ''
}
}
} }
export class BaseRealmService extends BaseService { export class BaseRealmService extends BaseService {
@ -217,7 +238,7 @@ export class BaseRealmService extends BaseService {
BookTaskDetailModel BookTaskDetailModel
], ],
path: this.dbpath, path: this.dbpath,
schemaVersion: 24, schemaVersion: 27,
migration: migration migration: migration
} }
this.realm = await Realm.open(config) this.realm = await Realm.open(config)

View File

@ -232,7 +232,8 @@ export enum OperateBookType {
BOOK = 'book', // 这个小说的所有批次 BOOK = 'book', // 这个小说的所有批次
BOOKTASK = 'bookTask', // 整个小说批次分镜合并 BOOKTASK = 'bookTask', // 整个小说批次分镜合并
BOOKTASKDETAIL = 'bookTaskDetail', // 单个分镜合并 BOOKTASKDETAIL = 'bookTaskDetail', // 单个分镜合并
UNDERBOOKTASK = 'underBookTask' // 执行小说批次任务的指定ID以及后面的所有的东西 UNDERBOOKTASK = 'underBookTask', // 执行小说批次任务的指定ID以及后面的所有的东西
ASSIGNBOOKTASK = 'assignBookTask' // 指定小说批次任务
} }
export enum CopyImageType { export enum CopyImageType {

View File

@ -241,14 +241,14 @@ export function BookIpc() {
// 高清图片前检查,主要是检查图片大小 // 高清图片前检查,主要是检查图片大小
ipcMain.handle( ipcMain.handle(
DEFINE_STRING.BOOK.CHECK_IMAGE_FILE_SIZE, DEFINE_STRING.BOOK.CHECK_IMAGE_FILE_SIZE,
async (event, id, fileSize, operateBookType) => async (event, id: string | string[], fileSize: number, operateBookType: OperateBookType) =>
await bookImage.CheckImageFileSize(id, fileSize, operateBookType) await bookImage.CheckImageFileSize(id, fileSize, operateBookType)
) )
// 开始执行高清图片 // 开始执行高清图片
ipcMain.handle( ipcMain.handle(
DEFINE_STRING.BOOK.HD_IMAGE, DEFINE_STRING.BOOK.HD_IMAGE,
async (event, id, scale, operateBookType) => await bookImage.HDImage(id, scale, operateBookType) async (event, id: string | string[], scale: number, operateBookType: OperateBookType) => await bookImage.HDImage(id, scale, operateBookType)
) )
// 删除所有的生成图片 // 删除所有的生成图片
@ -310,7 +310,7 @@ export function BookIpc() {
// 将小说任务添加到剪映草稿 // 将小说任务添加到剪映草稿
ipcMain.handle( ipcMain.handle(
DEFINE_STRING.BOOK.ADD_JIANYING_DRAFT, DEFINE_STRING.BOOK.ADD_JIANYING_DRAFT,
async (event, id, operateBookType) => await bookVideo.AddJianyingDraft(id, operateBookType) async (event, id: string | string[], operateBookType: OperateBookType) => await bookVideo.AddJianyingDraft(id, operateBookType)
) )
//#endregion //#endregion
} }

View File

@ -1,335 +1,370 @@
import path from "path"; import path from 'path'
import { define } from "../../define/define"; import { define } from '../../define/define'
import { Tools } from "../tools"; import { Tools } from '../tools'
import { DEFINE_STRING } from "../../define/define_string"; import { DEFINE_STRING } from '../../define/define_string'
import { get, has } from "lodash"; import { get, has } from 'lodash'
const util = require('util'); const util = require('util')
const { spawn, exec } = require('child_process'); const { spawn, exec } = require('child_process')
const execAsync = util.promisify(exec); const execAsync = util.promisify(exec)
const fspromises = require("fs").promises; const fspromises = require('fs').promises
export class PublicMethod { export class PublicMethod {
constructor(global) { constructor(global) {
this.global = global; this.global = global
this.tools = new Tools(); this.tools = new Tools()
}
/**
* 修改config.json文件中的指定的属性
* @param {*} value 0: 要修改的数据 1: 要修改的属性 2: 是否需要解析
* @returns
*/
async SaveConfigJsonProperty(value) {
try {
let data = value[0]
let property = value[1]
let parse = value[2]
if (parse) {
data = JSON.parse(value[0])
}
let json_path = path.join(global.config.project_path, 'scripts/config.json')
// 判断文件是不是存在
let isExit = await this.tools.checkExists(json_path)
let json_data = {}
if (!isExit) {
const dirPath = path.dirname(json_path)
await fspromises.mkdir(dirPath, { recursive: true })
await fspromises.writeFile(json_path, '{}')
} else {
const o_data = await fspromises.readFile(json_path, 'utf8')
// 将读取的 JSON 字符串转换为 JavaScript 对象
let obj = JSON.parse(o_data)
json_data = obj
}
json_data[property] = data
await fspromises.writeFile(json_path, JSON.stringify(json_data))
return {
code: 1
}
} catch (error) {
throw error
} }
}
/** /**
* 修改config.json文件中的指定的属性 * 返回当前项目的config.json文件中的指定的属性信息若是没有传入属性则返回所有的信息
* @param {*} value 0: 要修改的数据 1: 要修改的属性 2: 是否需要解析 * @param {Array} value 0 要获取的属性 1 返回的默认值
* @returns * @param {Boolean} ckeck 是否需要校验属性不存在
*/ * @returns
async SaveConfigJsonProperty(value) { */
async GetConfigJson(value, ckeck = true) {
try {
value = JSON.parse(value)
let srt_config_path = path.join(global.config.project_path, 'scripts/config.json')
let data = await this.tools.getJsonFilePropertyValue(
srt_config_path,
value[0],
value[1],
ckeck
)
return {
code: 1,
data: data
}
} catch (error) {
throw error
}
}
/**
* 修改生成图片的任务队列数据
* @param {传入的要修改的数据数组} value
*/
async ModifyImageTaskList(value) {
this.global.fileQueue.enqueue(
async () => {
try { try {
let data = value[0]; let task_list_path = path.join(this.global.config.project_path, 'scripts/task_list.json')
let property = value[1]; let isE = await this.tools.checkExists(task_list_path)
let parse = value[2]; if (!isE) {
if (parse) { throw new Error('任务队列文件不存在。请先添加 批次任务')
data = JSON.parse(value[0]) }
} let task_list_json = JSON.parse(await fspromises.readFile(task_list_path, 'utf-8'))
let json_path = path.join(global.config.project_path, "scripts/config.json"); // 循环循环数据。修改
// 判断文件是不是存在 for (let i = 0; i < value.length; i++) {
let isExit = await this.tools.checkExists(json_path); const element = value[i]
let json_data = {}; let index = task_list_json.task_list.findIndex((item) => item.id == element.id)
if (!isExit) { task_list_json.task_list[index] = element
const dirPath = path.dirname(json_path); }
await fspromises.mkdir(dirPath, { recursive: true }); await fspromises.writeFile(task_list_path, JSON.stringify(task_list_json))
await fspromises.writeFile(json_path, '{}');
}
else {
const o_data = await fspromises.readFile(json_path, 'utf8');
// 将读取的 JSON 字符串转换为 JavaScript 对象
let obj = JSON.parse(o_data);
json_data = obj;
}
json_data[property] = data;
await fspromises.writeFile(json_path, JSON.stringify(json_data));
return {
code: 1
}
} catch (error) { } catch (error) {
throw error; throw error
} }
} },
'modifyFile',
/** 'modifyFile',
* 返回当前项目的config.json文件中的指定的属性信息若是没有传入属性则返回所有的信息 'task_list'
* @param {Array} value 0 要获取的属性 1 返回的默认值 )
* @param {Boolean} ckeck 是否需要校验属性不存在 this.global.fileQueue.setSubBatchCompletionCallback(
* @returns 'modifyFile',
*/ 'task_list',
async GetConfigJson(value, ckeck = true) { async (failedTasks) => {
try { // 报错
value = JSON.parse(value) if (failedTasks.length > 0) {
let srt_config_path = path.join(global.config.project_path, "scripts/config.json"); let message = ''
let data = await this.tools.getJsonFilePropertyValue(srt_config_path, value[0], value[1], ckeck); failedTasks.forEach(({ taskId, error }) => {
return { message += `${taskId}-, \n 错误信息: ${error}` + '\n'
code: 1, })
data: data throw new Error(message)
} // this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
} catch (error) { // code: 0,
throw error; // message: message
// })
} }
// else {
// this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
// code: 1,
// message: "修改成功"
// })
// }
return true
}
)
}
/**
* 高清指定的文件夹
* @param {要高清的文件夹} folder
*/
async ImproveFolder(folder) {
try {
let bakPath = path.join(this.global.config.project_path, 'tmp/bak')
let oldInput = path.join(this.global.config.project_path, 'tmp/' + folder)
let newInput = path.join(this.global.config.project_path, 'tmp/bak/' + folder)
// 创建文件夹
let existFolder = await this.tools.checkExists(bakPath)
if (!existFolder) {
await fspromises.mkdir(bakPath, { recursive: true })
}
let isExistNewFolder = await this.tools.checkExists(newInput)
if (isExistNewFolder) {
await fspromises.rm(newInput, { recursive: true, force: true })
}
// 备份文件
await fspromises.rename(oldInput, newInput)
//创建同名的文件,用作输出
await fspromises.mkdir(oldInput, { recursive: true })
// 开始高清
let command = `"${path.join(
define.package_path,
'Improve/rnv.exe'
)}" -i "${newInput}" -o "${oldInput}" -s ${this.global.config.hdScale ?? 2}`
let out = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' })
console.log(out)
await this.ModifyTaskStatus('out_folder', folder, 'video_improvied')
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.VIDEO_GENERATE_STATUS_REFRESH, {
out_folder: folder,
status: 'video_improvied'
})
} catch (error) {
await this.ModifyTaskStatus('out_folder', folder, 'video_improvie_error')
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.VIDEO_GENERATE_STATUS_REFRESH, {
out_folder: folder,
status: 'video_improvie_error'
})
throw error
} }
}
/** /**
* 修改生成图片的任务队列数据 * 生成SD相对的JSON文件删除反推的txt文件
* @param {传入的要修改的数据数组} value */
*/ async AddWebuiJson() {
async ModifyImageTaskList(value) { try {
this.global.fileQueue.enqueue(async () => { // 读取所有txt文件
try { let txtfile = await this.tools.getFilesWithExtensions(
let task_list_path = path.join(this.global.config.project_path, "scripts/task_list.json"); path.join(this.global.config.project_path, 'tmp/input_crop'),
let isE = await this.tools.checkExists(task_list_path); '.txt'
if (!isE) { )
throw new Error("任务队列文件不存在。请先添加 批次任务"); let image = await this.tools.getFilesWithExtensions(
} path.join(this.global.config.project_path, 'tmp/input_crop'),
let task_list_json = JSON.parse(await fspromises.readFile(task_list_path, "utf-8")); '.png'
// 循环循环数据。修改 )
for (let i = 0; i < value.length; i++) { let promptJson = await this.tools.getFilesWithExtensions(
const element = value[i]; path.join(this.global.config.project_path, 'tmp/input_crop'),
let index = task_list_json.task_list.findIndex(item => item.id == element.id); '.json'
task_list_json.task_list[index] = element; )
}
await fspromises.writeFile(task_list_path, JSON.stringify(task_list_json));
} catch (error) {
throw error;
}
}, "modifyFile", "modifyFile", "task_list")
this.global.fileQueue.setSubBatchCompletionCallback("modifyFile", "task_list", async (failedTasks) => {
// 报错
if (failedTasks.length > 0) {
let message = "";
failedTasks.forEach(({ taskId, error }) => {
message += `${taskId}-, \n 错误信息: ${error}` + '\n';
});
throw new Error(message);
// this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
// code: 0,
// message: message
// })
}
// else {
// this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
// code: 1,
// message: "修改成功"
// })
// }
return true;
})
}
// json 已经存在,不做后续处理
/** if (image.length == promptJson.length) {
* 高清指定的文件夹 return {
* @param {要高清的文件夹} folder code: 1
*/
async ImproveFolder(folder) {
try {
let bakPath = path.join(this.global.config.project_path, "tmp/bak");
let oldInput = path.join(this.global.config.project_path, "tmp/" + folder);
let newInput = path.join(this.global.config.project_path, "tmp/bak/" + folder)
// 创建文件夹
let existFolder = await this.tools.checkExists(bakPath);
if (!existFolder) {
await fspromises.mkdir(bakPath, { recursive: true });
}
let isExistNewFolder = await this.tools.checkExists(newInput);
if (isExistNewFolder) {
await fspromises.rm(newInput, { recursive: true, force: true });
}
// 备份文件
await fspromises.rename(oldInput, newInput);
//创建同名的文件,用作输出
await fspromises.mkdir(oldInput, { recursive: true });
// 开始高清
let command = `"${path.join(define.package_path, "Improve/rnv.exe")}" -i "${newInput}" -o "${oldInput}"`;
let out = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' });
console.log(out);
await this.ModifyTaskStatus('out_folder', folder, "video_improvied");
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.VIDEO_GENERATE_STATUS_REFRESH, {
out_folder: folder,
status: "video_improvied"
})
} catch (error) {
await this.ModifyTaskStatus('out_folder', folder, "video_improvie_error");
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.VIDEO_GENERATE_STATUS_REFRESH, {
out_folder: folder,
status: "video_improvie_error"
})
throw error;
} }
} }
/** if (txtfile.length != image.length) {
* 生成SD相对的JSON文件删除反推的txt文件 throw new Error('关键词文件和图片数量对不上,请检查!!')
*/ }
async AddWebuiJson() { let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'))
try {
// 读取所有txt文件
let txtfile = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.txt');
let image = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.png');
let promptJson = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.json');
// json 已经存在,不做后续处理 for (let i = 0; i < image.length; i++) {
if (image.length == promptJson.length) { const element = image[i]
return { let txtpath = element.split('.png')[0] + '.txt'
code: 1, let prompt = await fspromises.readFile(txtpath, 'utf-8')
} // console.log(txtpath)
} let obj = {}
obj.model = sd_config.setting.type
if (txtfile.length != image.length) { obj.api = sd_config.setting.webui_api_url + 'sdapi/v1/img2img'
throw new Error("关键词文件和图片数量对不上,请检查!!") obj.webui_config = {
} sampler_name: sd_config.webui.sampler_name,
let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8')); prompt: prompt + ',' + sd_config.webui.prompt,
negative_prompt: sd_config.webui.negative_prompt,
for (let i = 0; i < image.length; i++) { batch_size: 1,
const element = image[i]; steps: sd_config.webui.steps,
let txtpath = element.split('.png')[0] + '.txt'; cfg_scale: sd_config.webui.cfg_scale,
let prompt = await fspromises.readFile(txtpath, 'utf-8'); denoising_strength: sd_config.webui.denoising_strength,
// console.log(txtpath) width: sd_config.webui.width,
let obj = {} height: sd_config.webui.height,
obj.model = sd_config.setting.type; seed: sd_config.setting.seed,
obj.api = sd_config.setting.webui_api_url + 'sdapi/v1/img2img'; init_images: element
obj.webui_config = {
sampler_name: sd_config.webui.sampler_name,
prompt: prompt + ',' + sd_config.webui.prompt,
negative_prompt: sd_config.webui.negative_prompt,
batch_size: 1,
steps: sd_config.webui.steps,
cfg_scale: sd_config.webui.cfg_scale,
denoising_strength: sd_config.webui.denoising_strength,
width: sd_config.webui.width,
height: sd_config.webui.height,
seed: sd_config.setting.seed,
init_images: element,
}
obj.adetailer = sd_config.webui.adetailer;
// 写入
await fspromises.writeFile(element + '.json', JSON.stringify(obj));
// 删除对应的txt文件
await fspromises.unlink(txtpath);
}
return {
code: 1,
}
} catch (error) {
throw error;
} }
} obj.adetailer = sd_config.webui.adetailer
/** // 写入
* 获取当前项目的生图任务列表 await fspromises.writeFile(element + '.json', JSON.stringify(obj))
*/ // 删除对应的txt文件
async GetImageTask() { await fspromises.unlink(txtpath)
try { }
let json_path = path.join(this.global.config.project_path, "scripts/task_list.json");
let isExit = await this.tools.checkExists(json_path); return {
if (!isExit) { code: 1
return { }
code: 1, } catch (error) {
data: null throw error
} }
} }
let json_data = JSON.parse(await fspromises.readFile(json_path));
return { /**
code: 1, * 获取当前项目的生图任务列表
data: json_data */
} async GetImageTask() {
} catch (error) { try {
return { let json_path = path.join(this.global.config.project_path, 'scripts/task_list.json')
code: 0, let isExit = await this.tools.checkExists(json_path)
message: error if (!isExit) {
} return {
code: 1,
data: null
} }
}
let json_data = JSON.parse(await fspromises.readFile(json_path))
return {
code: 1,
data: json_data
}
} catch (error) {
return {
code: 0,
message: error
}
} }
}
/**
/** * 修改任务的状态
* 修改任务的状态 * @param {查找的类型 id out_folder} type
* @param {查找的类型 id out_folder} type * @param {查找的类型} id
* @param {查找的类型} id * @param {新的状态} newStatus
* @param {新的状态} newStatus */
*/ async ModifyTaskStatus(type, id, newStatus) {
async ModifyTaskStatus(type, id, newStatus) { this.global.fileQueue.enqueue(
this.global.fileQueue.enqueue(async () => { async () => {
try {
// 将修改数据写入到一个并发为 1 的队列中
let tmp_task = await fspromises.readFile(path.join(this.global.config.project_path, 'scripts/task_list.json'), 'utf-8');
console.log(tmp_task)
let task = JSON.parse(tmp_task);
if (type == "id") {
let index = task.task_list.findIndex(item => item.id == id);
if (index < 0) {
throw new Error("传入的数据未找到");
} else {
task.task_list[index].status = newStatus;
}
} else if (type == "out_folder") {
let index = task.task_list.findIndex(item => item.out_folder == id);
if (index < 0) {
throw new Error("传入的数据未找到");
} else {
task.task_list[index].status = newStatus;
}
} else {
throw new Error("输入类型错误")
}
await fspromises.writeFile(path.join(this.global.config.project_path, 'scripts/task_list.json'), JSON.stringify(task));
} catch (error) {
throw error;
}
}, "modifyFile", "modifyFile", "task_list")
this.global.fileQueue.setSubBatchCompletionCallback("modifyFile", "task_list", async (failedTasks) => {
// 报错
if (failedTasks.length > 0) {
let message = "";
failedTasks.forEach(({ taskId, error }) => {
message += `${taskId}-, \n 错误信息: ${error}` + '\n';
});
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
code: 0,
message: message
})
}
})
}
/**
* 获取指定文件夹下面特定条件的文件夹
* @param {指定的文件夹目录} parentFolder
* @param {查询条件 start end include} condition
* @param {查询的值} value
* @returns
*/
async getSubFolderList(parentFolder, condition, value) {
try { try {
// console.log(value); // 将修改数据写入到一个并发为 1 的队列中
let folders = await fspromises.readdir(parentFolder, { withFileTypes: true }); let tmp_task = await fspromises.readFile(
folders = folders.filter(item => item.isDirectory()) path.join(this.global.config.project_path, 'scripts/task_list.json'),
.map(item => item.name) 'utf-8'
)
if (condition == "start") { console.log(tmp_task)
folders = folders.filter(item => item.startsWith(value)); let task = JSON.parse(tmp_task)
} else if (condition == "end") { if (type == 'id') {
folders = folders.filter(item => item.endsWith(value)); let index = task.task_list.findIndex((item) => item.id == id)
} else if (condition == "include") { if (index < 0) {
//包含过滤 throw new Error('传入的数据未找到')
folders = folders.filter(item => item.includes(value));
} else { } else {
throw new Error("条件参数错误"); task.task_list[index].status = newStatus
} }
return folders; } else if (type == 'out_folder') {
let index = task.task_list.findIndex((item) => item.out_folder == id)
if (index < 0) {
throw new Error('传入的数据未找到')
} else {
task.task_list[index].status = newStatus
}
} else {
throw new Error('输入类型错误')
}
await fspromises.writeFile(
path.join(this.global.config.project_path, 'scripts/task_list.json'),
JSON.stringify(task)
)
} catch (error) { } catch (error) {
throw error; throw error
} }
},
'modifyFile',
'modifyFile',
'task_list'
)
this.global.fileQueue.setSubBatchCompletionCallback(
'modifyFile',
'task_list',
async (failedTasks) => {
// 报错
if (failedTasks.length > 0) {
let message = ''
failedTasks.forEach(({ taskId, error }) => {
message += `${taskId}-, \n 错误信息: ${error}` + '\n'
})
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
code: 0,
message: message
})
}
}
)
}
/**
* 获取指定文件夹下面特定条件的文件夹
* @param {指定的文件夹目录} parentFolder
* @param {查询条件 start end include} condition
* @param {查询的值} value
* @returns
*/
async getSubFolderList(parentFolder, condition, value) {
try {
// console.log(value);
let folders = await fspromises.readdir(parentFolder, { withFileTypes: true })
folders = folders.filter((item) => item.isDirectory()).map((item) => item.name)
if (condition == 'start') {
folders = folders.filter((item) => item.startsWith(value))
} else if (condition == 'end') {
folders = folders.filter((item) => item.endsWith(value))
} else if (condition == 'include') {
//包含过滤
folders = folders.filter((item) => item.includes(value))
} else {
throw new Error('条件参数错误')
}
return folders
} catch (error) {
throw error
} }
} }
}

View File

@ -101,22 +101,30 @@ export class BookImage {
* @param scale * @param scale
* @param operateBookType BOOKBOOKTASK两种 * @param operateBookType BOOKBOOKTASK两种
*/ */
async HDImage(id: string, scale: number, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> { async HDImage(id: string | string[], scale: number, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
try { try {
if (scale <= 0 || scale > 4) { if (scale <= 0 || scale > 4) {
throw new Error('高清倍率只能是234') throw new Error('高清倍率只能是234')
} }
let bookTasks = undefined as Book.SelectBookTask[] let bookTasks = [] as Book.SelectBookTask[]
if (operateBookType == OperateBookType.BOOK) { if (operateBookType == OperateBookType.BOOK) {
// 获取所有的小说批次任务 // 获取所有的小说批次任务
bookTasks = (await this.bookServiceBasic.GetBookTaskData({ bookTasks = (await this.bookServiceBasic.GetBookTaskData({
bookId: id bookId: id as string
})).bookTasks })).bookTasks
} else if (operateBookType == OperateBookType.BOOKTASK) { } else if (operateBookType == OperateBookType.BOOKTASK) {
// 获取当前的小说批次任务 // 获取当前的小说批次任务
bookTasks = (await this.bookServiceBasic.GetBookTaskData({ bookTasks = (await this.bookServiceBasic.GetBookTaskData({
id: id id: id as string
})).bookTasks })).bookTasks
} else if (operateBookType == OperateBookType.ASSIGNBOOKTASK) {
for (let i = 0; i < id.length; i++) {
const element = id[i];
let tmpBookTask = (await this.bookServiceBasic.GetBookTaskData({
id: element
})).bookTasks
bookTasks.push(...tmpBookTask)
}
} else { } else {
throw new Error("不支持的操作类型,请检查") throw new Error("不支持的操作类型,请检查")
} }
@ -195,20 +203,29 @@ export class BookImage {
* @param fileSize * @param fileSize
* @param operateBookType BOOKBOOKTASK两种 * @param operateBookType BOOKBOOKTASK两种
*/ */
async CheckImageFileSize(id: string, fileSize: number, operateBookType: OperateBookType) { async CheckImageFileSize(id: string | string[], fileSize: number, operateBookType: OperateBookType) {
try { try {
let bookTasks = undefined as Book.SelectBookTask[] let bookTasks = [] as Book.SelectBookTask[]
if (operateBookType == OperateBookType.BOOK) { if (operateBookType == OperateBookType.BOOK) {
// 获取所有的小说批次任务 // 获取所有的小说批次任务
bookTasks = (await this.bookServiceBasic.GetBookTaskData({ bookTasks = (await this.bookServiceBasic.GetBookTaskData({
bookId: id bookId: id as string
})).bookTasks })).bookTasks
} else if (operateBookType == OperateBookType.BOOKTASK) { } else if (operateBookType == OperateBookType.BOOKTASK) {
// 获取当前的小说批次任务 // 获取当前的小说批次任务
bookTasks = (await this.bookServiceBasic.GetBookTaskData({ bookTasks = (await this.bookServiceBasic.GetBookTaskData({
id: id id: id as string
})).bookTasks })).bookTasks
} else { } else if (operateBookType == OperateBookType.ASSIGNBOOKTASK) {
for (let i = 0; i < id.length; i++) {
const element = id[i];
let tempBookTask = (await this.bookServiceBasic.GetBookTaskData({
id: element
})).bookTasks
bookTasks.push(...tempBookTask)
}
}
else {
throw new Error("不支持的操作类型,请检查") throw new Error("不支持的操作类型,请检查")
} }

View File

@ -1,38 +1,24 @@
import { OperateBookType } from "../../../define/enum/bookEnum"; import { OperateBookType } from "../../../define/enum/bookEnum";
import { Book } from "../../../model/book"; import { Book } from "../../../model/book";
import { errorMessage, successMessage } from "../../Public/generalTools"; import { errorMessage, successMessage } from "../../Public/generalTools";
import { BookService } from "../../../define/db/service/Book/bookService";
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
import { GeneralResponse } from "../../../model/generalResponse"; import { GeneralResponse } from "../../../model/generalResponse";
import { Setting } from '../../../main/setting/setting' import { Setting } from '../../../main/setting/setting'
import path from 'path' import path from 'path'
import { CheckFolderExistsOrCreate } from "../../../define/Tools/file"; import { CheckFolderExistsOrCreate } from "../../../define/Tools/file";
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
import fs from 'fs' import fs from 'fs'
import { ClipDraft } from '../../Public/clipDraft' import { ClipDraft } from '../../Public/clipDraft'
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
import { isEmpty } from "lodash";
import JianyingService from "../jianying/jianyingService";
export class BookVideo { export class BookVideo {
bookService: BookService
bookTaskService: BookTaskService
setting: Setting setting: Setting
bookTaskDetailService: BookTaskDetailService
bookServiceBasic: BookServiceBasic bookServiceBasic: BookServiceBasic
jianyingService: JianyingService
constructor() { constructor() {
this.setting = new Setting(global) this.setting = new Setting(global)
this.bookServiceBasic = new BookServiceBasic() this.bookServiceBasic = new BookServiceBasic()
} this.jianyingService = new JianyingService()
async InitService() {
if (!this.bookService) {
this.bookService = await BookService.getInstance()
}
if (!this.bookTaskService) {
this.bookTaskService = await BookTaskService.getInstance()
}
if (!this.bookTaskDetailService) {
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
}
} }
@ -44,23 +30,22 @@ export class BookVideo {
async UseBookVideoDataToBookTask(id: string, operateBookType: OperateBookType) { async UseBookVideoDataToBookTask(id: string, operateBookType: OperateBookType) {
try { try {
console.log(id, operateBookType) console.log(id, operateBookType)
await this.InitService();
let book = undefined as Book.SelectBook; let book = undefined as Book.SelectBook;
let bookTasks = undefined as Book.SelectBookTask[]; let bookTasks = undefined as Book.SelectBookTask[];
if (operateBookType == OperateBookType.BOOK) { if (operateBookType == OperateBookType.BOOK) {
book = this.bookService.GetBookDataById(id); book = await this.bookServiceBasic.GetBookDataById(id);
if (book == null) { if (book == null) {
throw new Error('未找到对应的小说') throw new Error('未找到对应的小说')
} }
bookTasks = this.bookTaskService.GetBookTaskData({ bookTasks = (await this.bookServiceBasic.GetBookTaskData({
bookId: id, bookId: id,
}).data; })).bookTasks;
} else if (operateBookType == OperateBookType.BOOKTASK) { } else if (operateBookType == OperateBookType.BOOKTASK) {
let bookTask = this.bookTaskService.GetBookTaskDataById(id); let bookTask = await this.bookServiceBasic.GetBookTaskDataById(id);
if (bookTask == null) { if (bookTask == null) {
throw new Error('未找到对应的小说任务') throw new Error('未找到对应的小说任务')
} }
book = this.bookService.GetBookDataById(bookTask.bookId); book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
if (book == null) { if (book == null) {
throw new Error('未找到对应的小说') throw new Error('未找到对应的小说')
} }
@ -117,9 +102,9 @@ export class BookVideo {
await CheckFolderExistsOrCreate(path.dirname(configPath)); await CheckFolderExistsOrCreate(path.dirname(configPath));
// 开始配置 // 开始配置
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({ let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
bookTaskId: bookTask.id bookTaskId: bookTask.id
}).data; });
let configData = { let configData = {
srt_time_information: [], srt_time_information: [],
@ -144,14 +129,7 @@ export class BookVideo {
start_time: element.startTime, start_time: element.startTime,
end_time: element.endTime, end_time: element.endTime,
timeLimit: `${element.startTime} -- ${element.endTime}`, timeLimit: `${element.startTime} -- ${element.endTime}`,
subValue: element.subValue?.map(item => { subValue: element.subValue,
return {
start_time: item.startTime,
end_time: item.endTime,
srt_value: item.srtValue,
id: item.id
}
}),
character_tags: [], character_tags: [],
gpt_prompt: element.gptPrompt, gpt_prompt: element.gptPrompt,
mjMessage: element.mjMessage, mjMessage: element.mjMessage,
@ -179,28 +157,29 @@ export class BookVideo {
* @param operateBookType * @param operateBookType
* @returns * @returns
*/ */
async AddJianyingDraft(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> { async AddJianyingDraft(id: string | string[], operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
try { try {
await this.InitService();
console.log(id, operateBookType) console.log(id, operateBookType)
let book = undefined as Book.SelectBook let book = undefined as Book.SelectBook
let bookTasks = undefined as Book.SelectBookTask[] let bookTasks = [] as Book.SelectBookTask[]
if (operateBookType == OperateBookType.BOOK) { if (operateBookType == OperateBookType.ASSIGNBOOKTASK) {
book = this.bookService.GetBookDataById(id); if (id.length <= 0) {
if (book == null) { throw new Error("没有找到小说批次任务,请检查");
throw new Error("没有找到对应的小说数据,请检查"); }
for (let i = 0; i < id.length; i++) {
const element = id[i];
let tempBookTask = await this.bookServiceBasic.GetBookTaskDataById(element as string);
bookTasks.push(tempBookTask)
book = await this.bookServiceBasic.GetBookDataById(tempBookTask.bookId);
} }
bookTasks = this.bookTaskService.GetBookTaskData({
bookId: id
}).data.bookTasks
} else if (operateBookType == OperateBookType.BOOKTASK) { } else if (operateBookType == OperateBookType.BOOKTASK) {
// 直接获取对应的数据 // 直接获取对应的数据
let tempBookTask = this.bookTaskService.GetBookTaskDataById(id); let tempBookTask = await this.bookServiceBasic.GetBookTaskDataById(id as string);
if (tempBookTask == null) { if (tempBookTask == null) {
throw new Error("没有找到小说批次任务,请检查"); throw new Error("没有找到小说批次任务,请检查");
} }
bookTasks = [tempBookTask] bookTasks = [tempBookTask]
book = this.bookService.GetBookDataById(tempBookTask.bookId); book = await this.bookServiceBasic.GetBookDataById(tempBookTask.bookId);
if (book == null) { if (book == null) {
throw new Error throw new Error
} }
@ -213,26 +192,38 @@ export class BookVideo {
} }
// 判断是不是生成单个,每次生成都要修改一下配置文件 // 判断是不是生成单个,每次生成都要修改一下配置文件
// TODO 后面这个地方要修改
// 调用生成草稿的方法 // 调用生成草稿的方法
let result = [] let result = []
for (let i = 0; i < bookTasks.length; i++) { for (let i = 0; i < bookTasks.length; i++) {
const element = bookTasks[i]; const element = bookTasks[i];
await this.GenerateConfigFile(book, element); // 判断是不是又依赖的草稿,又依赖的草稿,对于依赖的草稿进行操作
// 数据处理完毕,开始输出
let clipDraft = new ClipDraft(global, [element.name, { if ((!isEmpty(element.draftDepend) && operateBookType != OperateBookType.ASSIGNBOOKTASK) || (operateBookType == OperateBookType.ASSIGNBOOKTASK && !isEmpty(book.draftDepend))) {
srt_path: element.srtPath, let draft_name = `${book.name}_${element.name}`;
audio_path: element.audioPath, if (draft_name == element.draftDepend) {
draft_srt_style: element.draftSrtStyle ? element.draftSrtStyle : "0", throw new Error("生成的草稿名称和依赖的草稿名称一样,请检查");
background_music: element.backgroundMusic, }
friendly_reminder: element.friendlyReminder ? element.friendlyReminder : "0", await this.jianyingService.GenerateDraftFromDepend(
}]) operateBookType == OperateBookType.ASSIGNBOOKTASK ? book.draftDepend : element.draftDepend,
let res = await clipDraft.addDraft(); element.imageFolder, draft_name);
if (res.code == 0) { result.push(draft_name);
throw new Error(res.message) } else {
await this.GenerateConfigFile(book, element);
// 数据处理完毕,开始输出
let clipDraft = new ClipDraft(global, [element.name, {
srt_path: operateBookType == OperateBookType.ASSIGNBOOKTASK ? book.srtPath : element.srtPath,
audio_path: operateBookType == OperateBookType.ASSIGNBOOKTASK ? book.audioPath : element.audioPath,
draft_srt_style: operateBookType == OperateBookType.ASSIGNBOOKTASK ? (book.draftSrtStyle ? book.draftSrtStyle : '0') : (element.draftSrtStyle ? element.draftSrtStyle : "0"),
background_music: operateBookType == OperateBookType.ASSIGNBOOKTASK ? book.backgroundMusic : element.backgroundMusic,
friendly_reminder: operateBookType == OperateBookType.ASSIGNBOOKTASK ? (book.friendlyReminder ? book.bookFolderPath : '0') : (element.friendlyReminder ? element.friendlyReminder : "0"),
}])
let res = await clipDraft.addDraft();
if (res.code == 0) {
throw new Error(res.message)
}
result.push(res.draft_name);
} }
result.push(res.draft_name);
} }
return successMessage(result, `${result.join('\n')} ${'\n'} 剪映草稿添加成功`, "BookTask_AddJianyingDraft") return successMessage(result, `${result.join('\n')} ${'\n'} 剪映草稿添加成功`, "BookTask_AddJianyingDraft")

View File

@ -1,5 +1,5 @@
import path from 'path'; import path from 'path';
import { CheckFileOrDirExist, DeleteFolderAllFile } from '../../../define/Tools/file'; import { CheckFileOrDirExist, CopyFileOrFolder, DeleteFolderAllFile, GetFilesWithExtensions } from '../../../define/Tools/file';
import fs from "fs"; import fs from "fs";
import { ValidateJson } from '../../../define/Tools/validate'; import { ValidateJson } from '../../../define/Tools/validate';
import { FfmpegOptions } from '../ffmpegOptions'; import { FfmpegOptions } from '../ffmpegOptions';
@ -38,7 +38,7 @@ class JianyingService {
* @param projectDir * @param projectDir
* @param packagePath * @param packagePath
*/ */
async GetDraftFrameAndText(draftDir: string, projectDir: string, packagePath: string) { public async GetDraftFrameAndText(draftDir: string, projectDir: string, packagePath: string) {
try { try {
// 获取草稿文件路径 // 获取草稿文件路径
let draftJsonPath = path.resolve(draftDir, "draft_content.json"); let draftJsonPath = path.resolve(draftDir, "draft_content.json");
@ -101,6 +101,81 @@ class JianyingService {
} }
} }
/**
*
* @param draftName
* @param imageFolder
* 1稿
* 2稿
* 3稿
* 3
* 3
*/
public async GenerateDraftFromDepend(dependDraftName: string, imageFolder: string, draftName: string) {
console.log(draftName);
let dependDraftPath = path.resolve(global.config.draft_path, dependDraftName);
if (!await CheckFileOrDirExist(dependDraftPath)) {
throw new Error("依赖的草稿文件不存在,请检查");
}
let draftPath = path.resolve(global.config.draft_path, draftName);
if (await CheckFileOrDirExist(draftPath)) {
// 删除文件夹
await DeleteFolderAllFile(draftPath, true);
}
// 复制
await CopyFileOrFolder(dependDraftPath, draftPath)
let images = await GetFilesWithExtensions(imageFolder, ['.png']);
// 开始处理数据
let draftJsonPath = path.resolve(draftPath, "draft_content.json");
if (!await CheckFileOrDirExist(draftJsonPath)) {
throw new Error("剪映草稿文件数据文件不存在,请先检查");
}
// 读取草稿文件内容
let draftJsonString = await fs.promises.readFile(draftJsonPath, "utf-8");
if (!ValidateJson(draftJsonString)) {
throw new Error("剪映草稿文件格式错误,请检查");
}
let draftJson = JSON.parse(draftJsonString);
let draftTracks = draftJson.tracks;
if (draftTracks.length <= 0) {
throw new Error("剪映草稿文件格式错误,没有轨道,请检查");
}
let videoTrack = draftTracks[0];// 只处理主轨道
if (videoTrack.type !== "video") {
throw new Error("剪映草稿文件格式错误主轨道不是Video请检查");
}
let videoTrackSegments = videoTrack.segments;
if (videoTrackSegments.length <= 0) {
throw new Error("剪映草稿文件格式错误,主轨道没有对应的图片节点,请检查");
}
let segmentMaterialNodes = [];
for (let i = 0; i < videoTrackSegments.length; i++) {
const element = videoTrackSegments[i];
let materialId = element.material_id;
let materialNode = this.FindNode(draftJson.materials.videos, "id", materialId);
segmentMaterialNodes.push(materialNode);
}
if (images.length !== segmentMaterialNodes.length) {
throw new Error("当前新增的任务对应的图片数量和依赖的草稿的主轨道的图片数量不一致,请检查");
}
// 直接修改
for (let i = 0; i < segmentMaterialNodes.length; i++) {
const element = segmentMaterialNodes[i];
if (!images[i]) {
throw new Error("图片数量不对应,请检查");
}
element.path = images[i];
}
// 好了 写出草稿文件
await fs.promises.writeFile(draftJsonPath, JSON.stringify(draftJson), "utf-8");
}
/** /**
* *
* @param nodes * @param nodes

View File

@ -39,5 +39,6 @@ declare namespace SoftwareSettingModel {
space_image: string = undefined // 空白图片 space_image: string = undefined // 空白图片
gpt_key: string = undefined // GPT KEY, gpt_key: string = undefined // GPT KEY,
laiApiSelect: string = undefined // LaiAPI选择 laiApiSelect: string = undefined // LaiAPI选择
hdScale: number = 2 // HD缩放
} }
} }

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

@ -13,6 +13,7 @@ declare namespace Book {
oldVideoPath?: string, oldVideoPath?: string,
srtPath?: string, srtPath?: string,
audioPath?: string, audioPath?: string,
draftDepend?: string, // 草稿依赖
imageFolder?: string, imageFolder?: string,
draftSrtStyle?: string | null // 草稿字幕样式 draftSrtStyle?: string | null // 草稿字幕样式
backgroundMusic?: string | null // 背景音乐ID backgroundMusic?: string | null // 背景音乐ID
@ -54,6 +55,7 @@ declare namespace Book {
generateVideoPath?: string, generateVideoPath?: string,
srtPath?: string, srtPath?: string,
audioPath?: string, audioPath?: string,
draftDepend?: string,
draftSrtStyle?: string | null // 草稿字幕样式 draftSrtStyle?: string | null // 草稿字幕样式
backgroundMusic?: string | null // 背景音乐ID backgroundMusic?: string | null // 背景音乐ID
friendlyReminder?: string | null // 友情提示 friendlyReminder?: string | null // 友情提示
@ -147,6 +149,7 @@ declare namespace Book {
bookTaskId?: string bookTaskId?: string
videoPath?: string // 视频地址 videoPath?: string // 视频地址
audioPath?: string // 音频地址 audioPath?: string // 音频地址
draftDepend?: string // 草稿依赖
word?: string // 文案 word?: string // 文案
oldImage?: string // 旧图片用于SD的图生图 oldImage?: string // 旧图片用于SD的图生图
afterGpt?: string // GPT生成的文案 afterGpt?: string // GPT生成的文案

View File

@ -239,7 +239,7 @@ const book = {
await ipcRenderer.invoke(DEFINE_STRING.BOOK.GENERATE_IMAGE_ALL, bookTaskId, imageCategory), await ipcRenderer.invoke(DEFINE_STRING.BOOK.GENERATE_IMAGE_ALL, bookTaskId, imageCategory),
// 高清图片前检查 // 高清图片前检查
CheckImageFileSize: async (id, fileSize, operateBookType) => CheckImageFileSize: async (id: string | string[], fileSize: number, operateBookType: OperateBookType) =>
await ipcRenderer.invoke( await ipcRenderer.invoke(
DEFINE_STRING.BOOK.CHECK_IMAGE_FILE_SIZE, DEFINE_STRING.BOOK.CHECK_IMAGE_FILE_SIZE,
id, id,
@ -248,7 +248,7 @@ const book = {
), ),
// 高清图片任务 // 高清图片任务
HDImage: async (id, scale, operateBookType) => HDImage: async (id: string | string[], scale: number, operateBookType: OperateBookType) =>
await ipcRenderer.invoke(DEFINE_STRING.BOOK.HD_IMAGE, id, scale, operateBookType), await ipcRenderer.invoke(DEFINE_STRING.BOOK.HD_IMAGE, id, scale, operateBookType),
// 将小说视频相关的设置添加到小说任务批次 // 将小说视频相关的设置添加到小说任务批次
@ -260,7 +260,7 @@ const book = {
), ),
// 添加数据到剪映草稿 // 添加数据到剪映草稿
AddJianyingDraft: async (id, operateBookType) => AddJianyingDraft: async (id: string | string[], operateBookType: OperateBookType) =>
await ipcRenderer.invoke(DEFINE_STRING.BOOK.ADD_JIANYING_DRAFT, id, operateBookType) await ipcRenderer.invoke(DEFINE_STRING.BOOK.ADD_JIANYING_DRAFT, id, operateBookType)
//#endregion //#endregion

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,6 @@ export default defineComponent({
props: ['bookTask'], props: ['bookTask'],
setup(props) { setup(props) {
let message = useMessage() let message = useMessage()
let dialog = useDialog() let dialog = useDialog()
let bookTask = ref(props.bookTask) let bookTask = ref(props.bookTask)
@ -63,7 +62,6 @@ export default defineComponent({
* @param e * @param e
*/ */
async function ReSetBookTaskDetail(e) { async function ReSetBookTaskDetail(e) {
e.stopPropagation() e.stopPropagation()
dialog.warning({ dialog.warning({
title: '重置小说任务', title: '重置小说任务',
@ -115,15 +113,28 @@ export default defineComponent({
} }
async function hdImageFunc(id, operateBookType) { async function hdImageFunc(id, operateBookType) {
softwareStore.spin.spinning = true let da = dialog.warning({
softwareStore.spin.tip = '正在高清中。。。' title: '高清提示',
let res = await window.book.HDImage(id, 4, operateBookType) content: `是否确认高清,当前的高清倍数为 ${softwareStore.globalSetting.hdScale} 倍,是否继续?`,
softwareStore.spin.spinning = false positiveText: '继续',
if (res.code == 1) { negativeText: '取消',
message.success('高清成功') onPositiveClick: async () => {
} else { da.destroy()
message.error(res.message) softwareStore.spin.spinning = true
} softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(
id,
softwareStore.globalSetting.hdScale ?? 2,
operateBookType
)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
}
})
} }
/** /**
@ -171,10 +182,10 @@ export default defineComponent({
*/ */
async function ClipDraft(e) { async function ClipDraft(e) {
e.stopPropagation() e.stopPropagation()
dialog.info({ dialog.info({
closeOnEsc: false, closeOnEsc: false,
title: '生成草稿前检查', title: `生成草稿前检查 ${bookTask.value.name}`,
maskClosable: false, maskClosable: false,
content: () => content: () =>
h(ManageBookTaskGenerateInformation, { bookTask: bookTask.value, type: 'bookTask' }) h(ManageBookTaskGenerateInformation, { bookTask: bookTask.value, type: 'bookTask' })

View File

@ -46,15 +46,30 @@
clearable clearable
/> />
</n-form-item> </n-form-item>
<n-form-item label="选择剪映草稿" path="backgroundMusic">
<div>
<div style="color: red">
注意选择的草稿主轨道的图片数量要和当前的相同会生成新的草稿并且只会替换图片保留其余的数据
</div>
<n-select
style="width: 300px"
v-model:value="bookTask.draftDepend"
filterable
placeholder="选择样式"
:options="draftSelect"
clearable
/>
</div>
</n-form-item>
<n-form-item path="backgroundMusic"> <n-form-item path="backgroundMusic">
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask">{{ <n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask"
type == bookTask ? '应用主小说相关数据' : '当前就是用的主小说的数据' >应用主小说相关数据</n-button
}}</n-button> >
<n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button> <n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button>
</n-form-item> </n-form-item>
<div v-if="type == 'bookTask'" style="color: red">注意在生成草稿前要先保存数据</div> <div v-if="type == 'bookTask'" style="color: red">注意在生成草稿前要先保存数据</div>
<div v-else style="color: red"> <div v-else style="color: red">
注意在生成草稿前要先保存数据当前会生成全部的草稿全部会使用上面的参数 注意在生成草稿前要先保存数据当前会生成选择的草稿全部会使用上面的参数
</div> </div>
<n-form-item style="display: flex; justify-content: flex-end"> <n-form-item style="display: flex; justify-content: flex-end">
<n-button type="info" style="margin-left: 10px" @click="AddJianyingDraft">生成草稿</n-button> <n-button type="info" style="margin-left: 10px" @click="AddJianyingDraft">生成草稿</n-button>
@ -62,136 +77,166 @@
</n-form> </n-form>
</template> </template>
<script> <script setup>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue' import { ref, onMounted } from 'vue'
import { useMessage, NForm, NFormItem, NButton, NIcon, NInput, NSelect } from 'naive-ui' import { useMessage, NForm, NFormItem, NButton, NIcon, NInput, NSelect } from 'naive-ui'
import { FolderOpen } from '@vicons/ionicons5' import { FolderOpen } from '@vicons/ionicons5'
import { OperateBookType } from '../../../../../../define/enum/bookEnum' import { OperateBookType } from '../../../../../../define/enum/bookEnum'
import { useReverseManageStore } from '../../../../../../stores/reverseManage'
export default defineComponent({ let props = defineProps({
components: { NForm, NFormItem, NButton, NIcon, NInput, NSelect, FolderOpen }, bookTask: undefined,
props: ['bookTask', 'type'], type: undefined,
setup(props) { selectBookTask: []
let bookTask = ref(props.bookTask) })
let type = ref(props.type) let bookTask = ref(props.bookTask)
let backgroundMusicOptions = ref([]) let type = ref(props.type)
let message = useMessage()
onMounted(async () => { let backgroundMusicOptions = ref([])
// let message = useMessage()
await window.api.GetBackgroundMusicConfigList((value) => { let draftSelect = ref([])
if (value.code == 0) { let reverseManageStore = useReverseManageStore()
message.error(value.message)
return onMounted(async () => {
} // 稿
for (let i = 0; i < value.value.length; i++) { window.api.getDraftFileList((value) => {
const element = value.value[i] value.forEach((element) => {
let obj = { let obj = {
label: element.name, label: element,
value: element.id value: element
} }
backgroundMusicOptions.value.push(obj) draftSelect.value.push(obj)
}
})
}) })
})
/** //
* 选择对应的字幕文件 await window.api.GetBackgroundMusicConfigList((value) => {
*/ if (value.code == 0) {
async function SelectSrtFile() { message.error(value.message)
window.api.SelectFile(['srt'], (value) => { return
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.srtPath = value.value
})
} }
for (let i = 0; i < value.value.length; i++) {
/** const element = value.value[i]
* 选择对应的配音文件 let obj = {
*/ label: element.name,
async function SelectMusicFile() { value: element.id
window.api.SelectFile(['mp3', 'wav'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.audioPath = value.value
})
}
/**
* 应用主小说相关数据
*/
async function UseBookVideoDataToBookTask() {
if (type.value == 'book') {
message.error('当前状态这个按钮不可用')
return
}
let res = await window.book.UseBookVideoDataToBookTask(
bookTask.value.id,
OperateBookType.BOOKTASK
)
if (res.code == 0) {
message.error(res.message)
} else {
//
bookTask.value.backgroundMusic = res.data.backgroundMusic
bookTask.value.friendlyReminder = res.data.friendlyReminder
bookTask.value.draftSrtStyle = res.data.draftSrtStyle
bookTask.value.srtPath = res.data.srtPath
bookTask.value.audioPath = res.data.audioPath
message.success('应用主小说相关数据成功')
} }
backgroundMusicOptions.value.push(obj)
} }
})
})
/** /**
* 保存数据 * 选择对应的字幕文件
*/ */
async function SaveVideoData() { async function SelectSrtFile() {
let res = await window.db.UpdateBookTaskData(bookTask.value.id, { window.api.SelectFile(['srt'], (value) => {
srtPath: bookTask.value.srtPath, if (value.code == 0) {
audioPath: bookTask.value.audioPath, message.error(value.message)
backgroundMusic: bookTask.value.backgroundMusic, return
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle
})
if (res.code == 0) {
message.error('保存小说批次数据失败')
} else {
message.success('保存小说批次数据成功')
}
} }
bookTask.value.srtPath = value.value
})
}
/** /**
* 添加草稿 * 选择对应的配音文件
*/ */
async function AddJianyingDraft() { async function SelectMusicFile() {
let res = await window.book.AddJianyingDraft(bookTask.value.id, OperateBookType.BOOKTASK) window.api.SelectFile(['mp3', 'wav'], (value) => {
window.api.showGlobalMessageDialog(res) if (value.code == 0) {
message.error(value.message)
return
} }
bookTask.value.audioPath = value.value
})
}
return { /**
bookTask, * 应用主小说相关数据
type, */
AddJianyingDraft, async function UseBookVideoDataToBookTask() {
SelectSrtFile, if (type.value == 'book') {
SelectMusicFile, message.error('当前状态这个按钮不可用')
SaveVideoData, return
UseBookVideoDataToBookTask,
backgroundMusicOptions,
rules: {
srtPath: [
{ required: true, message: '请选择背景音乐', trigger: ['input', 'blur', 'change'] }
],
audioPath: [
{ required: true, message: '请选择音频文件', trigger: ['input', 'blur', 'change'] }
]
}
}
} }
let res = await window.book.UseBookVideoDataToBookTask(
bookTask.value.id,
OperateBookType.BOOKTASK
)
if (res.code == 0) {
message.error(res.message)
} else {
//
bookTask.value.backgroundMusic = res.data.backgroundMusic
bookTask.value.friendlyReminder = res.data.friendlyReminder
bookTask.value.draftSrtStyle = res.data.draftSrtStyle
bookTask.value.srtPath = res.data.srtPath
bookTask.value.audioPath = res.data.audioPath
message.success('应用主小说相关数据成功')
}
}
/**
* 保存数据
*/
async function SaveVideoData() {
console.log('SaveVideoData', bookTask.value)
if (props.type == 'book') {
let res = await window.db.UpdateBookData(bookTask.value.id, {
srtPath: bookTask.value.srtPath,
audioPath: bookTask.value.audioPath,
backgroundMusic: bookTask.value.backgroundMusic,
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle,
draftDepend: bookTask.value.draftDepend
})
if (res.code == 0) {
message.error(res.message)
} else {
message.success('保存小说数据成功')
}
} else if (props.type == 'bookTask') {
let res = await window.db.UpdateBookTaskData(bookTask.value.id, {
srtPath: bookTask.value.srtPath,
audioPath: bookTask.value.audioPath,
backgroundMusic: bookTask.value.backgroundMusic,
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle,
draftDepend: bookTask.value.draftDepend
})
if (res.code == 0) {
message.error(res.message)
} else {
message.success('保存小说批次数据成功')
}
} else {
message.error('未知的操作类型,请检查')
}
}
/**
* 添加草稿
*/
async function AddJianyingDraft() {
if (props.type == 'book') {
let res = await window.book.AddJianyingDraft(
props.selectBookTask,
OperateBookType.ASSIGNBOOKTASK
)
window.api.showGlobalMessageDialog(res)
} else if (props.type == 'bookTask') {
let res = await window.book.AddJianyingDraft(bookTask.value.id, OperateBookType.BOOKTASK)
window.api.showGlobalMessageDialog(res)
} else {
message.error('未知的操作类型,请检查')
return
}
}
let rules = ref({
srtPath: [{ required: true, message: '请选择背景音乐', trigger: ['input', 'blur', 'change'] }],
audioPath: [{ required: true, message: '请选择音频文件', trigger: ['input', 'blur', 'change'] }]
}) })
</script> </script>

View File

@ -1,21 +1,21 @@
<template> <template>
<div style="margin-bottom: 5px; margin-left: 5px; display: flex; align-items: center"> <div style="margin-bottom: 5px; margin-left: 5px; display: flex; align-items: center">
<n-button :render-icon="renderIcon" size="small" type="info" @click="AddBookDialog" <n-button :render-icon="renderIcon" size="small" type="info" @click="AddBookDialog()"
>新增</n-button >新增</n-button
> >
<n-button style="margin-left: 5px" size="small" type="info" @click="HDImageAll" <n-button style="margin-left: 5px" size="small" type="info" @click="HDImageAll()"
>一键高清</n-button >一键高清</n-button
> >
<n-button style="margin-left: 5px" type="info" size="small" @click="DraftAll" <n-button style="margin-left: 5px" type="info" size="small" @click="DraftAll()"
>一键草稿</n-button >一键草稿</n-button
> >
<n-button style="margin-left: 5px" type="info" size="small" @click="VideoAll" <n-button style="margin-left: 5px" type="info" size="small" @click="VideoAll()"
>一键视频</n-button >一键视频</n-button
> >
<n-button style="margin-left: 5px" type="info" size="small" @click="ResetAll" <n-button style="margin-left: 5px" type="info" size="small" @click="ResetAll()"
>一键重置</n-button >一键重置</n-button
> >
<n-button style="margin-left: 5px" type="info" size="small" @click="DeleteAll" <n-button style="margin-left: 5px" type="info" size="small" @click="DeleteAll()"
>一键删除</n-button >一键删除</n-button
> >
</div> </div>
@ -26,11 +26,13 @@
:data="reverseManageStore.bookTaskData" :data="reverseManageStore.bookTaskData"
:scroll-x="800" :scroll-x="800"
:row-props="rowProps" :row-props="rowProps"
:row-key="rowKey"
@update:checked-row-keys="handleCheck"
/> />
</div> </div>
</template> </template>
<script> <script setup>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue' import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
import { useMessage, useDialog, NButton, NDataTable, NIcon, NWatermark } from 'naive-ui' import { useMessage, useDialog, NButton, NDataTable, NIcon, NWatermark } from 'naive-ui'
import { useReverseManageStore } from '../../../../stores/reverseManage' import { useReverseManageStore } from '../../../../stores/reverseManage'
@ -42,198 +44,208 @@ import { OperateBookType } from '../../../../define/enum/bookEnum'
import { DEFINE_STRING } from '../../../../define/define_string' import { DEFINE_STRING } from '../../../../define/define_string'
import { ResponseMessageType } from '../../../../define/enum/softwareEnum' import { ResponseMessageType } from '../../../../define/enum/softwareEnum'
import AddBookTask from './Components/ManageBook/AddBookTask.vue' import AddBookTask from './Components/ManageBook/AddBookTask.vue'
import ManageBookTaskGenerateInformation from './Components/ManageBook/ManageBookTaskGenerateInformation.vue'
export default defineComponent({ let reverseManageStore = useReverseManageStore()
components: { let softwareStore = useSoftwareStore()
NButton, let dialog = useDialog()
NDataTable, const router = useRouter()
BookTaskListAction, let message = useMessage()
NWatermark let columns = createColumns()
}, const checkedRowKeysRef = ref([])
onMounted(async () => {
window.api.setEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
if (value.type == ResponseMessageType.HD_IMAGE) {
softwareStore.spin.tip = `正在高清中 ${value.data.current} / ${value.data.total}`
}
})
})
setup() { onUnmounted(() => {
let reverseManageStore = useReverseManageStore() window.api.removeEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN])
let softwareStore = useSoftwareStore() })
let dialog = useDialog()
const router = useRouter() function rowKey(row) {
let message = useMessage() return row.id
onMounted(async () => { }
window.api.setEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN], (value) => {
if (value.code == 0) { function handleCheck(rowKeys) {
message.error(value.message) checkedRowKeysRef.value = rowKeys
return }
}
if (value.type == ResponseMessageType.HD_IMAGE) { function createColumns() {
softwareStore.spin.tip = `正在高清中 ${value.data.current} / ${value.data.total}` return [
} {
}) type: 'selection'
},
{
title: 'No.',
key: 'no',
width: 80
},
{
title: '名称',
key: 'name',
width: 130
},
{
title: '风格',
key: 'styleList'
},
{
title: '前缀',
key: 'prefix',
width: 130
},
{
title: '状态',
key: 'status',
width: 100
},
{
title: '操作',
key: 'action',
width: 215,
fixed: 'right',
render(row, index) {
return h(BookTaskListAction, {
bookTask: row
})
}
}
]
}
/**
* 高清数据
*/
async function hdImageFunc(id, operateBookType) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(id, 4, operateBookType)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
}
/**
* 一键高清全部
*/
async function HDImageAll() {
console.log('一键高清', checkedRowKeysRef.value)
if (checkedRowKeysRef.value.length == 0) {
message.error('请选择要高清的数据')
return
}
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在进行高清检查。。。'
let checkImage = await window.book.CheckImageFileSize(
[...checkedRowKeysRef.value],
10240,
OperateBookType.ASSIGNBOOKTASK
)
softwareStore.spin.spinning = false
if (checkImage.code == 0) {
message.error(checkImage.message)
return
}
//
if (checkImage.data && checkImage.data.length > 0) {
//
let msg = checkImage.data.map((item, index) => {
return item.outImagePath + '\n'
}) })
dialog.warning({
onUnmounted(() => { title: '高清警告',
window.api.removeEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN]) content: '下面的图片大于10MB是否继续高清' + '\n' + msg,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
alert('确认高清')
await hdImageFunc([...checkedRowKeysRef.value], OperateBookType.ASSIGNBOOKTASK)
}
}) })
} else {
//
await hdImageFunc([...checkedRowKeysRef.value], OperateBookType.ASSIGNBOOKTASK)
}
}
function createColumns() { async function AddBookDialog() {
return [ message.info('新增' + reverseManageStore.selectBook.id)
{ dialog.create({
title: 'No.', title: '新增小说批次任务',
key: 'no', showIcon: false,
width: 80 content: () => h(AddBookTask),
}, style: { width: '600px' }
{ })
title: '名称', }
key: 'name',
width: 130
},
{
title: '风格',
key: 'styleList'
},
{
title: '前缀',
key: 'prefix',
width: 130
},
{
title: '状态',
key: 'status',
width: 100
},
{
title: '操作',
key: 'action',
width: 215,
fixed: 'right',
render(row, index) {
return h(BookTaskListAction, {
bookTask: row
})
}
}
]
}
/** /**
* 高清数据 * 一键生成草稿
*/ */
async function hdImageFunc(id, operateBookType) { async function DraftAll() {
softwareStore.spin.spinning = true if (checkedRowKeysRef.value.length == 0) {
softwareStore.spin.tip = '正在高清中。。。' message.error('请选择要生成草稿的任务')
let res = await window.book.HDImage(id, 4, operateBookType) return
softwareStore.spin.spinning = false }
if (res.code == 1) { // 稿
message.success('高清成功') dialog.info({
} else { closeOnEsc: false,
message.error(res.message) title: `生成草稿前检查 ${reverseManageStore.selectBook.name}`,
} maskClosable: false,
} content: () =>
h(ManageBookTaskGenerateInformation, {
/** bookTask: reverseManageStore.selectBook,
* 一键高清全部 type: 'book',
*/ selectBookTask: [...checkedRowKeysRef.value]
async function HDImageAll() {
alert('高清全部')
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在进行高清检查。。。'
let checkImage = await window.book.CheckImageFileSize(
reverseManageStore.selectBook.id,
10240,
OperateBookType.BOOK
)
softwareStore.spin.spinning = false
if (checkImage.code == 0) {
message.error(checkImage.message)
return
}
//
if (checkImage.data && checkImage.data.length > 0) {
//
let msg = checkImage.data.map((item, index) => {
return item.outImagePath + '\n'
})
dialog.warning({
title: '高清警告',
content: '下面的图片大于10MB是否继续高清' + '\n' + msg,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
alert('确认高清')
await hdImageFunc(reverseManageStore.selectBook.id, OperateBookType.BOOK)
}
})
} else {
//
await hdImageFunc(reverseManageStore.selectBook.id, OperateBookType.BOOK)
}
}
async function AddBookDialog() {
message.info('新增' + reverseManageStore.selectBook.id)
dialog.create({
title: '新增小说批次任务',
showIcon: false,
content: () => h(AddBookTask),
style: { width: '600px' }
}) })
} })
}
/** /**
* 一键生成草稿 * 一键生成视频
*/ */
async function DraftAll() { async function VideoAll() {
alert('草稿全部') alert('视频全部')
} }
/** /**
* 一键生成视频 * 一键重置
*/ */
async function VideoAll() { async function ResetAll() {
alert('视频全部') alert('重置全部')
} }
/** /**
* 一键重置 * 一键删除
*/ */
async function ResetAll() { async function DeleteAll() {
alert('重置全部') alert('删除全部')
} }
const renderIcon = () => {
/** return h(NIcon, null, {
* 一键删除 default: () => h(AddSharp, { size: '40', color: 'white' }, {})
*/ })
async function DeleteAll() { }
alert('删除全部') const rowProps = (row) => {
} return {
style: 'cursor: pointer;',
return { ondblclick: async () => {
reverseManageStore, // message.info(row.id)
AddBookDialog, reverseManageStore.selectBookTask = row
HDImageAll, softwareStore.spin.spinning = true
DraftAll, softwareStore.spin.tip = '正在加载数据'
VideoAll, //
ResetAll, router.push({ name: 'manage_book', params: { id: row.id } })
DeleteAll,
columns: createColumns(),
renderIcon() {
return h(NIcon, null, {
default: () => h(AddSharp, { size: '40', color: 'white' }, {})
})
},
rowProps: (row) => {
return {
style: 'cursor: pointer;',
onClick: async () => {
// message.info(row.id)
reverseManageStore.selectBookTask = row
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在加载数据'
//
router.push({ name: 'manage_book', params: { id: row.id } })
}
}
}
} }
} }
}) }
</script> </script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div style="height: 100%"> <div style="height: 100%">
<ManageBook style="height: 100%" v-if="softwareStore.softWare.reverse_display_show" /> <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%"> <n-split v-else direction="horizontal" :min="0.4" :max="0.8" :default-size="0.4" height="100%">
<template #1> <ManageBook style="height: 100%" /> </template> <template #1> <ManageBook style="height: 100%" /> </template>
<template #2> <template #2>
<ManageBookTask style="height: 100%" /> <ManageBookTask style="height: 100%" />

View File

@ -46,14 +46,24 @@
<template #unchecked> </template> <template #unchecked> </template>
</n-switch> </n-switch>
</n-form-item> </n-form-item>
<n-form-item label="人物场景选择模式" style="margin-left: 20px"> <n-form-item label="选择高清倍率" style="margin-left: 20px">
<n-select
size="small"
placeholder="请选择"
:options="hdSelectOptions"
v-model:value="formValue.hdScale"
style="width: 120px"
/>
</n-form-item>
<n-form-item style="margin-left: 20px" label="人物场景选择模式">
<n-select <n-select
size="small" size="small"
placeholder="请选择" placeholder="请选择"
:options="character_select_model_options" :options="character_select_model_options"
v-model:value="formValue.character_select_model" v-model:value="formValue.character_select_model"
style="width: 120px" style="width: 120px"
/> >
</n-select>
</n-form-item> </n-form-item>
<n-form-item style="margin-left: 20px" <n-form-item style="margin-left: 20px"
><n-checkbox v-model:checked="formValue.window_wh_bm_remember" ><n-checkbox v-model:checked="formValue.window_wh_bm_remember"
@ -212,12 +222,27 @@ export default defineComponent({
theme: softwareStore.globalSetting.theme, theme: softwareStore.globalSetting.theme,
character_select_model: window.config.character_select_model, character_select_model: window.config.character_select_model,
window_wh_bm_remember: window.config.window_wh_bm_remember, window_wh_bm_remember: window.config.window_wh_bm_remember,
laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN,
hdScale: window.config.hdScale ?? 2
}) })
let show = ref(false) let show = ref(false)
let gpt_options = ref([]) let gpt_options = ref([])
let gpt_model_options = ref([]) let gpt_model_options = ref([])
let character_select_model_options = ref([]) let character_select_model_options = ref([])
let hdSelectOptions = ref([
{
label: '2倍',
value: 2
},
{
label: '3倍',
value: 3
},
{
label: '4倍',
value: 4
}
])
let dialog = useDialog() let dialog = useDialog()
let loading = ref(false) let loading = ref(false)
/** /**
@ -472,6 +497,7 @@ export default defineComponent({
AddGptPrompt, AddGptPrompt,
character_select_model_options, character_select_model_options,
softwareStore, softwareStore,
hdSelectOptions,
ModifyTranslateSetting, ModifyTranslateSetting,
laiApiOptions: [ laiApiOptions: [
{ {