修复聚合推文剪映抽帧时,导入srt没有输入
(聚合推文) SD 反推,MJ反推添加单句洗稿功能
(聚合推文)小说任务列表,添加进入出图文件夹的菜单
(聚合推文)新增一键出图
(聚合推文)新增默认出图方式设置,
5.1只对原创生效,SD反推默认是SD,MJ反推默认是MJ
5.2添加批次的默认出图方式同 a点说明,但是选择了 选择旧批次,新批次的默认出图方式会继承
后台任务,完成后台任务的可视化界面
(聚合推文)小说详情界面,添加小说和批次名称显示
This commit is contained in:
lq1405 2024-11-02 18:18:55 +08:00
parent 22cfe65dde
commit 51deef0c09
64 changed files with 2051 additions and 1136 deletions

View File

@ -17,7 +17,8 @@ export default defineConfig({
renderer: { renderer: {
resolve: { resolve: {
alias: { alias: {
'@renderer': resolve('src/renderer/src') '@renderer': resolve('src/renderer/src'),
"@" : resolve('src/'),
} }
}, },
plugins: [vue(), Jsx()] plugins: [vue(), Jsx()]

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "laitool", "name": "laitool",
"version": "3.1.9", "version": "3.2.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "laitool", "name": "laitool",
"version": "3.1.9", "version": "3.2.0",
"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.9", "version": "3.2.0",
"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

@ -205,7 +205,7 @@ export class BookService extends BaseRealmService {
} else if (book.type == BookType.MJ_REVERSE) { } else if (book.type == BookType.MJ_REVERSE) {
imageCategory = BookImageCategory.MJ imageCategory = BookImageCategory.MJ
} else if (book.type == BookType.ORIGINAL) { } else if (book.type == BookType.ORIGINAL) {
imageCategory = BookImageCategory.MJ imageCategory = global.config.defaultImageMode
} else { } else {
throw new Error('未知的小说类型') throw new Error('未知的小说类型')
} }

View File

@ -104,6 +104,9 @@ const BOOK = {
*/ */
GET_IMAGE_URL_AND_DOWNLOAD: "GET_IMAGE_URL_AND_DOWNLOAD", GET_IMAGE_URL_AND_DOWNLOAD: "GET_IMAGE_URL_AND_DOWNLOAD",
/** 添加一键生图后台任务 */
GENERATE_ALL_TASK_IMAGE: "GENERATE_ALL_TASK_IMAGE",
//#endregion //#endregion
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD', COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',

View File

@ -3,6 +3,7 @@ import TASK from "./taskDefineString"
import TTS from "./ttsDefineString" import TTS from "./ttsDefineString"
import SETTING from "./settingDefineString" import SETTING from "./settingDefineString"
import BOOK from "./bookDefineString" import BOOK from "./bookDefineString"
import WRITE from "./writeDefineString"
export const DEFINE_STRING = { export const DEFINE_STRING = {
SYSTEM: SYSTEM, SYSTEM: SYSTEM,
@ -10,6 +11,7 @@ export const DEFINE_STRING = {
TTS: TTS, TTS: TTS,
BOOK: BOOK, BOOK: BOOK,
SETTING: SETTING, SETTING: SETTING,
WRITE: WRITE,
SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE", SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE",
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION', SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD', OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
@ -246,14 +248,6 @@ export const DEFINE_STRING = {
*/ */
GET_SCENE_PRESET: "GET_SCENE_PRESET" GET_SCENE_PRESET: "GET_SCENE_PRESET"
}, },
WRITE: {
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',
ACTION_START: 'ACTION_START',
GET_SUBTITLE_SETTING: "GET_SUBTITLE_SETTING",
RESET_SUBTITLE_SETTING: "RESET_SUBTITLE_SETTING",
SAVE_SUBTITLE_SETTING: "SAVE_SUBTITLE_SETTING",
},
DB: { DB: {
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA", UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA", UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA",

View File

@ -9,6 +9,9 @@ const TASK = {
/** 获取等待中的任务 */ /** 获取等待中的任务 */
GET_ALL_STATUS_TASK_COUNT: "GET_ALL_STATUS_TASK_COUNT", GET_ALL_STATUS_TASK_COUNT: "GET_ALL_STATUS_TASK_COUNT",
/** 获取后台任务的集合,分页 */
GET_BACK_TASK_COLLECTION: "GET_BACK_TASK_COLLECTION",
}; };
export default TASK; export default TASK;

View File

@ -0,0 +1,15 @@
const WRITE = {
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',
ACTION_START: 'ACTION_START',
GET_SUBTITLE_SETTING: "GET_SUBTITLE_SETTING",
RESET_SUBTITLE_SETTING: "RESET_SUBTITLE_SETTING",
SAVE_SUBTITLE_SETTING: "SAVE_SUBTITLE_SETTING",
/** 生成洗稿后文案 */
GENERATE_AFTER_GPT_WORD: "GENERATE_AFTER_GPT_WORD",
/** 生成洗稿后文案返回数据,前端接收 */
GENERATE_AFTER_GPT_WORD_RESPONSE: "GENERATE_AFTER_GPT_WORD_RESPONSE"
}
export default WRITE

View File

@ -282,3 +282,144 @@ export enum BookTagSelectType {
// 标签 // 标签
TAG = 'tag' TAG = 'tag'
} }
/**
* Key返回指定的后台任务类型的label
* @param key
* @returns
*/
export function GetBookBackTaskTypeLabel(key: string) {
switch (key) {
case BookBackTaskType.STORYBOARD:
return '分镜计算';
case BookBackTaskType.SPLIT:
return '分割视频';
case BookBackTaskType.AUDIO:
return '提取音频';
case BookBackTaskType.RECOGNIZE:
return '识别字幕';
case BookBackTaskType.FRAME:
return '抽帧';
case BookBackTaskType.MJ_REVERSE:
return 'MJ反推';
case BookBackTaskType.SD_REVERSE:
return 'SD反推';
case BookBackTaskType.MJ_IMAGE:
return 'MJ生成图片';
case BookBackTaskType.SD_IMAGE:
return 'SD生成图片';
case BookBackTaskType.FLUX_FORGE_IMAGE:
return 'flux forge生成图片';
case BookBackTaskType.FLUX_API_IMAGE:
return 'flux api生成图片';
case BookBackTaskType.D3_IMAGE:
return 'D3生成图片';
case BookBackTaskType.HD:
return '高清';
case BookBackTaskType.COMPOSING:
return '合成视频';
case BookBackTaskType.INFERENCE:
return '推理';
case BookBackTaskType.TRANSLATE:
return '翻译';
default:
return key;
}
}
/**
* Key返回指定的后台任务状态的label
* @param key
* @returns
*/
export function GetBookTaskDetailStatusLabel(key: string) {
switch (key) {
case BookTaskStatus.WAIT:
return '等待';
case BookTaskStatus.STORYBOARD:
return '分镜计算中';
case BookTaskStatus.STORYBOARD_FAIL:
return '分镜计算失败';
case BookTaskStatus.STORYBOARD_DONE:
return '分镜计算完成';
case BookTaskStatus.SPLIT:
return '分割视频中';
case BookTaskStatus.SPLIT_FAIL:
return '分割视频失败';
case BookTaskStatus.SPLIT_DONE:
return '分割视频完成';
case BookTaskStatus.AUDIO:
return '提取音频中';
case BookTaskStatus.AUDIO_FAIL:
return '提取音频失败';
case BookTaskStatus.AUDIO_DONE:
return '提取音频完成';
case BookTaskStatus.RECOGNIZE:
return '识别字幕中';
case BookTaskStatus.RECOGNIZE_FAIL:
return '识别字幕失败';
case BookTaskStatus.RECOGNIZE_DONE:
return '识别字幕完成';
case BookTaskStatus.FRAME:
return '抽帧中';
case BookTaskStatus.FRAME_FAIL:
return '抽帧失败';
case BookTaskStatus.FRAME_DONE:
return '抽帧完成';
case BookTaskStatus.REVERSE:
return '反推中';
case BookTaskStatus.REVERSE_FAIL:
return '反推失败';
case BookTaskStatus.REVERSE_DONE:
return '反推完成';
case BookTaskStatus.IMAGE:
return '生成图片中';
case BookTaskStatus.IMAGE_FAIL:
return '生成图片失败';
case BookTaskStatus.IMAGE_DONE:
return '生成图片完成';
case BookTaskStatus.HD:
return '高清中';
case BookTaskStatus.HD_FAIL:
return '高清失败';
case BookTaskStatus.HD_DONE:
return '高清完成';
case BookTaskStatus.COMPOSING:
return '合成视频中';
case BookTaskStatus.COMPOSING_FAIL:
return '合成视频失败';
case BookTaskStatus.COMPOSING_DONE:
return '合成视频完成';
case BookTaskStatus.DRAFT_DONE:
return '添加草稿完成';
case BookTaskStatus.DRAFT_FAIL:
return '添加草稿失败';
default:
return key;
}
}
/**
* Key返回指定的后台任务状态的label
* @param key
* @returns
*/
export function GetBookBackTaskStatusLabel(key: string) {
switch (key) {
case BookBackTaskStatus.WAIT:
return '等待';
case BookBackTaskStatus.RUNNING:
return '运行中';
case BookBackTaskStatus.PAUSE:
return '暂停';
case BookBackTaskStatus.DONE:
return '完成';
case BookBackTaskStatus.FAIL:
return '失败';
case BookBackTaskStatus.RECONNECT:
return '重连';
default:
return key;
}
}

View File

@ -267,21 +267,22 @@ export function BookIpc() {
async (event, id, operateBookType) => await bookImage.ResetGenerateImage(id, operateBookType) async (event, id, operateBookType) => await bookImage.ResetGenerateImage(id, operateBookType)
) )
// 获取图片的URL并且下载
ipcMain.handle( ipcMain.handle(
DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD, DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD,
async (event, id: string, operateBookType: OperateBookType, coverData: boolean) => async (event, id: string, operateBookType: OperateBookType, coverData: boolean) =>
await bookImage.GetImageUrlAndDownload(id, operateBookType, coverData) await bookImage.GetImageUrlAndDownload(id, operateBookType, coverData)
) )
/** 添加一键生图后台任务 */
ipcMain.handle(
DEFINE_STRING.BOOK.GENERATE_ALL_TASK_IMAGE,
async (event, ids: string[], operateBookType: OperateBookType) => await bookImage.GenerateAllTaskImage(ids, operateBookType)
)
//#endregion //#endregion
// 一拆四,将一个任务拆分成四个任务,并且复制对应的图片
ipcMain.handle(
DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK,
async (event, bookTaskDetailId) => await bookTask.OneToFourBookTask(bookTaskDetailId)
)
//#region 小说相关 //#region 小说相关
// 重置小说数据 // 重置小说数据
@ -294,6 +295,12 @@ export function BookIpc() {
//#region 小说批次任务相关 //#region 小说批次任务相关
// 一拆四,将一个任务拆分成四个任务,并且复制对应的图片
ipcMain.handle(
DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK,
async (event, bookTaskDetailId) => await bookTask.OneToFourBookTask(bookTaskDetailId)
)
// 新建小说批次任务 // 新建小说批次任务
ipcMain.handle(DEFINE_STRING.BOOK.ADD_NEW_BOOK_TASK, async (event, addBookTaskData) => await bookTask.AddNewBookTask(addBookTaskData)) ipcMain.handle(DEFINE_STRING.BOOK.ADD_NEW_BOOK_TASK, async (event, addBookTaskData) => await bookTask.AddNewBookTask(addBookTaskData))

View File

@ -6,6 +6,7 @@ import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "../../def
let bookServiceBasic = new BookServiceBasic(); let bookServiceBasic = new BookServiceBasic();
import BackTaskService from '../Service/task/backTaskService' import BackTaskService from '../Service/task/backTaskService'
import { TaskModal } from "@/model/task";
const backTaskService = new BackTaskService() const backTaskService = new BackTaskService()
function TaskIpc() { function TaskIpc() {
@ -38,8 +39,12 @@ function TaskIpc() {
return errorMessage(`添加多个任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddMultiBookBackTask') return errorMessage(`添加多个任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddMultiBookBackTask')
} }
}) })
/** 获取指定状态的任务数量 */ /** 获取指定状态的任务数量 */
ipcMain.handle(DEFINE_STRING.TASK.GET_ALL_STATUS_TASK_COUNT, async (event, value: BookBackTaskStatus[]) => await backTaskService.GetAllStatusTaskCount(value)) ipcMain.handle(DEFINE_STRING.TASK.GET_ALL_STATUS_TASK_COUNT, async (event, value: BookBackTaskStatus[]) => await backTaskService.GetAllStatusTaskCount(value))
/** 获取后台任务的集合,分页 */
ipcMain.handle(DEFINE_STRING.TASK.GET_BACK_TASK_COLLECTION, async (event, queryTaskCondition: TaskModal.QueryTaskCondition) => await backTaskService.GetBackTaskCollection(queryTaskCondition))
} }
export { TaskIpc } export { TaskIpc }

View File

@ -5,7 +5,9 @@ let writing = new Writing(global)
import { WritingSetting } from '../setting/writeSetting' import { WritingSetting } from '../setting/writeSetting'
let writingSetting = new WritingSetting() let writingSetting = new WritingSetting()
import { SubtitleService } from '../Service/Subtitle/subtitleService' import { SubtitleService } from '../Service/Subtitle/subtitleService'
import { BookPrompt } from '../Service/Book/bookPrompt'
let subtitleService = new SubtitleService() let subtitleService = new SubtitleService()
const bookPrompt = new BookPrompt();
function WritingIpc() { function WritingIpc() {
// 监听分镜时间的保存 // 监听分镜时间的保存
@ -71,5 +73,14 @@ function WritingIpc() {
DEFINE_STRING.WRITE.ACTION_START, DEFINE_STRING.WRITE.ACTION_START,
async (event, aiSetting, word) => await writing.ActionStart(aiSetting, word) async (event, aiSetting, word) => await writing.ActionStart(aiSetting, word)
) )
//#region 文案洗稿相关
/** 生成洗稿后文案 */
ipcMain.handle(
DEFINE_STRING.WRITE.GENERATE_AFTER_GPT_WORD,
async (event, ids: string[], isEmpty: boolean) => await bookPrompt.GenerateAfterGptWord(ids, isEmpty)
)
//#endregion
} }
export { WritingIpc } export { WritingIpc }

View File

@ -84,7 +84,7 @@ export class BookFrame {
startTime: Math.ceil(element.startTime / 1000), startTime: Math.ceil(element.startTime / 1000),
endTime: Math.ceil(element.endTime / 1000), endTime: Math.ceil(element.endTime / 1000),
status: BookTaskStatus.WAIT, status: BookTaskStatus.WAIT,
word: element.word, word: element.text,
videoPath: element.videoPath, videoPath: element.videoPath,
oldImage: path.relative(define.project_path, element.framePath), oldImage: path.relative(define.project_path, element.framePath),
afterGpt: element.text, afterGpt: element.text,

View File

@ -1,4 +1,4 @@
import { BookImageCategory, BookType, MJAction, OperateBookType } from "../../../define/enum/bookEnum"; import { BookBackTaskType, BookImageCategory, BookType, MJAction, OperateBookType, TaskExecuteType } from "../../../define/enum/bookEnum";
import { GeneralResponse } from "../../../model/generalResponse"; import { GeneralResponse } from "../../../model/generalResponse";
import { errorMessage, successMessage } from "../../Public/generalTools"; import { errorMessage, successMessage } from "../../Public/generalTools";
import { Book } from "../../../model/book"; import { Book } from "../../../model/book";
@ -19,6 +19,13 @@ import { MJImageType } from "../../../define/enum/mjEnum";
import MJApi from '../MJ/mjApi' import MJApi from '../MJ/mjApi'
const execAsync = util.promisify(exec); const execAsync = util.promisify(exec);
type TaskTemp = {
bookTaskId: string;
bookId: string;
imageCategory: BookImageCategory;
bookTaskDetail: Book.SelectBookTaskDetail;
}
/** /**
* *
*/ */
@ -87,8 +94,9 @@ export class BookImage {
} }
//#endregion //#endregion
//#region 开始高清图片任务
/** /**
* *
* @param id ID * @param id ID
* @param scale * @param scale
* @param operateBookType BOOKBOOKTASK两种 * @param operateBookType BOOKBOOKTASK两种
@ -188,7 +196,9 @@ export class BookImage {
} }
} }
//#endregion
//#region 检查图片的大小
/** /**
* fileSize false * fileSize false
* @param id IDIDID * @param id IDIDID
@ -251,6 +261,88 @@ export class BookImage {
} }
} }
//#endregion
/**
*
* @param ids ID
* @param operateBookType
*/
async GenerateAllTaskImage(ids: string[], operateBookType: OperateBookType) {
try {
let bookTasks = [] as Book.SelectBookTask[];
if (operateBookType == OperateBookType.ASSIGNBOOKTASK) {
for (let i = 0; i < ids.length; i++) {
const element = ids[i];
let tempBookTask = await this.bookServiceBasic.GetBookTaskDataById(element);
bookTasks.push(tempBookTask)
}
} else {
throw new Error('不支持的操作类型,请检查')
}
if (bookTasks.length <= 0) {
throw new Error('没有找到需要操作的数据,请检查')
}
let taskTemp = [] as TaskTemp[]
for (let i = 0; i < bookTasks.length; i++) {
const element = bookTasks[i];
let bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
bookTaskId: element.id
}, true)
if (bookTaskDetails.length <= 0) {
throw new Error(`批次任务 ${element.name} 没有找到分镜数据,请检查`)
}
let emptyPrompt = bookTaskDetails.filter(item => isEmpty(item.prompt));
if (emptyPrompt.length > 0) {
throw new Error(`批次任务 ${element.name} 的分镜 ${emptyPrompt[0].name} 没有找到出图提示词,请检查`)
}
taskTemp.push(...bookTaskDetails.map((item) => {
return {
bookTaskId: element.id,
bookId: element.bookId,
imageCategory: element.imageCategory,
bookTaskDetail: item
}
}))
}
// 检查当前小说批次任务是不是又出图方式
// 判断是不是所有的小说批次都有小说分镜
// 判断每个分镜是不是都有出图提示词
// 添加出图任务
for (let i = 0; i < taskTemp.length; i++) {
const element = taskTemp[i];
// 添加任务
let taskType = BookBackTaskType.MJ_IMAGE
let responseMessageName = DEFINE_STRING.BOOK.MJ_IMAGE_GENERATE_RETURN;
if (element.imageCategory == BookImageCategory.MJ) {
taskType = BookBackTaskType.MJ_IMAGE;
responseMessageName = DEFINE_STRING.BOOK.MJ_IMAGE_GENERATE_RETURN;
} else if (element.imageCategory == BookImageCategory.SD) {
taskType = BookBackTaskType.SD_IMAGE;
responseMessageName = DEFINE_STRING.BOOK.SD_IMAGE_GENERATE_RETURN;
} else if (element.imageCategory == BookImageCategory.D3) {
taskType = BookBackTaskType.D3_IMAGE;
responseMessageName = DEFINE_STRING.BOOK.D3_IMAGE_GENERATE_RETURN;
} else if (element.imageCategory == BookImageCategory.FLUX_FORGE) {
taskType = BookBackTaskType.FLUX_FORGE_IMAGE;
responseMessageName = DEFINE_STRING.BOOK.FLUX_FORGE_IMAGE_GENERATE_RETURN
} else if (element.imageCategory == BookImageCategory.FLUX_API) {
taskType = BookBackTaskType.FLUX_API_IMAGE;
responseMessageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN;
} else {
throw new Error('未知的出图类型')
}
await this.bookServiceBasic.AddBookBackTask(element.bookId, taskType, TaskExecuteType.AUTO, element.bookTaskId, element.bookTaskDetail.id, responseMessageName)
}
return successMessage(null, "添加所选的的生图任务成功", "BookImage_GenerateAllTaskImage")
} catch (error) {
return errorMessage("添加所有的生图任务失败,失败信息如下:" + error.toString(), "BookImage_GenerateAllTaskImage");
}
}
/** /**
* *
@ -277,6 +369,7 @@ export class BookImage {
} }
} }
//#region 对图片进行锁定或者是解锁操作
/** /**
* *
* @param id id * @param id id
@ -327,7 +420,9 @@ export class BookImage {
return errorMessage("图片执行锁定或解锁失败,失败信息如下:" + error.toString(), "BookImage_ImageLockOperation") return errorMessage("图片执行锁定或解锁失败,失败信息如下:" + error.toString(), "BookImage_ImageLockOperation")
} }
} }
//#endregion
//#region 下载指定的图片地址并且分割
/** /**
* *
* @param bookTaskDetailId ID * @param bookTaskDetailId ID
@ -416,8 +511,9 @@ export class BookImage {
} }
} }
} }
//#endregion
//#region 获取指定的图片链接 ,然后下载图片
/** /**
* *
* @param id * @param id
@ -486,4 +582,5 @@ export class BookImage {
return errorMessage('获取图片链接并且下载失败,错误信息如下:' + error.message, 'BookImage_GetImageUrlAndDownload') return errorMessage('获取图片链接并且下载失败,错误信息如下:' + error.message, 'BookImage_GetImageUrlAndDownload')
} }
} }
//#endregion
} }

View File

@ -13,6 +13,7 @@ import path from 'path'
import readline from 'readline'; import readline from 'readline';
import { define } from "../../../define/define"; import { define } from "../../../define/define";
import { ValidateJson } from "../../../define/Tools/validate"; import { ValidateJson } from "../../../define/Tools/validate";
import { SendMessageToRenderer } from "../globalService";
export class BookPrompt { export class BookPrompt {
@ -290,6 +291,67 @@ export class BookPrompt {
} }
} }
/**
* 稿
* @param ids 稿ID
* @param isEmpty
* 稿
*/
async GenerateAfterGptWord(ids: string[], empty: boolean) {
try {
if (ids.length <= 0) {
throw new Error('没有传入要洗稿的数据ID')
}
let bookTaskDetails = [] as Book.SelectBookTaskDetail[]
for (let i = 0; i < ids.length; i++) {
const element = ids[i];
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(element)
bookTaskDetails.push(bookTaskDetail);
}
if (empty) {
bookTaskDetails = bookTaskDetails.filter(item => isEmpty(item.gptPrompt))
}
if (bookTaskDetails.length <= 0) {
throw new Error('没有找到要洗稿的数据')
}
// 开始删除数据
for (let i = 0; i < bookTaskDetails.length; i++) {
const element = bookTaskDetails[i];
await this.bookServiceBasic.UpdateBookTaskDetail(element.id, {
afterGpt: undefined
})
SendMessageToRenderer({
code: 1,
message: "删除洗稿后文案成功",
id: element.id,
data: ""
}, DEFINE_STRING.WRITE.GENERATE_AFTER_GPT_WORD_RESPONSE)
}
for (let i = 0; i < bookTaskDetails.length; i++) {
const element = bookTaskDetails[i];
// 开始洗稿
let content = await this.gptService.GenerateAfterGptWordByGPT(element.word);
// 修改数据
await this.bookServiceBasic.UpdateBookTaskDetail(element.id, {
afterGpt: content
})
SendMessageToRenderer({
code: 1,
message: "文案洗稿成功",
id: element.id,
data: content
}, DEFINE_STRING.WRITE.GENERATE_AFTER_GPT_WORD_RESPONSE)
}
return successMessage(null, "洗稿完成", "ReverseBook_GenerateAfterGptWord")
} catch (error) {
return errorMessage("生成洗稿后文案失败,错误信息如下:" + error.message, "ReverseBook_GenerateAfterGptWord")
}
}
//#endregion //#endregion
//#region 原创的提示词相关 //#region 原创的提示词相关

