修复聚合推文剪映抽帧时,导入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: {
resolve: {
alias: {
'@renderer': resolve('src/renderer/src')
'@renderer': resolve('src/renderer/src'),
"@" : resolve('src/'),
}
},
plugins: [vue(), Jsx()]

4
package-lock.json generated
View File

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

View File

@ -1,6 +1,6 @@
{
"name": "laitool",
"version": "3.1.9",
"version": "3.2.0",
"description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js",
"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) {
imageCategory = BookImageCategory.MJ
} else if (book.type == BookType.ORIGINAL) {
imageCategory = BookImageCategory.MJ
imageCategory = global.config.defaultImageMode
} else {
throw new Error('未知的小说类型')
}

View File

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

View File

@ -3,6 +3,7 @@ import TASK from "./taskDefineString"
import TTS from "./ttsDefineString"
import SETTING from "./settingDefineString"
import BOOK from "./bookDefineString"
import WRITE from "./writeDefineString"
export const DEFINE_STRING = {
SYSTEM: SYSTEM,
@ -10,6 +11,7 @@ export const DEFINE_STRING = {
TTS: TTS,
BOOK: BOOK,
SETTING: SETTING,
WRITE: WRITE,
SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE",
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
@ -246,14 +248,6 @@ export const DEFINE_STRING = {
*/
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: {
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_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_BACK_TASK_COLLECTION: "GET_BACK_TASK_COLLECTION",
};
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'
}
/**
* 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)
)
// 获取图片的URL并且下载
ipcMain.handle(
DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD,
async (event, id: string, operateBookType: OperateBookType, coverData: boolean) =>
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
// 一拆四,将一个任务拆分成四个任务,并且复制对应的图片
ipcMain.handle(
DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK,
async (event, bookTaskDetailId) => await bookTask.OneToFourBookTask(bookTaskDetailId)
)
//#region 小说相关
// 重置小说数据
@ -294,6 +295,12 @@ export function BookIpc() {
//#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))

View File

@ -6,6 +6,7 @@ import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "../../def
let bookServiceBasic = new BookServiceBasic();
import BackTaskService from '../Service/task/backTaskService'
import { TaskModal } from "@/model/task";
const backTaskService = new BackTaskService()
function TaskIpc() {
@ -38,8 +39,12 @@ function TaskIpc() {
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_BACK_TASK_COLLECTION, async (event, queryTaskCondition: TaskModal.QueryTaskCondition) => await backTaskService.GetBackTaskCollection(queryTaskCondition))
}
export { TaskIpc }

View File

@ -5,7 +5,9 @@ let writing = new Writing(global)
import { WritingSetting } from '../setting/writeSetting'
let writingSetting = new WritingSetting()
import { SubtitleService } from '../Service/Subtitle/subtitleService'
import { BookPrompt } from '../Service/Book/bookPrompt'
let subtitleService = new SubtitleService()
const bookPrompt = new BookPrompt();
function WritingIpc() {
// 监听分镜时间的保存
@ -71,5 +73,14 @@ function WritingIpc() {
DEFINE_STRING.WRITE.ACTION_START,
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 }

View File

@ -84,7 +84,7 @@ export class BookFrame {
startTime: Math.ceil(element.startTime / 1000),
endTime: Math.ceil(element.endTime / 1000),
status: BookTaskStatus.WAIT,
word: element.word,
word: element.text,
videoPath: element.videoPath,
oldImage: path.relative(define.project_path, element.framePath),
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 { errorMessage, successMessage } from "../../Public/generalTools";
import { Book } from "../../../model/book";
@ -19,6 +19,13 @@ import { MJImageType } from "../../../define/enum/mjEnum";
import MJApi from '../MJ/mjApi'
const execAsync = util.promisify(exec);
type TaskTemp = {
bookTaskId: string;
bookId: string;
imageCategory: BookImageCategory;
bookTaskDetail: Book.SelectBookTaskDetail;
}
/**
*
*/
@ -87,8 +94,9 @@ export class BookImage {
}
//#endregion
//#region 开始高清图片任务
/**
*
*
* @param id ID
* @param scale
* @param operateBookType BOOKBOOKTASK两种
@ -188,7 +196,9 @@ export class BookImage {
}
}
//#endregion
//#region 检查图片的大小
/**
* fileSize false
* @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
@ -327,7 +420,9 @@ export class BookImage {
return errorMessage("图片执行锁定或解锁失败,失败信息如下:" + error.toString(), "BookImage_ImageLockOperation")
}
}
//#endregion
//#region 下载指定的图片地址并且分割
/**
*
* @param bookTaskDetailId ID
@ -416,8 +511,9 @@ export class BookImage {
}
}
}
//#endregion
//#region 获取指定的图片链接 ,然后下载图片
/**
*
* @param id
@ -486,4 +582,5 @@ export class BookImage {
return errorMessage('获取图片链接并且下载失败,错误信息如下:' + error.message, 'BookImage_GetImageUrlAndDownload')
}
}
//#endregion
}

View File

@ -13,6 +13,7 @@ import path from 'path'
import readline from 'readline';
import { define } from "../../../define/define";
import { ValidateJson } from "../../../define/Tools/validate";
import { SendMessageToRenderer } from "../globalService";
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
//#region 原创的提示词相关

View File

@ -1,5 +1,5 @@
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 { Book } from "../../../model/book";
import path from 'path'
@ -119,9 +119,23 @@ export class BookTask {
* @param no
* @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 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 = {
id: uuidv4(),
bookId: bookTask.bookId,
@ -142,7 +156,7 @@ export class BookTask {
videoConfig: bookTask.videoConfig ??= undefined,
prefixPrompt: addNewBookTask.prefixPrompt ??= undefined,
suffixPrompt: addNewBookTask.suffixPrompt ?? undefined,
imageCategory: bookTask.imageCategory ??= BookImageCategory.MJ,
imageCategory: imageCategory,
subImageFolder: [],
draftSrtStyle: undefined,
backgroundMusic: bookTask.backgroundMusic ??= undefined,
@ -164,7 +178,7 @@ export class BookTask {
* @returns
*/
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)
return {
newBookTask: newBookTask,
@ -199,7 +213,7 @@ export class BookTask {
bookTasks.push(newBookTask)
bookTaskDetail.push(...newBookTaskDetails)
} 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);
}
}