View File

@ -1,5 +1,5 @@
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFolderAllFile } from "../../../define/Tools/file"; import { CheckFileOrDirExist, CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFolderAllFile } from "../../../define/Tools/file";
import { AddBookTaskCopyData, BookImageCategory, BookTaskStatus, CopyImageType, OperateBookType } from "../../../define/enum/bookEnum"; import { AddBookTaskCopyData, BookImageCategory, BookTaskStatus, BookType, CopyImageType, OperateBookType } from "../../../define/enum/bookEnum";
import { errorMessage, successMessage } from "../../Public/generalTools"; import { errorMessage, successMessage } from "../../Public/generalTools";
import { Book } from "../../../model/book"; import { Book } from "../../../model/book";
import path from 'path' import path from 'path'
@ -119,9 +119,23 @@ export class BookTask {
* @param no * @param no
* @returns * @returns
*/ */
CopyBookTaskBaseData(bookTask: Book.SelectBookTask, addNewBookTask: Book.AddBookTask, no: number): Book.SelectBookTask { async CopyBookTaskBaseData(bookTask: Book.SelectBookTask, addNewBookTask: Book.AddBookTask, no: number): Promise<Book.SelectBookTask> {
let name = 'output_' + no.toString().padStart(5, '0'); let name = 'output_' + no.toString().padStart(5, '0');
let imageFolder = path.join(define.project_path, `${bookTask.bookId}/tmp/${name}`); let imageFolder = path.join(define.project_path, `${bookTask.bookId}/tmp/${name}`);
let imageCategory = global.config.defaultImageMode;
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId)
if (!isEmpty(bookTask.imageCategory)) {
imageCategory = bookTask.imageCategory;
} else {
if (book.type == BookType.MJ_REVERSE) {
imageCategory = BookImageCategory.MJ
} else if (book.type == BookType.SD_REVERSE) {
imageCategory = BookImageCategory.SD
} else if (book.type == BookType.ORIGINAL) {
imageCategory = global.config.defaultImageMode
}
}
let newBookTask = { let newBookTask = {
id: uuidv4(), id: uuidv4(),
bookId: bookTask.bookId, bookId: bookTask.bookId,
@ -142,7 +156,7 @@ export class BookTask {
videoConfig: bookTask.videoConfig ??= undefined, videoConfig: bookTask.videoConfig ??= undefined,
prefixPrompt: addNewBookTask.prefixPrompt ??= undefined, prefixPrompt: addNewBookTask.prefixPrompt ??= undefined,
suffixPrompt: addNewBookTask.suffixPrompt ?? undefined, suffixPrompt: addNewBookTask.suffixPrompt ?? undefined,
imageCategory: bookTask.imageCategory ??= BookImageCategory.MJ, imageCategory: imageCategory,
subImageFolder: [], subImageFolder: [],
draftSrtStyle: undefined, draftSrtStyle: undefined,
backgroundMusic: bookTask.backgroundMusic ??= undefined, backgroundMusic: bookTask.backgroundMusic ??= undefined,
@ -164,7 +178,7 @@ export class BookTask {
* @returns * @returns
*/ */
async AddOneBookTask(bookTask: Book.SelectBookTask, bookTaskDetails: Book.SelectBookTaskDetail[], addNewBookTask: Book.AddBookTask, no: number): Promise<{ newBookTask: Book.SelectBookTask, newBookTaskDetails: Book.SelectBookTaskDetail[] }> { async AddOneBookTask(bookTask: Book.SelectBookTask, bookTaskDetails: Book.SelectBookTaskDetail[], addNewBookTask: Book.AddBookTask, no: number): Promise<{ newBookTask: Book.SelectBookTask, newBookTaskDetails: Book.SelectBookTaskDetail[] }> {
let newBookTask = this.CopyBookTaskBaseData(bookTask, addNewBookTask, no) let newBookTask = await this.CopyBookTaskBaseData(bookTask, addNewBookTask, no)
let newBookTaskDetails = await this.CopyBookTaskDetailBaseData(bookTask, newBookTask, bookTaskDetails, addNewBookTask) let newBookTaskDetails = await this.CopyBookTaskDetailBaseData(bookTask, newBookTask, bookTaskDetails, addNewBookTask)
return { return {
newBookTask: newBookTask, newBookTask: newBookTask,
@ -199,7 +213,7 @@ export class BookTask {
bookTasks.push(newBookTask) bookTasks.push(newBookTask)
bookTaskDetail.push(...newBookTaskDetails) bookTaskDetail.push(...newBookTaskDetails)
} else { } else {
let newBookTask = this.CopyBookTaskBaseData({ bookId: addNewBookTask.selectBookId }, addNewBookTask, maxNo + i) let newBookTask = await this.CopyBookTaskBaseData({ bookId: addNewBookTask.selectBookId }, addNewBookTask, maxNo + i)
bookTasks.push(newBookTask); bookTasks.push(newBookTask);
} }
} }

View File

@ -160,6 +160,7 @@ export class FluxOpt {
}) })
} catch (error) { } catch (error) {
let errorMsg = "FLUX FORGE 生成图片失败,错误信息如下:" + error.toString() let errorMsg = "FLUX FORGE 生成图片失败,错误信息如下:" + error.toString()
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "", mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "",
progress: 0, progress: 0,
@ -171,6 +172,11 @@ export class FluxOpt {
status: "error", status: "error",
message: errorMsg message: errorMsg
}) })
await this.bookServiceBasic.UpdateTaskStatus({
id: task.id,
status: BookBackTaskStatus.FAIL,
errorMessage: errorMsg
});
global.newWindow[0].win.webContents.send(task.messageName, { global.newWindow[0].win.webContents.send(task.messageName, {
code: 0, code: 0,

View File

@ -318,4 +318,65 @@ export class GptService {
} }
} }
//#endregion //#endregion
//#region 聚合推文 文案洗稿
/**
* 稿
* @param word
* @returns
*/
async GenerateAfterGptWordByGPT(word: string,) {
try {
let prompt = `## - Role: 文案去重
<Background>:
##
1.
2.
3.
4.
##
1
输出1: 雌性每洞房一次
2
输出2: 我重生后的第一件事就是生吞羊辣子
3SSS级异能紫霄神器
输出3: 我明明觉醒了sss级暗黑系异能
3
输出3: 我爷爷觉醒了s级凶兽黄金朱厌ss级神兽泰坦巨猿
输入5: 一个先天满属性的天才却被称为废物
输出5: 一个先天满属性的天才却被称为废物
##
<要求><示例><要求>Ai部分
`;
let message = [
{
"role": "system",
"content": prompt,
}, {
"role": "user",
"content": word
}
]
// 开始请求这个默认是使用的是LAI API的gpt-4o-mini
let content = await RetryWithBackoff<string>(async () => {
return await this.FetchGpt(message, null, null, null);
}, 5, 2000)
return content;
} catch (error) {
throw error
}
}
//#endregion
} }

View File

@ -660,7 +660,7 @@ export class MJOpt {
data: task_res data: task_res
}, task.messageName); }, task.messageName);
// 当获取的图片的进度小于100的时候等待5秒继续监听 // 当获取的图片的进度小于100的时候等待5秒继续监听
await new Promise(resolve => setTimeout(resolve, 5000)); await new Promise(resolve => setTimeout(resolve, 9000));
} catch (error) { } catch (error) {
throw error; throw error;
} }

View File

@ -369,7 +369,6 @@ export class SDOpt {
action: MJAction.IMAGINE, action: MJAction.IMAGINE,
status: "error", status: "error",
message: errorMsg, message: errorMsg,
id: task.bookTaskDetailId
}) })
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {

View File

@ -1,6 +1,8 @@
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "../../../define/enum/bookEnum"; import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "../../../define/enum/bookEnum";
import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService"; import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService";
import { Book } from "../../../model/book"; import { Book } from "../../../model/book";
import { TaskModal } from "@/model/task";
import { cloneDeep, isEmpty } from "lodash";
export default class BookBackTaskServiceBasic { export default class BookBackTaskServiceBasic {
bookBackTaskListService: BookBackTaskListService bookBackTaskListService: BookBackTaskListService
@ -57,6 +59,29 @@ export default class BookBackTaskServiceBasic {
this.bookBackTaskListService.UpdateTaskStatus(bookBackTask) this.bookBackTaskListService.UpdateTaskStatus(bookBackTask)
} }
/**
*
* @param messageName
* @param errorMessage
*/
async SetMessageNameTaskToFail(messageName: string, errorMessage: string) {
console.log(messageName, errorMessage)
await this.InitService();
let tasks = this.bookBackTaskListService.realm.objects('BookBackTaskList').filtered('messageName == $0 ', messageName)
tasks = tasks.filtered('status != $0', BookBackTaskStatus.DONE);
tasks = tasks.filtered('status != $0', BookBackTaskStatus.FAIL);
let ids = tasks.map((item) => {
return item.id
})
this.bookBackTaskListService.transaction(() => {
for (let i = 0; i < ids.length; i++) {
let task = this.bookBackTaskListService.realm.objectForPrimaryKey('BookBackTaskList', ids[i]);
task.status = BookBackTaskStatus.FAIL
task.errorMessage = errorMessage
}
})
}
/** /**
* *
*/ */
@ -75,4 +100,86 @@ export default class BookBackTaskServiceBasic {
} }
}) })
} }
/**
*
* @param queryTaskCondition
*/
GetBackTaskCollection(queryTaskCondition: TaskModal.QueryTaskCondition): TaskModal.TaskCollection {
let tasks = this.bookBackTaskListService.realm.objects('BookBackTaskList');
if (!isEmpty(queryTaskCondition.bookName)) {
let book = this.bookBackTaskListService.realm.objects('Book').filtered('name CONTAINS[c] $0', queryTaskCondition.bookName);
let ids = [] as string[]
if (book.length > 0) {
ids = book.map((item) => {
return item.id as string
})
}
tasks = tasks.filtered('bookId in $0', ids);
}
if (!isEmpty(queryTaskCondition.bookTaskName)) {
let bookTask = this.bookBackTaskListService.realm.objects('BookTask').filtered('name CONTAINS[c] $0', queryTaskCondition.bookTaskName);
let ids = [] as string[]
if (bookTask.length > 0) {
ids = bookTask.map((item) => {
return item.id as string
})
}
tasks = tasks.filtered('bookTaskId in $0', ids);
}
if (!isEmpty(queryTaskCondition.bookTaskDetailName)) {
let bookTaskDetail = this.bookBackTaskListService.realm.objects('BookTaskDetail').filtered('name CONTAINS[c] $0', queryTaskCondition.bookTaskDetailName);
let ids = [] as string[]
if (bookTaskDetail.length > 0) {
ids = bookTaskDetail.map((item) => {
return item.id as string
})
}
tasks = tasks.filtered('bookTaskDetailId in $0', ids);
}
if (!isEmpty(queryTaskCondition.taskName)) {
tasks = tasks.filtered('name CONTAINS[c] $0', queryTaskCondition.taskName);
}
if (!isEmpty(queryTaskCondition.taskType)) {
tasks = tasks.filtered('type == $0', queryTaskCondition.taskType);
}
if (!isEmpty(queryTaskCondition.taskStatus)) {
tasks = tasks.filtered('status == $0', queryTaskCondition.taskStatus);
}
if (!isEmpty(queryTaskCondition.taskErrorMessage)) {
tasks = tasks.filtered('errorMessage CONTAINS[c] $0', queryTaskCondition.taskErrorMessage);
}
let count = tasks.length
tasks = tasks.sorted('createTime', true)
let task = tasks.slice((queryTaskCondition.page - 1) * queryTaskCondition.pageSize, queryTaskCondition.page * queryTaskCondition.pageSize) as TaskModal.BackTaskCollection[];
let taskList = Array.from(task).map((item) => {
let resObj = {
...item,
} as TaskModal.BackTaskCollection
return cloneDeep(resObj)
})
for (let i = 0; i < taskList.length; i++) {
const element = taskList[i];
let book = this.bookBackTaskListService.realm.objectForPrimaryKey('Book', element.bookId)
if (book) {
element.bookName = book.name as string;
}
let bookTask = this.bookBackTaskListService.realm.objectForPrimaryKey('BookTask', element.bookTaskId);
if (bookTask) {
element.bookTaskName = bookTask.name as string;
}
let bookTaskDetail = this.bookBackTaskListService.realm.objectForPrimaryKey('BookTaskDetail', element.bookTaskDetailId);
if (bookTaskDetail) {
element.bookTaskDetailName = bookTaskDetail.name as string;
}
}
return {
page: queryTaskCondition.page,
pageSize: queryTaskCondition.pageSize,
count: count,
data: taskList
}
}
} }

View File

@ -7,6 +7,7 @@ import BookBackTaskServiceBasic from "./bookBackTaskServiceBasic";
import { BookBasic } from "./bookBasic"; import { BookBasic } from "./bookBasic";
import BookTaskServiceBasic from "./bookTaskServiceBasic"; import BookTaskServiceBasic from "./bookTaskServiceBasic";
import BookTaskDetailServiceBasic from "./bookTaskDetailServiceBasic"; import BookTaskDetailServiceBasic from "./bookTaskDetailServiceBasic";
import { TaskModal } from "@/model/task";
/** /**
* *
@ -90,6 +91,10 @@ class BookServiceBasic {
UpdateTaskStatus = async (bookBackTask: Book.UpdateBookTaskListStatus) => await this.bookBackTaskServiceBasic.UpdateTaskStatus(bookBackTask); UpdateTaskStatus = async (bookBackTask: Book.UpdateBookTaskListStatus) => await this.bookBackTaskServiceBasic.UpdateTaskStatus(bookBackTask);
GiveUpNotStartBackTask = async () => await this.bookBackTaskServiceBasic.GiveUpNotStartBackTask(); GiveUpNotStartBackTask = async () => await this.bookBackTaskServiceBasic.GiveUpNotStartBackTask();
/** 设置指定的消息名称的任务状态为错误及错误信息 */
SetMessageNameTaskToFail = async (massageName: string, errorMessage: string) => await this.bookBackTaskServiceBasic.SetMessageNameTaskToFail(massageName, errorMessage);
/** 查询指定的条件的后台任务 */
GetBackTaskCollection = async (queryTaskCondition: TaskModal.QueryTaskCondition) => await this.bookBackTaskServiceBasic.GetBackTaskCollection(queryTaskCondition);
//#endregion //#endregion
} }
export { BookServiceBasic }; export { BookServiceBasic };