View File

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

View File

@ -318,4 +318,65 @@ export class GptService {
}
}
//#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
}, task.messageName);
// 当获取的图片的进度小于100的时候等待5秒继续监听
await new Promise(resolve => setTimeout(resolve, 5000));
await new Promise(resolve => setTimeout(resolve, 9000));
} catch (error) {
throw error;
}

View File

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

View File

@ -1,6 +1,8 @@
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from "../../../define/enum/bookEnum";
import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService";
import { Book } from "../../../model/book";
import { TaskModal } from "@/model/task";
import { cloneDeep, isEmpty } from "lodash";
export default class BookBackTaskServiceBasic {
bookBackTaskListService: BookBackTaskListService
@ -57,6 +59,29 @@ export default class BookBackTaskServiceBasic {
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 BookTaskServiceBasic from "./bookTaskServiceBasic";
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);
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
}
export { BookServiceBasic };

View File

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

View File

@ -1,3 +1,4 @@
import { TaskModal } from "@/model/task";
import { BookBackTaskStatus } from "../../../define/enum/bookEnum";
import { GeneralResponse } from "../../../model/generalResponse";
import { errorMessage, successMessage } from "../../Public/generalTools";
@ -10,6 +11,7 @@ export default class BackTaskService {
this.bookServiceBasic = new BookServiceBasic()
}
//#region 获取指定状态的后台任务数量
/**
*
*/
@ -23,6 +25,9 @@ export default class BackTaskService {
}
}
//#endregion
//#region 启动后台任务
/**
*
* @param isGiveUp
@ -44,4 +49,14 @@ export default class BackTaskService {
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 { MJSetting } from '../../../model/Setting/mjSetting'
import { BookVideo } from '../Book/bookVideo'
import { BookServiceBasic } from '../ServiceBasic/bookServiceBasic'
import { TaskModal } from '@/model/task'
export class TaskManager {
isExecuting: boolean = false;
@ -26,6 +28,7 @@ export class TaskManager {
eventListeners: Record<string | number, Function[]> = {};
softWareServiceBasic: SoftWareServiceBasic
bookVideo: BookVideo
bookServiceBasic: BookServiceBasic
mjSetting: MJSetting.MjSetting
spaceTime: number = 5000;
@ -48,6 +51,7 @@ export class TaskManager {
this.d3Opt = new D3Opt()
this.softWareServiceBasic = new SoftWareServiceBasic();
this.fluxOpt = new FluxOpt()
this.bookServiceBasic = new BookServiceBasic();
}
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() {
if (this.isListening) return; // 如果已经在监听,直接返回
@ -201,7 +215,6 @@ export class TaskManager {
global.requestQuene.enqueue(async () => {
await this.basicReverse.ExtractSubtitlesData(task);
}, `${batch}_${task.id}`, batch)
}
/**
@ -209,10 +222,10 @@ export class TaskManager {
* @param task
*/
AddSingleReversePrompt(task: TaskModal.Task): void {
let batch = DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT;
let batch = task.messageName;
global.requestQuene.enqueue(async () => {
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) {
// 判断是不是MJ的任务
let batch = DEFINE_STRING.MJ.MJ_IMAGE;
let batch = task.messageName;
global.mjQueue.enqueue(async () => {
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
*/
async AddSDImage(task: TaskModal.Task) {
let batch = DEFINE_STRING.SD.TXT2IMG
let batch = task.messageName;
global.requestQuene.enqueue(async () => {
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;
global.requestQuene.enqueue(async () => {
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 () => {
this.bookVideo = new BookVideo();
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
*/
async AddFluxForgeImage(task: TaskModal.Task) {
let batch = task.messageName
let batch = task.messageName;
global.requestQuene.enqueue(async () => {
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;
global.requestQuene.enqueue(async () => {
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.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.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')
? value.adetailer
: sd_config.webui.adetailer
@ -695,6 +697,7 @@ async function SaveSDConfig(value) {
} else {
sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX
}
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config))
return {
code: 1,

View File

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

View File

@ -40,5 +40,6 @@ declare namespace SoftwareSettingModel {
gpt_key: string = undefined // GPT KEY,
laiApiSelect: string = undefined // LaiAPI选择
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 {
type Task = {
interface Task {
id?: string
bookId?: string
bookTaskId?: string
@ -16,4 +17,32 @@ declare namespace TaskModal {
endTime?: number,
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) =>
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
//#region 一键反推的单个任务

View File

@ -1,6 +1,7 @@
import { ipcRenderer } from 'electron'
import { DEFINE_STRING } from '../define/define_string'
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from '../define/enum/bookEnum'
import { TaskModal } from '@/model/task'
const task = {
@ -10,16 +11,8 @@ const task = {
* @returns
*/
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,
executeType = TaskExecuteType.AUTO,
bookTaskId = null,
@ -27,14 +20,14 @@ const task = {
responseMessageName: string = null) =>
await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName),
/**
*
* @param task
*/
/** 同时添加多个任务 */
AddMultiBookBackTask: async (task: TaskModal.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),
/** 获取后台任务的集合,分页 */
GetBackTaskCollection: async (queryTaskCondition: TaskModal.QueryTaskCondition) => await ipcRenderer.invoke(DEFINE_STRING.TASK.GET_BACK_TASK_COLLECTION, queryTaskCondition),
}
export { task }

View File

@ -30,7 +30,13 @@ const write = {
// 开始执行API相关的一系列任务
ActionStart(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
}

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 dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,14 @@
<template>
<div style="display: flex; justify-content: space-between; 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-button :color="softwareStore.SoftColor.ORANGE" @click="Start" style="margin-left: 5px">
自动开始
@ -206,6 +213,7 @@ async function ComputeStoryboard() {
async function JianyingFrame() {
let da = dialog.info({
title: '剪映分镜参数',
maskClosable: false,
content: () => h(JianyingFrameOption)
})
}
@ -403,7 +411,6 @@ async function GetWatermarkPosition() {
//
let dialogWidth = window.innerWidth * 0.7
let dialogHeight = window.innerHeight * 0.9
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
@ -806,6 +813,7 @@ async function ImportWordAndSrtFunc() {
let tempData = []
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
debugger
const element = reverseManageStore.selectBookTaskDetail[i]
tempData.push({
no: element.no,
@ -820,7 +828,6 @@ async function ImportWordAndSrtFunc() {
})
}
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,

View File

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

View File

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

View File

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

View File

@ -1,7 +1,12 @@
<template>
<div style="display: flex; align-items: center">
<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-button strong secondary @click="ReturnMain" size="small">一键全自动</n-button>
<n-divider vertical style="height: 30px" /> -->
@ -133,7 +138,6 @@ async function ImportWord() {
})
}
// ImportWordAndSrt
let da = dialog.create({
showIcon: false,
closeOnEsc: false,
@ -162,7 +166,7 @@ async function ImportWord() {
async function CharacterLibrary() {
//
//
let dialogWidth = window.innerWidth * 0.6
let dialogWidth = 1000
let dialogHeight = window.innerHeight * 0.9
let word = '' // word
@ -373,7 +377,6 @@ async function GetPromptAll() {
* @param {Boolean} cover - 是否覆盖现有图像
*/
async function AddFluxImageAll(type, cover) {
let messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN
let taskType = BookBackTaskType.FLUX_API_IMAGE
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 APIIcon from '../Icon/APIIcon.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 { TimeDelay } from '../../../../define/Tools/time'
import { BookBackTaskStatus } from '../../../../define/enum/bookEnum'
@ -603,7 +603,8 @@ function renderIcon(icon) {
}
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
dialog.create({
title: '后台任务',

View File

@ -315,7 +315,8 @@ export default defineComponent({
let sdObj = {
batch_size: toRaw(sd_batch_size.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) => {
if (value.code == 0) {

View File

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

View File

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

View File

@ -36,6 +36,25 @@
placeholder="输入重绘幅度"
/>
</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-input-number
:precision="2"

View File

@ -71,6 +71,16 @@
>
</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_business" label="GPT接口服务商">
<n-select
@ -161,7 +171,7 @@
</NSpace>
</template>
<script>
<script setup>
import { ref, toRaw, onMounted, defineComponent, h } from 'vue'
import {
NForm,
@ -183,337 +193,300 @@ import { FolderOpenSharp as FolderOpen } from '@vicons/ionicons5'
import AddGptPrompts from './Components/AddGptPrompts.vue'
import { isEmpty } from 'lodash'
import { useSoftwareStore } from '../../../../stores/software'
import { TranslateAPIType } from '../../../../define/enum/translate'
import TranslateSetting from './TranslateSetting.vue'
import { LaiAPIType } from '../../../../define/enum/softwareEnum'
export default defineComponent({
components: {
NForm,
NFormItem,
NInput,
NInputNumber,
NButton,
NSpace,
NSpin,
NSelect,
NCheckbox,
NSwitch,
FolderOpen,
NIcon
let formRef = ref(null)
let softwareStore = useSoftwareStore()
let message = useMessage()
let formValue = ref({
draft_path: window.config.draft_path,
project_path: window.config.project_path,
project_name: window.config.project_name,
gpt_business: window.config.gpt_business,
gpt_key: window.config.gpt_key,
gpt_model: window.config.gpt_model,
gpt_count: window.config.gpt_count,
task_number: window.config.task_number,
translation_business: window.config.translation_business,
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)
let softwareStore = useSoftwareStore()
let message = useMessage()
let formValue = ref({
draft_path: window.config.draft_path,
project_path: window.config.project_path,
project_name: window.config.project_name,
gpt_business: window.config.gpt_business,
gpt_key: window.config.gpt_key,
gpt_model: window.config.gpt_model,
gpt_count: window.config.gpt_count,
task_number: window.config.task_number,
translation_business: window.config.translation_business,
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
})
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
{
label: '3倍',
value: 3
},
{
label: '4倍',
value: 4
}
])
let dialog = useDialog()
let loading = ref(false)
let defaultImageModeOptions = ref([])
/**
* 加载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 () => {
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
},
{
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
})
trigger: ['input', 'blur', 'change']
}
]
}
onMounted(async () => {
await InitGptOptions()
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))
})
//
function SwitchTranslate(value, option) {
//
formValue.value.translation_app_id = null
formValue.value.translation_secret = null
if (saveRes.code == 0) {
message.error(saveRes.message)
return
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
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))
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
})
if (saveRes.code == 0) {
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'
}
window.api.showGlobalMessageDialog({ code: 1, message: value.message })
} else {
style.background = '#775039'
if (focused) {
style.boxShadow = '0 0 0 2px #775039'
}
window.api.showGlobalMessageDialog({ code: 0, message: value.message })
}
return style
}
})
softwareStore.SetSoftware({ theme: formValue.value.theme })
})
}
/**
* 打开购买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)
}
let railStyle = (focused, checked) => {
const style = {}
if (checked) {
style.background = '#f3a694'
if (focused) {
style.boxShadow = '0 0 0 2px #f3a694'
}
/**
* 切换主题
* @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
// 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
}
]
} else {
style.background = '#775039'
if (focused) {
style.boxShadow = '0 0 0 2px #775039'
}
}
})
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>

View File

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

View File

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