View File

@ -179,6 +179,9 @@ export class SubtitleService {
default: default:
throw new Error("未知的识别字幕模式") throw new Error("未知的识别字幕模式")
} }
if (res.code == 0) {
throw new Error(res.message)
}
if (operateBookType == OperateBookType.BOOKTASKDETAIL) { if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskId) let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskId)
return successMessage(bookTaskDetail.afterGpt, "获取文案成功", "ReverseBook_GetCopywriting") return successMessage(bookTaskDetail.afterGpt, "获取文案成功", "ReverseBook_GetCopywriting")

View File

@ -32,7 +32,7 @@ export default class ElectronInterface {
/** /**
* *
* @param params * @param params
* @returns * @returns
*/ */
public async OpenFolder(params: OpenFolderParams) { public async OpenFolder(params: OpenFolderParams) {
try { try {

View File

@ -1,3 +1,4 @@
import { TaskModal } from "@/model/task";
import { BookBackTaskStatus } from "../../../define/enum/bookEnum"; import { BookBackTaskStatus } from "../../../define/enum/bookEnum";
import { GeneralResponse } from "../../../model/generalResponse"; import { GeneralResponse } from "../../../model/generalResponse";
import { errorMessage, successMessage } from "../../Public/generalTools"; import { errorMessage, successMessage } from "../../Public/generalTools";
@ -10,6 +11,7 @@ export default class BackTaskService {
this.bookServiceBasic = new BookServiceBasic() this.bookServiceBasic = new BookServiceBasic()
} }
//#region 获取指定状态的后台任务数量
/** /**
* *
*/ */
@ -23,6 +25,9 @@ export default class BackTaskService {
} }
} }
//#endregion
//#region 启动后台任务
/** /**
* *
* @param isGiveUp * @param isGiveUp
@ -44,4 +49,14 @@ export default class BackTaskService {
return errorMessage('启动后台任务失败', 'BackTaskService_StartBackTask') return errorMessage('启动后台任务失败', 'BackTaskService_StartBackTask')
} }
} }
//#endregion
public async GetBackTaskCollection(queryTaskCondition: TaskModal.QueryTaskCondition) {
try {
let res = await this.bookServiceBasic.GetBackTaskCollection(queryTaskCondition);
return successMessage(res, '获取后台任务集合成功', 'BackTaskService_GetBackTaskCollection');
} catch (error) {
return errorMessage('获取后台任务集合失败,失败信息如下:' + error.toString(), 'BackTaskService_GetBackTaskCollection')
}
}
} }

View File

@ -14,6 +14,8 @@ import { AsyncQueue } from '../../quene'
import { SoftWareServiceBasic } from '../ServiceBasic/softwareServiceBasic' import { SoftWareServiceBasic } from '../ServiceBasic/softwareServiceBasic'
import { MJSetting } from '../../../model/Setting/mjSetting' import { MJSetting } from '../../../model/Setting/mjSetting'
import { BookVideo } from '../Book/bookVideo' import { BookVideo } from '../Book/bookVideo'
import { BookServiceBasic } from '../ServiceBasic/bookServiceBasic'
import { TaskModal } from '@/model/task'
export class TaskManager { export class TaskManager {
isExecuting: boolean = false; isExecuting: boolean = false;
@ -26,6 +28,7 @@ export class TaskManager {
eventListeners: Record<string | number, Function[]> = {}; eventListeners: Record<string | number, Function[]> = {};
softWareServiceBasic: SoftWareServiceBasic softWareServiceBasic: SoftWareServiceBasic
bookVideo: BookVideo bookVideo: BookVideo
bookServiceBasic: BookServiceBasic
mjSetting: MJSetting.MjSetting mjSetting: MJSetting.MjSetting
spaceTime: number = 5000; spaceTime: number = 5000;
@ -48,6 +51,7 @@ export class TaskManager {
this.d3Opt = new D3Opt() this.d3Opt = new D3Opt()
this.softWareServiceBasic = new SoftWareServiceBasic(); this.softWareServiceBasic = new SoftWareServiceBasic();
this.fluxOpt = new FluxOpt() this.fluxOpt = new FluxOpt()
this.bookServiceBasic = new BookServiceBasic();
} }
async InitService(getMJsetting = false) { async InitService(getMJsetting = false) {
@ -63,6 +67,16 @@ export class TaskManager {
} }
} }
/**
*
*
* @param messageName
*/
async ErrorTaskHandle(messageName: string, ems: string, bsb: BookServiceBasic) {
debugger
bsb.SetMessageNameTaskToFail(messageName, ems);
}
// 初始化事件监听方法 // 初始化事件监听方法
InitListeners() { InitListeners() {
if (this.isListening) return; // 如果已经在监听,直接返回 if (this.isListening) return; // 如果已经在监听,直接返回
@ -201,7 +215,6 @@ export class TaskManager {
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.basicReverse.ExtractSubtitlesData(task); await this.basicReverse.ExtractSubtitlesData(task);
}, `${batch}_${task.id}`, batch) }, `${batch}_${task.id}`, batch)
} }
/** /**
@ -209,10 +222,10 @@ export class TaskManager {
* @param task * @param task
*/ */
AddSingleReversePrompt(task: TaskModal.Task): void { AddSingleReversePrompt(task: TaskModal.Task): void {
let batch = DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT; let batch = task.messageName;
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.reverseBook.SingleReversePrompt(task); await this.reverseBook.SingleReversePrompt(task);
}, `${batch}_${task.id}`, batch) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail);
} }
/** /**
@ -221,10 +234,10 @@ export class TaskManager {
*/ */
async AddImageMJImage(task: TaskModal.Task) { async AddImageMJImage(task: TaskModal.Task) {
// 判断是不是MJ的任务 // 判断是不是MJ的任务
let batch = DEFINE_STRING.MJ.MJ_IMAGE; let batch = task.messageName;
global.mjQueue.enqueue(async () => { global.mjQueue.enqueue(async () => {
await this.mjOpt.MJImagine(task); await this.mjOpt.MJImagine(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`); }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail);
} }
@ -233,10 +246,10 @@ export class TaskManager {
* @param task * @param task
*/ */
async AddSDImage(task: TaskModal.Task) { async AddSDImage(task: TaskModal.Task) {
let batch = DEFINE_STRING.SD.TXT2IMG let batch = task.messageName;
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.sdOpt.SDImageGenerate(task); await this.sdOpt.SDImageGenerate(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail)
} }
/** /**
@ -251,7 +264,7 @@ export class TaskManager {
let batch = task.messageName; let batch = task.messageName;
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.d3Opt.D3ImageGenerate(task); await this.d3Opt.D3ImageGenerate(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail);
} }
/** 添加生成视频的后台任务 */ /** 添加生成视频的后台任务 */
@ -260,7 +273,7 @@ export class TaskManager {
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
this.bookVideo = new BookVideo(); this.bookVideo = new BookVideo();
await this.bookVideo.GenerateVideo(task); await this.bookVideo.GenerateVideo(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail)
} }
@ -269,10 +282,10 @@ export class TaskManager {
* @param task * @param task
*/ */
async AddFluxForgeImage(task: TaskModal.Task) { async AddFluxForgeImage(task: TaskModal.Task) {
let batch = task.messageName let batch = task.messageName;
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.fluxOpt.FluxForgeImage(task); await this.fluxOpt.FluxForgeImage(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail)
} }
/** /**
@ -283,7 +296,7 @@ export class TaskManager {
let batch = task.messageName; let batch = task.messageName;
global.requestQuene.enqueue(async () => { global.requestQuene.enqueue(async () => {
await this.fluxOpt.FluxAPIImage(task); await this.fluxOpt.FluxAPIImage(task);
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`, this.bookServiceBasic.SetMessageNameTaskToFail)
} }
/** /**

View File

@ -683,6 +683,8 @@ async function SaveSDConfig(value) {
sd_config.webui.width = value.width ? value.width : sd_config.webui.width sd_config.webui.width = value.width ? value.width : sd_config.webui.width
sd_config.webui.height = value.height ? value.height : sd_config.webui.height sd_config.webui.height = value.height ? value.height : sd_config.webui.height
sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale
sd_config.webui.batch_size = value.batch_size ? value.batch_size : sd_config.webui.batch_size
sd_config.setting.seed = value.seed ? value.seed : sd_config.setting.seed
sd_config.webui.adetailer = value.hasOwnProperty('adetailer') sd_config.webui.adetailer = value.hasOwnProperty('adetailer')
? value.adetailer ? value.adetailer
: sd_config.webui.adetailer : sd_config.webui.adetailer
@ -695,6 +697,7 @@ async function SaveSDConfig(value) {
} else { } else {
sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX
} }
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config)) await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config))
return { return {
code: 1, code: 1,

View File

@ -19,7 +19,7 @@ export class AsyncQueue {
this.taskProgress = [] this.taskProgress = []
} }
async enqueue(task, taskId, batchId, subBatchId = 'default') { async enqueue(task, taskId, batchId, subBatchId = 'default', errorFunc = null) {
if (batchId && batchId != DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER) { if (batchId && batchId != DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER) {
// 判断当前的任务是否已经存在,存在则不添加 // 判断当前的任务是否已经存在,存在则不添加
let index = this.tasks.findIndex( let index = this.tasks.findIndex(
@ -44,7 +44,7 @@ export class AsyncQueue {
this.batchCompletion[batchId].remaining++ this.batchCompletion[batchId].remaining++
this.batchCompletion[batchId].subBatches[subBatchId].remaining++ this.batchCompletion[batchId].subBatches[subBatchId].remaining++
this.tasks.push({ task, taskId, batchId, subBatchId }) this.tasks.push({ task, taskId, batchId, subBatchId, errorFunc })
if (!this.manualMode) { if (!this.manualMode) {
await this.process() await this.process()
} }
@ -95,7 +95,7 @@ export class AsyncQueue {
? this.taskProgress.length < task_count ? this.taskProgress.length < task_count
: this.currentConcurrency < this.concurrencyLimit) : this.currentConcurrency < this.concurrencyLimit)
) { ) {
const { task, taskId, batchId, subBatchId } = this.tasks.shift() const { task, taskId, batchId, subBatchId, errorFunc } = this.tasks.shift()
this.currentConcurrency++ this.currentConcurrency++
Promise.resolve(task()) Promise.resolve(task())
.then(() => { .then(() => {
@ -132,6 +132,13 @@ export class AsyncQueue {
// console.error(`Task ${taskId} failed after ${maxRetryCount} retries`); // console.error(`Task ${taskId} failed after ${maxRetryCount} retries`);
this.currentConcurrency-- this.currentConcurrency--
this.handleTaskCompletion(batchId, subBatchId, { taskId, error }) this.handleTaskCompletion(batchId, subBatchId, { taskId, error })
// 执行传入的错误后执行方法,一般用于修改后台任务或者是批量提示
if (errorFunc) {
errorFunc(
batchId,
`任务 ${taskId} 执行失败,错误信息:${error.toString()}开始清理整个批次批次ID${batchId}`
)
}
if (!this.manualMode) { if (!this.manualMode) {
this.process() this.process()
} }
@ -151,6 +158,13 @@ export class AsyncQueue {
// 出现报错。直接停掉当前对应的的子批次 // 出现报错。直接停掉当前对应的的子批次
this.currentConcurrency-- this.currentConcurrency--
this.handleTaskCompletion(batchId, subBatchId, { taskId, error }) this.handleTaskCompletion(batchId, subBatchId, { taskId, error })
// 执行传入的错误后执行方法,一般用于修改后台任务或者是批量提示
if (errorFunc) {
errorFunc(
batchId,
`任务 ${taskId} 执行失败,错误信息:${error.toString()}开始清理整个批次批次ID${batchId}`
)
}
if (!this.manualMode) { if (!this.manualMode) {
this.process() this.process()
} else { } else {

View File

@ -40,5 +40,6 @@ declare namespace SoftwareSettingModel {
gpt_key: string = undefined // GPT KEY, gpt_key: string = undefined // GPT KEY,
laiApiSelect: string = undefined // LaiAPI选择 laiApiSelect: string = undefined // LaiAPI选择
hdScale: number = 2 // HD缩放 hdScale: number = 2 // HD缩放
defaultImageMode: BookImageCategory = 'mj' // 默认图片模式
} }
} }

31
src/model/task.d.ts vendored
View File

@ -1,6 +1,7 @@
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "@/define/enum/bookEnum"
declare namespace TaskModal { declare namespace TaskModal {
type Task = { interface Task {
id?: string id?: string
bookId?: string bookId?: string
bookTaskId?: string bookTaskId?: string
@ -16,4 +17,32 @@ declare namespace TaskModal {
endTime?: number, endTime?: number,
messageName?: string messageName?: string
} }
interface TaskCondition {
bookName?: string,
bookTaskName?: string,
bookTaskDetailName?: string,
taskName?: string,
taskType?: BookBackTaskType,
taskStatus?: BookBackTaskStatus,
taskErrorMessage?: string
}
interface QueryTaskCondition extends TaskCondition {
page: number,
pageSize: number
}
interface BackTaskCollection extends Task {
bookName?: string
bookTaskName?: string
bookTaskDetailName?: string
}
type TaskCollection = {
page: number,
pageSize: number,
count: number,
data: BackTaskCollection[]
}
} }

View File

@ -179,6 +179,9 @@ const book = {
GetImageUrlAndDownload: async (id: string, operateBookType: OperateBookType, coverData: boolean) => GetImageUrlAndDownload: async (id: string, operateBookType: OperateBookType, coverData: boolean) =>
await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD, id, operateBookType, coverData), await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD, id, operateBookType, coverData),
/** 添加一键生图后台任务 */
GenerateAllTaskImage: async (ids: string[], operateBookType: OperateBookType) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.GENERATE_ALL_TASK_IMAGE, ids, operateBookType),
//#endregion //#endregion
//#region 一键反推的单个任务 //#region 一键反推的单个任务

View File

@ -1,6 +1,7 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { DEFINE_STRING } from '../define/define_string' import { DEFINE_STRING } from '../define/define_string'
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from '../define/enum/bookEnum' import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from '../define/enum/bookEnum'
import { TaskModal } from '@/model/task'
const task = { const task = {
@ -10,16 +11,8 @@ const task = {
* @returns * @returns
*/ */
StartBackTask: async (isGiveUp: boolean) => await ipcRenderer.invoke(DEFINE_STRING.TASK.START_BACK_TASK, isGiveUp), StartBackTask: async (isGiveUp: boolean) => await ipcRenderer.invoke(DEFINE_STRING.TASK.START_BACK_TASK, isGiveUp),
/**
* /** 添加单个任务 */
* @param bookId ID
* @param taskType
* @param executeType
* @param bookTaskId ID
* @param bookTaskDetailId ID
* @param responseMessageName
* @returns
*/
AddBookBackTask: async (bookId: string, taskType: BookBackTaskType, AddBookBackTask: async (bookId: string, taskType: BookBackTaskType,
executeType = TaskExecuteType.AUTO, executeType = TaskExecuteType.AUTO,
bookTaskId = null, bookTaskId = null,
@ -27,14 +20,14 @@ const task = {
responseMessageName: string = null) => responseMessageName: string = null) =>
await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName), await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName),
/** /** 同时添加多个任务 */
*
* @param task
*/
AddMultiBookBackTask: async (task: TaskModal.Task[]) => AddMultiBookBackTask: async (task: TaskModal.Task[]) =>
await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, task), await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, task),
/** 获取等待中的任务 */ /** 获取等待中的任务 */
GetAllStatusTaskCount: async (value: BookBackTaskStatus[]) => await ipcRenderer.invoke(DEFINE_STRING.TASK.GET_ALL_STATUS_TASK_COUNT, value), GetAllStatusTaskCount: async (value: BookBackTaskStatus[]) => await ipcRenderer.invoke(DEFINE_STRING.TASK.GET_ALL_STATUS_TASK_COUNT, value),
/** 获取后台任务的集合,分页 */
GetBackTaskCollection: async (queryTaskCondition: TaskModal.QueryTaskCondition) => await ipcRenderer.invoke(DEFINE_STRING.TASK.GET_BACK_TASK_COLLECTION, queryTaskCondition),
} }
export { task } export { task }

View File

@ -30,7 +30,13 @@ const write = {
// 开始执行API相关的一系列任务 // 开始执行API相关的一系列任务
ActionStart(aiSetting, word) { ActionStart(aiSetting, word) {
return ipcRenderer.invoke(DEFINE_STRING.WRITE.ACTION_START, aiSetting, word) return ipcRenderer.invoke(DEFINE_STRING.WRITE.ACTION_START, aiSetting, word)
} },
//#endregion
//#region 文案洗稿相关
/** 生成洗稿后文案 */
GenerateAfterGptWord: async (ids: string[], isEmpty: boolean) => await ipcRenderer.invoke(DEFINE_STRING.WRITE.GENERATE_AFTER_GPT_WORD, ids, isEmpty),
//#endregion //#endregion
} }

View File

@ -0,0 +1,19 @@
<script setup>
import { onMounted, ref } from 'vue'
import TaskDataTable from './TaskDataTable.vue'
let props = defineProps({
height: undefined
})
let height = ref(props.height - 220)
onMounted(() => {
//
// height.value = props.height - 200
console.log(height.value)
})
</script>
<template>
<TaskDataTable :height="height" />
</template>

View File

@ -0,0 +1,247 @@
<template>
<n-form
ref="formRef"
inline
:label-width="80"
:model="softwareStore.backTask.queryData"
size="small"
style="min-width: 600px"
>
<n-grid x-gap="12" y-gap="0" cols="5">
<n-grid-item>
<n-form-item label="任务名称" path="taskName">
<n-input
v-model:value="softwareStore.backTask.queryData.taskName"
placeholder="请输入任务名称"
/>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="小说名" path="bookId">
<n-input
v-model:value="softwareStore.backTask.queryData.bookName"
placeholder="请输入小说名称"
/>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="小说批次任务" path="bookTaskId">
<n-input
v-model:value="softwareStore.backTask.queryData.bookTaskName"
placeholder="请输入小说批次任务名称"
/>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="小说分镜名称" path="bookTaskId">
<n-input
v-model:value="softwareStore.backTask.queryData.bookTaskDetailName"
placeholder="请输入小说分镜名称"
/>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="任务类型" path="taskType">
<n-select
v-model:value="softwareStore.backTask.queryData.taskType"
placeholder="请选择小说任务类型"
:options="taskTypeOptions"
clearable="true"
>
</n-select>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="任务状态" path="taskStatus">
<n-select
v-model:value="softwareStore.backTask.queryData.taskStatus"
placeholder="请选择小说任务类型"
:options="taskStatusOptions"
clearable="true"
></n-select>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item label="任务失败原因" path="taskErrorMessage">
<n-input
v-model:value="softwareStore.backTask.queryData.taskErrorMessage"
placeholder="请输入小说失败原因"
/>
</n-form-item>
</n-grid-item>
<n-grid-item>
<n-form-item path="taskErrorMessage">
<n-button type="info" @click="ResetQuery">重置</n-button>
<n-button style="margin-left: 10px" type="info" @click="QueryByByCondition"
>查询</n-button
>
</n-form-item>
</n-grid-item>
</n-grid>
</n-form>
<n-data-table
remote
ref="table"
:columns="columns"
:data="softwareStore.backTask.taskData"
:loading="loading"
:pagination="pagination"
:row-key="rowKey"
@update:page="handlePageChange"
:style="{ height: `${height}px` }"
flex-height
:scroll-x="1000"
/>
</template>
<script setup>
import { h, onMounted, reactive, ref, render } from 'vue'
import {
NDataTable,
useMessage,
NForm,
NFormItem,
NInput,
NButton,
NGrid,
NGridItem,
NSelect
} from 'naive-ui'
import { useSoftwareStore } from '@/stores/software'
import {
BookBackTaskStatus,
BookBackTaskType,
GetBookBackTaskStatusLabel,
GetBookBackTaskTypeLabel
} from '@/define/enum/bookEnum'
let softwareStore = useSoftwareStore()
let message = useMessage()
let loading = ref(true)
let props = defineProps({
height: undefined
})
let height = ref(props.height)
let columns = [
{
title: '任务名(小说名+批次任务名+分镜名+任务类型)',
key: 'name',
width: '350px'
},
{
title: '消息名称',
key: 'messageName',
minWidth: 200,
ellipsis: {
tooltip: true
}
},
{
title: '任务类型',
key: 'type',
minWidth: 100
},
{
title: '状态',
key: 'status',
minWidth: 100
},
{
title: '失败原因',
key: 'errorMessage',
minWidth: 300,
ellipsis: {
tooltip: true
}
}
]
async function ResetQuery() {
softwareStore.ResetBackTaskQueryData()
await query(1, pagination.value.pageSize)
}
async function QueryByByCondition() {
await query(1, pagination.value.pageSize)
}
async function query(page, pageSize = 10) {
try {
loading.value = true
let res = await window.task.GetBackTaskCollection({
page,
pageSize,
...softwareStore.backTask.queryData
})
console.log(res)
if (res.code == 0) {
message.error(res.message)
} else {
softwareStore.backTask.taskData = res.data.data
pagination.value.page = page
pagination.value.pageCount = Math.ceil(res.data.count / pageSize)
pagination.value.itemCount = res.data.count
}
} catch (error) {
message.error(error.message)
} finally {
loading.value = false
}
}
const pagination = ref({
page: 1,
pageCount: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 20, 50, 100, 200, 500],
prefix({ itemCount }) {
return `Total is ${itemCount}.`
},
onUpdatePageSize: async (pageSize) => {
pagination.value.pageSize = pageSize
await handlePageChange(pagination.value.page)
}
})
onMounted(async () => {
debugger
height.value = props.height
console.log(height.value)
await query(pagination.value.page, pagination.value.pageSize)
})
let rowKey = (rowData) => rowData.column1
async function handlePageChange(currentPage) {
if (!loading.value) {
loading.value = true
await query(currentPage, pagination.value.pageSize)
pagination.value.page = currentPage
pagination.value.pageSize = pagination.value.pageSize
}
}
let GetBookBackTaskType = () => {
let options = []
for (const key in BookBackTaskType) {
options.push({
label: GetBookBackTaskTypeLabel(BookBackTaskType[key]),
value: BookBackTaskType[key]
})
}
return options
}
let taskTypeOptions = GetBookBackTaskType()
let GeBookBackTaskStatus = () => {
let options = []
for (const key in BookBackTaskStatus) {
options.push({
label: GetBookBackTaskStatusLabel(BookBackTaskStatus[key]),
value: BookBackTaskStatus[key]
})
}
return options
}
let taskStatusOptions = GeBookBackTaskStatus()
</script>

View File

@ -99,7 +99,6 @@ export default defineComponent({
// //
let dialogWidth = window.innerWidth * 0.7 let dialogWidth = window.innerWidth * 0.7
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -397,7 +397,6 @@ export default defineComponent({
// //
let dialogWidth = window.innerWidth * 0.8 let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -479,7 +478,6 @@ export default defineComponent({
// //
let dialogWidth = 800 let dialogWidth = 800
let dialogHeight = 600 let dialogHeight = 600
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -652,7 +652,6 @@ export default defineComponent({
// //
let dialogWidth = window.innerWidth * 0.7 let dialogWidth = window.innerWidth * 0.7
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -51,7 +51,6 @@ async function EditBook(e) {
reverseManageStore.SetSelectBook(toRaw(book.value)) reverseManageStore.SetSelectBook(toRaw(book.value))
// //
let dialogWidth = 600 let dialogWidth = 600
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -83,11 +83,10 @@ export default defineComponent({
reverseManageStore.SetSelectBook({ reverseManageStore.SetSelectBook({
name: null, name: null,
id: null, id: null,
type: BookType.MJ_REVERSE type: BookType.ORIGINAL,
}) })
// //
let dialogWidth = 600 let dialogWidth = 600
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -103,7 +102,7 @@ export default defineComponent({
*/ */
async function DataTableStripedUpdate() { async function DataTableStripedUpdate() {
// //
// //
let res = await softwareStore.SaveSoftware() let res = await softwareStore.SaveSoftware()
console.log(res) console.log(res)
@ -115,7 +114,6 @@ export default defineComponent({
// //
async function SelectDropdown(key) { async function SelectDropdown(key) {
console.log(key) console.log(key)
softwareStore.softWare.reverse_data_table_size = key softwareStore.softWare.reverse_data_table_size = key
// //

View File

@ -7,7 +7,7 @@
</div> </div>
</template> </template>
<template #2> <template #2>
<div style="margin-left: 20px"> <div style="margin-left: 20px; min-width: 500px; overflow: auto">
<AddCharacterTag <AddCharacterTag
v-if="currentType.startsWith('character')" v-if="currentType.startsWith('character')"
:currentCharacter="currentCharacter" :currentCharacter="currentCharacter"

View File

@ -243,8 +243,6 @@ async function SelectReversePrompt() {
message.error('当前没有反推提示词') message.error('当前没有反推提示词')
return return
} }
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
title: `重选MJ反推提示词 ${data.value.name}`, title: `重选MJ反推提示词 ${data.value.name}`,

View File

@ -6,7 +6,7 @@
size="tiny" size="tiny"
:options="image_options" :options="image_options"
@update:value="UpdateImageGenerateCategory" @update:value="UpdateImageGenerateCategory"
v-model:value="reverseManageStore.selectBookTask.imageCategory" v-model:value="select"
placeholder="选择生图模式" placeholder="选择生图模式"
></n-select> ></n-select>
<div v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'"> <div v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'">
@ -38,7 +38,7 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted, computed } from 'vue'
import { NSelect, NButton, useMessage, useDialog, NPopover, NIcon } from 'naive-ui' import { NSelect, NButton, useMessage, useDialog, NPopover, NIcon } from 'naive-ui'
import { useSoftwareStore } from '../../../../../stores/software' import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage' import { useReverseManageStore } from '../../../../../stores/reverseManage'
@ -50,6 +50,12 @@ let dialog = useDialog()
let reverseManageStore = useReverseManageStore() let reverseManageStore = useReverseManageStore()
let image_options = ref([]) let image_options = ref([])
let select = computed(() =>
reverseManageStore.selectBookTask.imageCategory
? reverseManageStore.selectBookTask.imageCategory
: softwareStore.globalSetting.defaultImageMode
)
onMounted(async () => { onMounted(async () => {
// //
await window.api.GetImageGenerateCategory((value) => { await window.api.GetImageGenerateCategory((value) => {
@ -68,6 +74,7 @@ async function UpdateImageGenerateCategory(value, options) {
imageCategory: value imageCategory: value
}) })
window.api.showGlobalMessage(res) window.api.showGlobalMessage(res)
reverseManageStore.selectBookTask.imageCategory = value
} }
async function DownloadAllImage() { async function DownloadAllImage() {

View File

@ -172,6 +172,7 @@ async function SelectPromptIndex() {
title: '选择反推提示词', title: '选择反推提示词',
content: () => h(SelectMJReversePrompt), content: () => h(SelectMJReversePrompt),
style: 'width : 500px', style: 'width : 500px',
maskClosable: false,
showIcon: false showIcon: false
}) })
} }
@ -183,7 +184,6 @@ async function SelectStyle() {
// //
let dialogWidth = window.innerWidth * 0.8 let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -45,11 +45,12 @@ export default defineComponent({
let select = computed(() => let select = computed(() =>
reverseManageStore.selectBookTask.imageCategory reverseManageStore.selectBookTask.imageCategory
? reverseManageStore.selectBookTask.imageCategory ? reverseManageStore.selectBookTask.imageCategory
: BookImageCategory.MJ : softwareStore.globalSetting.defaultImageMode
) )
let options = ref([]) let options = ref([])
onMounted(async () => { onMounted(async () => {
debugger
// //
await window.api.GetImageGenerateCategory((value) => { await window.api.GetImageGenerateCategory((value) => {
if (value.code == 0) { if (value.code == 0) {

View File

@ -1,7 +1,14 @@
<template> <template>
<div style="display: flex; justify-content: space-between; align-items: center"> <div style="display: flex; justify-content: space-between; align-items: center">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<n-button strong secondary @click="RetuenMain" size="small"> 返回 </n-button> <n-button strong secondary @click="RetuenMain" size="small">
{{
'返回 | ' +
reverseManageStore.selectBook?.name +
'_' +
reverseManageStore.selectBookTask?.name
}}
</n-button>
<!-- <n-dropdown trigger="hover" :options="AutoOptions" @select="SelectAutoAction"> <!-- <n-dropdown trigger="hover" :options="AutoOptions" @select="SelectAutoAction">
<n-button :color="softwareStore.SoftColor.ORANGE" @click="Start" style="margin-left: 5px"> <n-button :color="softwareStore.SoftColor.ORANGE" @click="Start" style="margin-left: 5px">
自动开始 自动开始
@ -206,6 +213,7 @@ async function ComputeStoryboard() {
async function JianyingFrame() { async function JianyingFrame() {
let da = dialog.info({ let da = dialog.info({
title: '剪映分镜参数', title: '剪映分镜参数',
maskClosable: false,
content: () => h(JianyingFrameOption) content: () => h(JianyingFrameOption)
}) })
} }
@ -403,7 +411,6 @@ async function GetWatermarkPosition() {
// //
let dialogWidth = window.innerWidth * 0.7 let dialogWidth = window.innerWidth * 0.7
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -806,6 +813,7 @@ async function ImportWordAndSrtFunc() {
let tempData = [] let tempData = []
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) { for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
debugger
const element = reverseManageStore.selectBookTaskDetail[i] const element = reverseManageStore.selectBookTaskDetail[i]
tempData.push({ tempData.push({
no: element.no, no: element.no,
@ -820,7 +828,6 @@ async function ImportWordAndSrtFunc() {
}) })
} }
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -54,6 +54,7 @@ async function OpenGetVideoFrame() {
dialog.create({ dialog.create({
title: '获取视频的帧', title: '获取视频的帧',
style: 'width : 800px;', style: 'width : 800px;',
maskClosable: false,
content: () => content: () =>
h(GetVideoFrame, { h(GetVideoFrame, {
videoPath: data.value.videoPath, videoPath: data.value.videoPath,

View File

@ -3,6 +3,9 @@
<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="GenerateAllTaskImage()"
>一键生图</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
> >
@ -55,7 +58,7 @@ import {
} from 'naive-ui' } from 'naive-ui'
import { useReverseManageStore } from '../../../../stores/reverseManage' import { useReverseManageStore } from '../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../stores/software' import { useSoftwareStore } from '../../../../stores/software'
import { AddSharp } from '@vicons/ionicons5' import { AddSharp, Open } from '@vicons/ionicons5'
import BookTaskListAction from './Components/ManageBook/BookTaskListAction.vue' import BookTaskListAction from './Components/ManageBook/BookTaskListAction.vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { OperateBookType } from '../../../../define/enum/bookEnum' import { OperateBookType } from '../../../../define/enum/bookEnum'
@ -63,6 +66,7 @@ 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' import ManageBookTaskGenerateInformation from './Components/ManageBook/ManageBookTaskGenerateInformation.vue'
import { isEmpty } from 'lodash'
let reverseManageStore = useReverseManageStore() let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore() let softwareStore = useSoftwareStore()
@ -125,6 +129,11 @@ function createColumns() {
key: 'prefix', key: 'prefix',
width: 130 width: 130
}, },
{
title: '出图方式',
key: 'imageCategory',
width: 90
},
{ {
title: '状态', title: '状态',
key: 'status', key: 'status',
@ -161,6 +170,10 @@ function createOptions(row) {
label: `合成视频 ${row.name}`, label: `合成视频 ${row.name}`,
key: 'generateVideo' key: 'generateVideo'
}, },
{
label: `打开生图文件夹`,
key: 'openImageFolder'
},
{ {
label: () => h('span', { style: { color: '#f4a534' } }, `重置 ${row.name}`), label: () => h('span', { style: { color: '#f4a534' } }, `重置 ${row.name}`),
key: 'reset' key: 'reset'
@ -263,6 +276,23 @@ async function GenerateVideo(value) {
}) })
} }
async function OpenImageFolder(value) {
debugger
if (isEmpty(value.imageFolder)) {
message.error('没有找到对应的文件夹')
return
}
let res = await window.system.OpenFolder({
folderPath: value.imageFolder,
baseProject: false
})
if (res.code == 0) {
message.error(res.message)
return
}
message.success('打开文件夹成功')
}
/** /**
* 重置小说数据 * 重置小说数据
* @param e * @param e
@ -328,6 +358,9 @@ async function handleSelect(key) {
case 'generateVideo': case 'generateVideo':
await GenerateVideo(selectRow.value) await GenerateVideo(selectRow.value)
break break
case 'openImageFolder':
await OpenImageFolder(selectRow.value)
break
case 'reset': case 'reset':
await ReSetBookTaskDetail(selectRow.value) await ReSetBookTaskDetail(selectRow.value)
break break
@ -344,20 +377,31 @@ function onClickoutside() {
showDropdown.value = false showDropdown.value = false
} }
// /** //
// * async function GenerateAllTaskImage() {
// */ if (checkedRowKeysRef.value.length == 0) {
// async function hdImageFunc2(id, operateBookType) { message.error('请选择要生图的数据')
// softwareStore.spin.spinning = true return
// softwareStore.spin.tip = '' }
// let res = await window.book.HDImage(id, 4, operateBookType) let da = dialog.warning({
// softwareStore.spin.spinning = false title: '一键生图提示',
// if (res.code == 1) { content:
// message.success('') '即将开始添加生图任务,会按照每个批次的出图方式添加后台任务,添加之后不可修改,请检查每个批次的出图方式,是否继续?',
// } else { positiveText: '继续',
// message.error(res.message) negativeText: '取消',
// } onPositiveClick: async () => {
// } da?.destroy()
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在校验/添加生图任务。。。'
let res = await window.book.GenerateAllTaskImage(
[...checkedRowKeysRef.value],
OperateBookType.ASSIGNBOOKTASK
)
window.api.showGlobalMessageDialog(res);
softwareStore.spin.spinning = false
}
})
}
/** /**
* 一键高清全部 * 一键高清全部
@ -406,6 +450,7 @@ async function AddBookDialog() {
dialog.create({ dialog.create({
title: '新增小说批次任务', title: '新增小说批次任务',
showIcon: false, showIcon: false,
maskClosable: false,
content: () => h(AddBookTask), content: () => h(AddBookTask),
style: { width: '600px' } style: { width: '600px' }
}) })
@ -486,6 +531,7 @@ async function ResetAll() {
return return
} }
message.success('重置小说任务成功') message.success('重置小说任务成功')
checkedRowKeysRef.value = []
} else { } else {
message.error(res.message) message.error(res.message)
} }
@ -525,6 +571,7 @@ async function DeleteAll() {
} }
// //
message.success('删除小说任务并刷新数据成功') message.success('删除小说任务并刷新数据成功')
checkedRowKeysRef.value = []
} else { } else {
message.error(res.message) message.error(res.message)
} }

View File

@ -274,7 +274,6 @@ async function SelectStyle() {
// //
let dialogWidth = window.innerWidth * 0.8 let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -1,7 +1,12 @@
<template> <template>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<div style="display: flex"> <div style="display: flex">
<n-button strong secondary @click="ReturnMain" size="small">返回</n-button> <n-button strong secondary @click="ReturnMain" size="small">{{
'返回 | ' +
reverseManageStore.selectBook?.name +
'_' +
reverseManageStore.selectBookTask?.name
}}</n-button>
<n-divider vertical style="height: 30px" /> <n-divider vertical style="height: 30px" />
<!-- <n-button strong secondary @click="ReturnMain" size="small">一键全自动</n-button> <!-- <n-button strong secondary @click="ReturnMain" size="small">一键全自动</n-button>
<n-divider vertical style="height: 30px" /> --> <n-divider vertical style="height: 30px" /> -->
@ -133,7 +138,6 @@ async function ImportWord() {
}) })
} }
// ImportWordAndSrt
let da = dialog.create({ let da = dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -162,10 +166,10 @@ async function ImportWord() {
async function CharacterLibrary() { async function CharacterLibrary() {
// //
// //
let dialogWidth = window.innerWidth * 0.6 let dialogWidth = 1000
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
let word = '' // word let word = '' // word
let temp_arr = [] let temp_arr = []
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) { for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i] const element = reverseManageStore.selectBookTaskDetail[i]
@ -235,7 +239,7 @@ async function ResetGPTPrompt() {
onPositiveClick: async () => { onPositiveClick: async () => {
da?.destroy() da?.destroy()
softwareStore.spin.spinning = true softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在重置推理提示词,请稍后。。。' softwareStore.spin.tip = '正在重置推理提示词,请稍后。。。'
let res = await window.book.ResetGptReverseData( let res = await window.book.ResetGptReverseData(
reverseManageStore.selectBookTask.id, reverseManageStore.selectBookTask.id,
@ -373,7 +377,6 @@ async function GetPromptAll() {
* @param {Boolean} cover - 是否覆盖现有图像 * @param {Boolean} cover - 是否覆盖现有图像
*/ */
async function AddFluxImageAll(type, cover) { async function AddFluxImageAll(type, cover) {
let messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN let messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN
let taskType = BookBackTaskType.FLUX_API_IMAGE let taskType = BookBackTaskType.FLUX_API_IMAGE
if (type == BookImageCategory.FLUX_FORGE) { if (type == BookImageCategory.FLUX_FORGE) {

View File

@ -1,19 +0,0 @@
<script setup>
import { onMounted, ref } from 'vue'
import { useMessage, NButton, NFloatButton, NBadge, NIcon } from 'naive-ui'
import { Layers } from '@vicons/ionicons5'
import { useSoftwareStore } from '../../../../../stores/software'
import QueryButton from './QueryButton.vue'
import TaskDataTable from './TaskDataTable.vue'
let softwareStore = useSoftwareStore()
onMounted(() => {
//
})
</script>
<template>
<QueryButton />
<TaskDataTable />
</template>

View File

@ -1,57 +0,0 @@
<script setup>
import { onMounted, ref } from 'vue'
import { useMessage, NForm, NFormItem, NInput, NButton } from 'naive-ui'
import { useSoftwareStore } from '../../../../../stores/software'
let softwareStore = useSoftwareStore()
function handleSubmit() {
alert(123)
}
</script>
<template>
<n-form
ref="formRef"
inline
:label-width="80"
:model="softwareStore.backTask.queryData"
size="small"
>
<n-form-item label="小说" path="bookId">
<n-input v-model:value="softwareStore.backTask.queryData.bookId" placeholder="选择小说任务" />
</n-form-item>
<n-form-item label="小说批次任务" path="bookTaskId">
<n-input
v-model:value="softwareStore.backTask.queryData.bookTaskId"
placeholder="选择小说批次任务"
/>
</n-form-item>
<n-form-item label="任务名字" path="taskName">
<n-input
v-model:value="softwareStore.backTask.queryData.taskName"
placeholder="选择小说批次任务"
/>
</n-form-item>
<n-form-item label="任务类型" path="taskType">
<n-input
v-model:value="softwareStore.backTask.queryData.taskType"
placeholder="选择小说批次任务"
/>
</n-form-item>
<n-form-item label="任务状态" path="taskStatus">
<n-input
v-model:value="softwareStore.backTask.queryData.taskStatus"
placeholder="选择小说批次任务"
/>
</n-form-item>
<n-form-item label="任务失败原因" path="taskErrorMessage">
<n-input
v-model:value="softwareStore.backTask.queryData.taskErrorMessage"
placeholder="选择小说批次任务"
/>
</n-form-item>
<n-form-item path="taskErrorMessage">
<n-button type="info" @click="handleSubmit">查询</n-button>
</n-form-item>
</n-form>
</template>

View File

@ -1,7 +0,0 @@
<script setup>
</script>
<template>
<div>TaskDataTable</div>
</template>

View File

@ -64,7 +64,7 @@ import { MD5 } from 'crypto-js'
import InputDialogContent from '../Original/Components/InputDialogContent.vue' import InputDialogContent from '../Original/Components/InputDialogContent.vue'
import APIIcon from '../Icon/APIIcon.vue' import APIIcon from '../Icon/APIIcon.vue'
import BackTaskIcon from '../Icon/BackTaskIcon.vue' import BackTaskIcon from '../Icon/BackTaskIcon.vue'
import BackTask from '../Components/BackTask/BackTask.vue' import BackTask from '@/renderer/src/components/BackTask/BackTask.vue'
import { useSystemStore } from '../../../../stores/system' import { useSystemStore } from '../../../../stores/system'
import { TimeDelay } from '../../../../define/Tools/time' import { TimeDelay } from '../../../../define/Tools/time'
import { BookBackTaskStatus } from '../../../../define/enum/bookEnum' import { BookBackTaskStatus } from '../../../../define/enum/bookEnum'
@ -603,7 +603,8 @@ function renderIcon(icon) {
} }
function OpneBackTask() { function OpneBackTask() {
let dialogWidth = window.innerWidth * 0.8 let dialogWidth = window.innerWidth * 0.9
if (dialogWidth < 800) dialogWidth = 800
let dialogHeight = window.innerHeight * 0.95 let dialogHeight = window.innerHeight * 0.95
dialog.create({ dialog.create({
title: '后台任务', title: '后台任务',

View File

@ -315,7 +315,8 @@ export default defineComponent({
let sdObj = { let sdObj = {
batch_size: toRaw(sd_batch_size.value), batch_size: toRaw(sd_batch_size.value),
width: toRaw(sd_image_width.value), width: toRaw(sd_image_width.value),
height: toRaw(sd_image_height.value) height: toRaw(sd_image_height.value),
seed: toRaw(sd_seed.value)
} }
await window.api.SaveSDConfig(sdObj, (value) => { await window.api.SaveSDConfig(sdObj, (value) => {
if (value.code == 0) { if (value.code == 0) {

View File

@ -615,7 +615,6 @@ export default defineComponent({
// //
let dialogWidth = window.innerWidth * 0.8 let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,

View File

@ -114,7 +114,6 @@ export default defineComponent({
// //
let dialogWidth = window.innerWidth * 0.95 let dialogWidth = window.innerWidth * 0.95
let dialogHeight = window.innerHeight * 0.95 let dialogHeight = window.innerHeight * 0.95
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -133,9 +132,8 @@ export default defineComponent({
async function GetCharacter() { async function GetCharacter() {
// //
// //
let dialogWidth = window.innerWidth * 0.6 let dialogWidth = 1000
let dialogHeight = window.innerHeight * 0.9 let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({ dialog.create({
showIcon: false, showIcon: false,
closeOnEsc: false, closeOnEsc: false,
@ -217,7 +215,6 @@ export default defineComponent({
* 生成所有的图片 * 生成所有的图片
*/ */
async function GenerateImageAll() { async function GenerateImageAll() {
let tmpData = cloneDeep(toRaw(data.value)) let tmpData = cloneDeep(toRaw(data.value))
tmpData = tmpData.filter((item) => { tmpData = tmpData.filter((item) => {
return item.imageLock == null || item.imageLock == false return item.imageLock == null || item.imageLock == false
@ -363,11 +360,10 @@ export default defineComponent({
message.error(value.message) message.error(value.message)
return return
} }
console.log(value.value) console.log(value.value)
// //
await window.pmpt.OpenPromptFileTxt(value.value, (res) => { await window.pmpt.OpenPromptFileTxt(value.value, (res) => {
console.log(res) console.log(res)
if (res.code == 0) { if (res.code == 0) {
message.error(res.message) message.error(res.message)
@ -382,7 +378,6 @@ export default defineComponent({
positiveText: '继续', positiveText: '继续',
negativeText: '取消', negativeText: '取消',
onPositiveClick: async () => { onPositiveClick: async () => {
// //
for (let i = 0; i < data.value.length && i < res.data.length; i++) { for (let i = 0; i < data.value.length && i < res.data.length; i++) {
const element = res.data[i] const element = res.data[i]

View File

@ -36,6 +36,25 @@
placeholder="输入重绘幅度" placeholder="输入重绘幅度"
/> />
</n-form-item> </n-form-item>
<n-form-item label="SD批次出图张数" style="margin-right: 30px">
<n-input-number
:min="0"
:max="30"
:step="1"
:default-value="1"
v-model:value="formValue.batch_size"
placeholder="SD批次出图张数"
/>
</n-form-item>
<n-form-item label="种子值" style="margin-right: 30px">
<n-input-number
:min="-1"
:step="1"
:default-value="-1"
v-model:value="formValue.seed"
placeholder="SD批次出图张数"
/>
</n-form-item>
<n-form-item label="重绘幅度" path="denoising_strength"> <n-form-item label="重绘幅度" path="denoising_strength">
<n-input-number <n-input-number
:precision="2" :precision="2"

View File

@ -71,6 +71,16 @@
> >
</n-form-item> </n-form-item>
</n-form-item> </n-form-item>
<n-form-item path="image_setting" label="生图设置">
<n-form-item path="defaultImageMode" label="默认生图模式">
<n-select
v-model:value="formValue.defaultImageMode"
:options="defaultImageModeOptions"
placeholder="选择默认的生图模式"
style="width: 200px"
/>
</n-form-item>
</n-form-item>
<n-form-item path="gpt_setting" label="GPT设置"> <n-form-item path="gpt_setting" label="GPT设置">
<n-form-item path="gpt_business" label="GPT接口服务商"> <n-form-item path="gpt_business" label="GPT接口服务商">
<n-select <n-select
@ -161,7 +171,7 @@
</NSpace> </NSpace>
</template> </template>
<script> <script setup>
import { ref, toRaw, onMounted, defineComponent, h } from 'vue' import { ref, toRaw, onMounted, defineComponent, h } from 'vue'
import { import {
NForm, NForm,
@ -183,337 +193,300 @@ import { FolderOpenSharp as FolderOpen } from '@vicons/ionicons5'
import AddGptPrompts from './Components/AddGptPrompts.vue' import AddGptPrompts from './Components/AddGptPrompts.vue'
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { useSoftwareStore } from '../../../../stores/software' import { useSoftwareStore } from '../../../../stores/software'
import { TranslateAPIType } from '../../../../define/enum/translate'
import TranslateSetting from './TranslateSetting.vue' import TranslateSetting from './TranslateSetting.vue'
import { LaiAPIType } from '../../../../define/enum/softwareEnum' import { LaiAPIType } from '../../../../define/enum/softwareEnum'
export default defineComponent({ let formRef = ref(null)
components: { let softwareStore = useSoftwareStore()
NForm, let message = useMessage()
NFormItem, let formValue = ref({
NInput, draft_path: window.config.draft_path,
NInputNumber, project_path: window.config.project_path,
NButton, project_name: window.config.project_name,
NSpace, gpt_business: window.config.gpt_business,
NSpin, gpt_key: window.config.gpt_key,
NSelect, gpt_model: window.config.gpt_model,
NCheckbox, gpt_count: window.config.gpt_count,
NSwitch, task_number: window.config.task_number,
FolderOpen, translation_business: window.config.translation_business,
NIcon translation_app_id: window.config.translation_app_id,
translation_secret: window.config.translation_secret,
translation_auto: window.config.translation_auto,
theme: softwareStore.globalSetting.theme,
character_select_model: window.config.character_select_model,
window_wh_bm_remember: window.config.window_wh_bm_remember,
laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN,
hdScale: window.config.hdScale ?? 2,
defaultImageMode: window.config.defaultImageMode ?? 'mj'
})
let show = ref(false)
let gpt_options = ref([])
let gpt_model_options = ref([])
let character_select_model_options = ref([])
let hdSelectOptions = ref([
{
label: '2倍',
value: 2
}, },
setup() { {
let formRef = ref(null) label: '3倍',
let softwareStore = useSoftwareStore() value: 3
let message = useMessage() },
let formValue = ref({ {
draft_path: window.config.draft_path, label: '4倍',
project_path: window.config.project_path, value: 4
project_name: window.config.project_name, }
gpt_business: window.config.gpt_business, ])
gpt_key: window.config.gpt_key, let dialog = useDialog()
gpt_model: window.config.gpt_model, let loading = ref(false)
gpt_count: window.config.gpt_count, let defaultImageModeOptions = ref([])
task_number: window.config.task_number, /**
translation_business: window.config.translation_business, * 加载GPT的配置信息
translation_app_id: window.config.translation_app_id, */
translation_secret: window.config.translation_secret, async function InitGptOptions() {
translation_auto: window.config.translation_auto, await window.api.getGptBusinessOption('all', (value) => {
theme: softwareStore.globalSetting.theme, if (value.code == 0) {
character_select_model: window.config.character_select_model, message.error(value.message)
window_wh_bm_remember: window.config.window_wh_bm_remember, return
laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN, }
hdScale: window.config.hdScale ?? 2 gpt_options.value = value.data.filter((item) => item.gpt_url)
}) })
let show = ref(false)
let gpt_options = ref([]) await window.api.getGptModelOption('all', (value) => {
let gpt_model_options = ref([]) if (value.code == 0) {
let character_select_model_options = ref([]) message.error(value.message)
let hdSelectOptions = ref([ return
{ }
label: '2倍', gpt_model_options.value = value.data
value: 2 })
await window.mj.GetTagSelectModel((value) => {
character_select_model_options.value = value.data
})
}
onMounted(async () => {
await InitGptOptions()
//
await window.api.GetImageGenerateCategory((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
defaultImageModeOptions.value = value.data
})
})
//
function SwitchTranslate(value, option) {
//
formValue.value.translation_app_id = null
formValue.value.translation_secret = null
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
}, },
{ trigger: ['input', 'blur', 'change']
label: '3倍',
value: 3
},
{
label: '4倍',
value: 4
}
])
let dialog = useDialog()
let loading = ref(false)
/**
* 加载GPT的配置信息
*/
async function InitGptOptions() {
await window.api.getGptBusinessOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
gpt_options.value = value.data.filter((item) => item.gpt_url)
})
await window.api.getGptModelOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
gpt_model_options.value = value.data
})
await window.mj.GetTagSelectModel((value) => {
character_select_model_options.value = value.data
})
} }
]
}
onMounted(async () => { let rules = {
await InitGptOptions() draft_path: ruleObj('必填剪映草稿地址'),
project_path: ruleObj('必填项目地址'),
project_name: ruleObj('必填项目名称'),
task_number: ruleObj('必填后台并行任务数'),
gpt_business: ruleObj('必填GPT接口服务商'),
gpt_key: ruleObj('必填GPT Key'),
gpt_model: ruleObj('必填GPT模型'),
gpt_count: ruleObj('必填自动推理上下文行数'),
translation_secret: ruleObj('必填产品密钥'),
translation_app_id: ruleObj('必填APP ID'),
translation_business: ruleObj('必填翻译服务商')
}
/**
* 保存配置信息
*/
async function handleValidateButtonClick(e) {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
//
let saveRes = await window.setting.SaveSoftWareSetting({
globalSetting: JSON.stringify(toRaw(formValue.value))
}) })
if (saveRes.code == 0) {
// message.error(saveRes.message)
function SwitchTranslate(value, option) { return
//
formValue.value.translation_app_id = null
formValue.value.translation_secret = null
} }
softwareStore.globalSetting = toRaw(formValue.value)
let ruleObj = (errorMessage) => { //
return [ window.api.ModifySampleSetting(JSON.stringify(toRaw(formValue.value)), (value) => {
{ if (value.code == 1) {
required: true, window.api.getSettingDafultData((value) => {
validator(rule, value) { window.config = value
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
draft_path: ruleObj('必填剪映草稿地址'),
project_path: ruleObj('必填项目地址'),
project_name: ruleObj('必填项目名称'),
task_number: ruleObj('必填后台并行任务数'),
gpt_business: ruleObj('必填GPT接口服务商'),
gpt_key: ruleObj('必填GPT Key'),
gpt_model: ruleObj('必填GPT模型'),
gpt_count: ruleObj('必填自动推理上下文行数'),
translation_secret: ruleObj('必填产品密钥'),
translation_app_id: ruleObj('必填APP ID'),
translation_business: ruleObj('必填翻译服务商')
}
/**
* 保存配置信息
*/
async function handleValidateButtonClick(e) {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
//
let saveRes = await window.setting.SaveSoftWareSetting({
globalSetting: JSON.stringify(toRaw(formValue.value))
}) })
if (saveRes.code == 0) { window.api.showGlobalMessageDialog({ code: 1, message: value.message })
message.error(saveRes.message)
return
}
softwareStore.globalSetting = toRaw(formValue.value)
//
window.api.ModifySampleSetting(JSON.stringify(toRaw(formValue.value)), (value) => {
if (value.code == 1) {
window.api.getSettingDafultData((value) => {
window.config = value
})
window.api.showGlobalMessageDialog({ code: 1, message: value.message })
} else {
window.api.showGlobalMessageDialog({ code: 0, message: value.message })
}
})
softwareStore.SetSoftware({ theme: formValue.value.theme })
})
}
let railStyle = (focused, checked) => {
const style = {}
if (checked) {
style.background = '#f3a694'
if (focused) {
style.boxShadow = '0 0 0 2px #f3a694'
}
} else { } else {
style.background = '#775039' window.api.showGlobalMessageDialog({ code: 0, message: value.message })
if (focused) {
style.boxShadow = '0 0 0 2px #775039'
}
} }
return style })
} softwareStore.SetSoftware({ theme: formValue.value.theme })
})
}
/** let railStyle = (focused, checked) => {
* 打开购买GPT的地址 const style = {}
*/ if (checked) {
async function openGptBuyUrl() { style.background = '#f3a694'
let tmp_gb = gpt_options.value.filter((item) => item.value == formValue.value.gpt_business) if (focused) {
if (tmp_gb.length == 0) { style.boxShadow = '0 0 0 2px #f3a694'
message.error('当前选择的服务商没有购买地址!')
return
}
let buy_url = tmp_gb[0].buy_url
if (isEmpty(buy_url)) {
message.error('当前选择的服务商没有购买地址!')
} else {
window.api.openGptBuyUrl(buy_url)
}
} }
} else {
/** style.background = '#775039'
* 切换主题 if (focused) {
* @param {*} value 主题名称 style.boxShadow = '0 0 0 2px #775039'
*/
async function ChangeMode(value) {
console.log(value)
const isDarkMode = await window.darkMode.toggle(value)
}
/**
* 添加GPT地址或者模型
*/
async function addGptOption() {
//
//
let dialogWidth = 600
let dialogHeight = 450
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '添加GPT地址或者模型',
content: () => h(AddGptOption, {}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
//
await InitGptOptions()
}
})
}
/**
* 测试当前GPT是不是可以链接成功
*/
async function TestGPTConnection() {
loading.value = true
//
await window.api.TestGPTConnection(JSON.stringify(formValue.value), (value) => {
loading.value = false
if (value.code == 0) {
window.api.showGlobalMessageDialog({
code: 0,
message: 'GPT链接失败错误信息 ' + value.message
})
return
}
window.api.showGlobalMessageDialog({ code: 1, message: 'gpt链接测试成功可以正常使用' })
})
}
/**
* 选择项目文件夹
*/
async function SelectProjectFolder() {
await window.api.selectFolder(
{ default_paht: toRaw(formValue.value).project_path },
(value) => {
if (value.length > 0) {
formValue.value.project_path = value[0]
}
}
)
}
/**
* 添加GPT提示词预设
*/
async function AddGptPrompt() {
//
//
let dialogWidth = 600
let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '添加GPT提示词预设',
content: () => h(AddGptPrompts, { height: dialogHeight }),
style: `width : ${dialogWidth}px; height : ${dialogHeight}px; padding-right : 3px `,
maskClosable: false,
onClose: () => {}
})
}
/**
* 进行翻译设置
*/
async function ModifyTranslateSetting() {
//
//
let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({
showIcon: false,
title: '翻译设置',
content: () => h(TranslateSetting, { height: dialogHeight }),
style: `width : ${dialogWidth}px; height : ${dialogHeight}px`,
maskClosable: false
})
}
return {
formRef,
ChangeMode,
openGptBuyUrl,
railStyle,
handleValidateButtonClick,
rules,
SwitchTranslate,
gpt_model_options,
gpt_options,
show,
formValue,
addGptOption,
TestGPTConnection,
loading,
SelectProjectFolder,
AddGptPrompt,
character_select_model_options,
softwareStore,
hdSelectOptions,
ModifyTranslateSetting,
laiApiOptions: [
{
label: '主站点',
value: LaiAPIType.MAIN
},
{
label: '香港站点',
value: LaiAPIType.HK_PROXY
},
{
label: '备用主站点',
value: LaiAPIType.BAK_MAIN
}
]
} }
} }
}) return style
}
/**
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = gpt_options.value.filter((item) => item.value == formValue.value.gpt_business)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
}
let buy_url = tmp_gb[0].buy_url
if (isEmpty(buy_url)) {
message.error('当前选择的服务商没有购买地址!')
} else {
window.api.openGptBuyUrl(buy_url)
}
}
/**
* 切换主题
* @param {*} value 主题名称
*/
async function ChangeMode(value) {
console.log(value)
const isDarkMode = await window.darkMode.toggle(value)
}
/**
* 添加GPT地址或者模型
*/
async function addGptOption() {
//
//
let dialogWidth = 600
let dialogHeight = 450
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '添加GPT地址或者模型',
content: () => h(AddGptOption, {}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
//
await InitGptOptions()
}
})
}
/**
* 测试当前GPT是不是可以链接成功
*/
async function TestGPTConnection() {
loading.value = true
//
await window.api.TestGPTConnection(JSON.stringify(formValue.value), (value) => {
loading.value = false
if (value.code == 0) {
window.api.showGlobalMessageDialog({
code: 0,
message: 'GPT链接失败错误信息 ' + value.message
})
return
}
window.api.showGlobalMessageDialog({ code: 1, message: 'gpt链接测试成功可以正常使用' })
})
}
/**
* 选择项目文件夹
*/
async function SelectProjectFolder() {
await window.api.selectFolder({ default_paht: toRaw(formValue.value).project_path }, (value) => {
if (value.length > 0) {
formValue.value.project_path = value[0]
}
})
}
/**
* 添加GPT提示词预设
*/
async function AddGptPrompt() {
//
//
let dialogWidth = 600
let dialogHeight = window.innerHeight * 0.9
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '添加GPT提示词预设',
content: () => h(AddGptPrompts, { height: dialogHeight }),
style: `width : ${dialogWidth}px; height : ${dialogHeight}px; padding-right : 3px `,
maskClosable: false,
onClose: () => {}
})
}
/**
* 进行翻译设置
*/
async function ModifyTranslateSetting() {
//
//
let dialogWidth = window.innerWidth * 0.8
let dialogHeight = window.innerHeight * 0.9
dialog.create({
showIcon: false,
title: '翻译设置',
content: () => h(TranslateSetting, { height: dialogHeight }),
style: `width : ${dialogWidth}px; height : ${dialogHeight}px`,
maskClosable: false
})
}
let laiApiOptions = [
{
label: '主站点',
value: LaiAPIType.MAIN
},
{
label: '香港站点',
value: LaiAPIType.HK_PROXY
},
{
label: '备用主站点',
value: LaiAPIType.BAK_MAIN
}
]
</script> </script>

View File

@ -39,6 +39,7 @@ export const useReverseManageStore = defineStore('reverseManage', {
imageFolder: null, imageFolder: null,
styleList: null, styleList: null,
prefix: null, prefix: null,
imageCategory: null,
status: BookTaskStatus.WAIT, status: BookTaskStatus.WAIT,
errorMsg: null errorMsg: null
} as Book.SelectBookTask// 当前选中的小说任务 } as Book.SelectBookTask// 当前选中的小说任务

View File

@ -1,3 +1,4 @@
import { TaskModal } from '@/model/task'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
// 系统相关设置 // 系统相关设置
@ -15,8 +16,8 @@ export const useSoftwareStore = defineStore('software', {
taskType: undefined, taskType: undefined,
taskStatus: undefined, taskStatus: undefined,
taskErrorMessage: undefined, taskErrorMessage: undefined,
}, // 查询传递的数据 } as TaskModal.TaskCondition, // 查询传递的数据
taskData: [], // 后台任务数据 taskData: [] as TaskModal.Task[], // 后台任务数据
}, },
softWare: { softWare: {
theme: 'light', // 系统主题,亮或是暗 theme: 'light', // 系统主题,亮或是暗
@ -43,15 +44,6 @@ export const useSoftwareStore = defineStore('software', {
} }
}, },
actions: { actions: {
// 设置一键反推界面显示数据
SetReverseDispalayShow(value) {
this.softWare.reverse_display_show = value
},
// 设置反推界面时候小说信息显示斑马纹
SetReverseBookStripedShow(value) {
this.softWare.reverse_show_book_striped = value
},
// 修改软件主题 // 修改软件主题
SetSoftware(value) { SetSoftware(value) {
@ -75,8 +67,22 @@ export const useSoftwareStore = defineStore('software', {
// 保存数据 // 保存数据
// @ts-ignore // @ts-ignore
return await window.setting.SaveSoftWareSetting(JSON.parse(JSON.stringify(this.softWare))) return await window.setting.SaveSoftWareSetting(JSON.parse(JSON.stringify(this.softWare)))
} },
//#endregion //#endregion
/**
*
*/
ResetBackTaskQueryData() {
this.backTask.queryData = {
taskName: undefined,
bookId: undefined,
bookTaskId: undefined,
taskType: undefined,
taskStatus: undefined,
taskErrorMessage: undefined
}
}
} }
}) })