diff --git a/package-lock.json b/package-lock.json index 6c27789..5245d82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "laitool", - "version": "3.1.1", + "version": "3.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "laitool", - "version": "3.1.1", + "version": "3.1.2", "hasInstallScript": true, "dependencies": { "@alicloud/alimt20181012": "^1.2.0", diff --git a/package.json b/package.json index a1720a4..a37684f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "3.1.1", + "version": "3.1.2", "description": "An AI tool for image processing, video processing, and other functions.", "main": "./out/main/index.js", "author": "laitool.cn", diff --git a/resources/scripts/db/book.realm.lock b/resources/scripts/db/book.realm.lock index eff58b5..fdb0407 100644 Binary files a/resources/scripts/db/book.realm.lock and b/resources/scripts/db/book.realm.lock differ diff --git a/resources/scripts/db/software.realm.lock b/resources/scripts/db/software.realm.lock index f6d4476..26841f8 100644 Binary files a/resources/scripts/db/software.realm.lock and b/resources/scripts/db/software.realm.lock differ diff --git a/src/define/db/service/Book/bookTaskDetailService.ts b/src/define/db/service/Book/bookTaskDetailService.ts index 59a7f17..ab58ec0 100644 --- a/src/define/db/service/Book/bookTaskDetailService.ts +++ b/src/define/db/service/Book/bookTaskDetailService.ts @@ -67,7 +67,7 @@ export class BookTaskDetailService extends BaseRealmService { videoPath: JoinPath(define.project_path, item.videoPath), audioPath: JoinPath(define.project_path, item.audioPath), oldImage: JoinPath(define.project_path, item.oldImage), - outImagePath: JoinPath(define.project_path, item.outImagePath), + outImagePath: JoinPath(define.project_path, item.outImagePath) , subImagePath: (item.subImagePath as string[])?.map((subImage) => { return JoinPath(define.project_path, subImage) }), diff --git a/src/define/define_string.ts b/src/define/define_string.ts index f4d1cfe..5f01dd5 100644 --- a/src/define/define_string.ts +++ b/src/define/define_string.ts @@ -253,9 +253,20 @@ export const DEFINE_STRING = { REPLACE_BOOK_DATA: "REPLACE_BOOK_DATA", SAVE_COPYWRITING: 'SAVE_COPYWRITING', - //#region 原创推理提示词 + //#region 提示词 + /** + * 原创推理提示词 + */ ORIGINAL_GPT_PROMPT: "ORIGINAL_GPT_PROMPT", + /** + * 原创推理提示词返回 + */ ORIGINAL_GPT_PROMPT_RETURN: "ORIGINAL_GPT_PROMPT_RETURN", + + /** + * 导入提示词,通用 + */ + IMPORT_GPT_PROMPT: "IMPORT_GPT_PROMPT", //#endregion //#region 生图返回相关 @@ -287,6 +298,15 @@ export const DEFINE_STRING = { //#endregion + //#region 图片相关 + + /** + * 获取MJ的消息ID,下载图片并分割 + */ + GET_IMAGE_URL_AND_DOWNLOAD : "GET_IMAGE_URL_AND_DOWNLOAD", + + //#endregion + COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD', GET_FRAME: 'GET_FRAME', diff --git a/src/define/enum/mjEnum.ts b/src/define/enum/mjEnum.ts index d82f312..6cc6aca 100644 --- a/src/define/enum/mjEnum.ts +++ b/src/define/enum/mjEnum.ts @@ -18,7 +18,11 @@ export enum MJImageType { FLUX_API = 'flux-api', // flxu-forge - FLUX_FORGE = 'flux-forge' + FLUX_FORGE = 'flux-forge', + + // 导入 + IMPORT = 'import', + } export enum MJRobotType { diff --git a/src/main/IPCEvent/bookIpc.ts b/src/main/IPCEvent/bookIpc.ts index 5b01401..93711db 100644 --- a/src/main/IPCEvent/bookIpc.ts +++ b/src/main/IPCEvent/bookIpc.ts @@ -149,6 +149,11 @@ export function BookIpc() { await bookPrompt.OriginalGetPrompt(id, operateBookType, coverData) ) + ipcMain.handle( + DEFINE_STRING.BOOK.IMPORT_GPT_PROMPT, + async (event, bookTaskId: string, txtPath: string) => await bookPrompt.ImportGPTPrompt(bookTaskId, txtPath) + ) + //#endregion //#region 文案相关 @@ -252,6 +257,12 @@ export function BookIpc() { async (event, id, operateBookType) => await bookImage.ResetGenerateImage(id, operateBookType) ) + ipcMain.handle( + DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD, + async (event, id: string, operateBookType: OperateBookType, coverData: boolean) => + await bookImage.GetImageUrlAndDownload(id, operateBookType, coverData) + ) + //#endregion diff --git a/src/main/Service/Book/bookGeneral.ts b/src/main/Service/Book/bookGeneral.ts index 8671a27..9fac188 100644 --- a/src/main/Service/Book/bookGeneral.ts +++ b/src/main/Service/Book/bookGeneral.ts @@ -28,18 +28,37 @@ export class BookGeneral { this.bookServiceBasic.transaction((realm) => { for (let i = 0; i < bookTaskDetail.length; i++) { let element = bookTaskDetail[i]; + // 这边新增判断,是不是有subValue,有点话替换subValue中的数据 let afterGpt = element.afterGpt - // 判断是否存在before的数据 - if (!afterGpt.includes(replaceData.before)) { - continue + let subValue = element.subValue + if (subValue && subValue.length > 0) { + subValue = subValue.map(item => { + return { + ...item, + srt_value: item.srt_value.replaceAll(replaceData.before, replaceData.after) + } + }) + let btd = realm.objectForPrimaryKey('BookTaskDetail', element.id) + btd.subValue = JSON.stringify(subValue); + result.push({ + bookTaskDetailId: element.id, + newData: subValue, + type: 'subValue' + } as Book.ReplaceDataRes) + // 保存数据 + } else { + // 判断是否存在before的数据 + if (!afterGpt.includes(replaceData.before)) { + continue + } + let newAfterGpt = afterGpt.replaceAll(replaceData.before, replaceData.after); + let btd = realm.objectForPrimaryKey('BookTaskDetail', element.id) + btd.afterGpt = newAfterGpt + result.push({ + bookTaskDetailId: element.id, + newData: newAfterGpt + } as Book.ReplaceDataRes) } - let newAfterGpt = afterGpt.replaceAll(replaceData.before, replaceData.after); - let btd = realm.objectForPrimaryKey('BookTaskDetail', element.id) - btd.afterGpt = newAfterGpt - result.push({ - bookTaskDetailId: element.id, - newData: newAfterGpt - } as Book.ReplaceDataRes) } }) return result diff --git a/src/main/Service/Book/bookImage.ts b/src/main/Service/Book/bookImage.ts index 0ba205a..ba7b023 100644 --- a/src/main/Service/Book/bookImage.ts +++ b/src/main/Service/Book/bookImage.ts @@ -1,4 +1,4 @@ -import { BookImageCategory, BookType, OperateBookType } from "../../../define/enum/bookEnum"; +import { BookImageCategory, BookType, MJAction, OperateBookType } from "../../../define/enum/bookEnum"; import { GeneralResponse } from "../../../model/generalResponse"; import { errorMessage, successMessage } from "../../Public/generalTools"; import { Book } from "../../../model/book"; @@ -15,6 +15,8 @@ import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import fs from 'fs' import util from 'util' import { exec } from 'child_process' +import { MJImageType } from "../../../define/enum/mjEnum"; +import MJApi from '../MJ/mjApi' const execAsync = util.promisify(exec); /** @@ -24,9 +26,11 @@ export class BookImage { bookServiceBasic: BookServiceBasic tools: Tools; mjOpt: MJOpt; + mjApi: MJApi constructor() { this.tools = new Tools() this.mjOpt = new MJOpt() + this.mjApi = new MJApi() this.bookServiceBasic = new BookServiceBasic() } @@ -45,7 +49,7 @@ export class BookImage { * @param id * @param operateBookType */ - async ResetGenerateImage(id: string, operateBookType: OperateBookType, coverData: boolean): Promise { + async ResetGenerateImage(id: string, operateBookType: OperateBookType): Promise { try { let bookTaskDetails = undefined as Book.SelectBookTaskDetail[] let bookTask = undefined as Book.SelectBookTask @@ -58,9 +62,8 @@ export class BookImage { throw new Error('不支持的操作类型,请检查') } //这边过滤被锁定的数据 - if (!coverData) { - bookTaskDetails = bookTaskDetails.filter(item => !item.imageLock) - } + bookTaskDetails = bookTaskDetails.filter(item => !item.imageLock) + if (bookTaskDetails.length <= 0) { throw new Error('没有要删除的分镜数据,请检查') @@ -69,15 +72,15 @@ export class BookImage { // 开始删除数据,要删除图片数据和出图的信息 for (let i = 0; i < bookTaskDetails.length; i++) { const element = bookTaskDetails[i]; - if (bookTask.imageCategory == BookImageCategory.MJ) { - await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id); - } else if (bookTask.imageCategory == BookImageCategory.D3) { - throw new Error('暂时不支持D3生成的图片删除') - } else if (bookTask.imageCategory == BookImageCategory.SD) { - await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id); - } else { - throw new Error('未知的小说类型,请检查') - } + await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id); + // if (bookTask.imageCategory == BookImageCategory.MJ) { + // } else if (bookTask.imageCategory == BookImageCategory.D3) { + // throw new Error('暂时不支持D3生成的图片删除') + // } else if (bookTask.imageCategory == BookImageCategory.SD) { + // await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id); + // } else { + // throw new Error('未知的小说类型,请检查') + // } // 上面的信息重置完毕之后,开始删除文件信息 let outImage = element.outImagePath; if (await CheckFileOrDirExist(outImage)) { @@ -322,7 +325,7 @@ export class BookImage { * @param imageUrl 图片地址 * @returns */ - async DownloadImageUrlAndSplit(bookTaskDetailId: string, imageUrl: string,) { + async DownloadImageUrlAndSplit(bookTaskDetailId: string, imageUrl: string,): Promise { try { let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskDetailId) if (bookTaskDetail == null) { @@ -348,19 +351,33 @@ export class BookImage { await this.tools.downloadFileUrl(imageUrl, imagePath) } - // 进行图片裁剪 - let imageRes = await ImageSplit(imagePath, bookTaskDetail.name, path.join(book.bookFolderPath, 'data\\MJOriginalImage')); - if (imageRes && imageRes.length < 4) { - throw new Error("图片裁剪失败") + let imageCategory = bookTask.imageCategory; + let out_file = undefined + let imageRes = [] + if (imageCategory == BookImageCategory.MJ) { + // 只有MJ需要裁剪,其他的不需要 + // 进行图片裁剪 + imageRes = await ImageSplit(imagePath, bookTaskDetail.name, path.join(book.bookFolderPath, 'data\\MJOriginalImage')); + if (imageRes && imageRes.length < 4) { + throw new Error("图片裁剪失败") + } + // 修改数据 + // 修改数据库数据,将图片保存到对应的文件夹中 + let firstImage = imageRes[0]; + if (book.type == BookType.ORIGINAL) { + await CopyFileOrFolder(firstImage, path.join(book.bookFolderPath, `tmp\\input\\${bookTaskDetail.name}.png`)); + } + out_file = path.join(bookTask.imageFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(firstImage, out_file); + } else { + // 其他的导入,每次只能导入一张图 + out_file = path.join(bookTask.imageFolder, `${bookTaskDetail.name}.png`); + if (book.type == BookType.ORIGINAL) { + await CopyFileOrFolder(imagePath, path.join(book.bookFolderPath, `tmp\\input\\${bookTaskDetail.name}.png`)); + } + await CopyFileOrFolder(imagePath, out_file); + imageRes = [out_file] } - // 修改数据 - // 修改数据库数据,将图片保存到对应的文件夹中 - let firstImage = imageRes[0]; - if (book.type == BookType.ORIGINAL) { - await CopyFileOrFolder(firstImage, path.join(book.bookFolderPath, `tmp\\input\\${bookTaskDetail.name}.png`)); - } - let out_file = path.join(bookTask.imageFolder, `${bookTaskDetail.name}.png`) - await CopyFileOrFolder(firstImage, out_file); // 修改分镜的数据 await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetailId, { @@ -368,9 +385,20 @@ export class BookImage { subImagePath: imageRes.map((item) => path.relative(define.project_path, item)) }) + let mjMessage = { + status: 'success', + progress: 100, + category: MJImageType.IMPORT, + messageId: '', + action: MJAction.IMAGINE, + }; + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(bookTaskDetailId, mjMessage) + + return successMessage({ outImagePath: out_file + '?time=' + new Date().getTime(), - subImagePath: imageRes.map((item) => item + '?time=' + new Date().getTime()) + subImagePath: imageRes.map((item) => item + '?time=' + new Date().getTime()), + mjMessage: mjMessage }, "下载指定的图片地址并且分割成功", "BookImage_DownloadImageUrlAndSplit") } catch (error) { return { @@ -379,4 +407,74 @@ export class BookImage { } } } + + + /** + * 获取指定的图片链接 ,然后下载图片 + * @param id + * @param operateBookType + * @param coverData + */ + async GetImageUrlAndDownload(id: string, operateBookType: OperateBookType, coverData: boolean): Promise { + try { + console.log("GetImageUrlAndDownload", id, operateBookType, coverData) + let bookTaskDetail = undefined as Book.SelectBookTaskDetail[] + let bookTask = undefined as Book.SelectBookTask + + if (operateBookType == OperateBookType.BOOKTASK) { + bookTask = await this.bookServiceBasic.GetBookTaskDataById(id); + bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: bookTask.id + }) + // 这边过滤出图成功的数据 + if (!coverData) { + bookTaskDetail = bookTaskDetail.filter((item) => !item.outImagePath) + } + } else if (operateBookType == OperateBookType.BOOKTASKDETAIL) { + let currentBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id); + bookTask = await this.bookServiceBasic.GetBookTaskDataById(currentBookTaskDetail.bookTaskId); + bookTaskDetail = [currentBookTaskDetail] + } else { + throw new Error('不支持的操作类型') + } + + // 这边再做个详细的筛选 + + if (bookTaskDetail.length < 0) { + throw new Error("没有找到需要采集的数据") + } + if (bookTask.imageCategory != BookImageCategory.MJ) { + throw new Error("只有MJ模式下才能使用这个功能") + } + let result = [] + + for (let i = 0; i < bookTaskDetail.length; i++) { + const element = bookTaskDetail[i]; + if (!element.mjMessage) continue; + if (element.mjMessage.status == 'error') continue; + if (isEmpty(element.mjMessage.messageId)) continue; + // 这边开始采集 + let res = await this.mjApi.GetMJAPITaskById(element.mjMessage.messageId, undefined); + if (isEmpty(res.imagePath)) { + throw new Error("获取图片地址链接为空") + } + // 开始下载 + let dr = await this.DownloadImageUrlAndSplit(element.id, res.imagePath); + if (dr.code == 0) { + throw new Error(dr.message) + } + result.push({ + id: element.id, + data: dr.data + }) + } + + if (result.length <= 0) { + throw new Error("没有找到需要采集的数据") + } + return successMessage(result, "获取图片链接并且下载成功", "BookImage_GetImageUrlAndDownload") + } catch (error) { + return errorMessage('获取图片链接并且下载失败,错误信息如下:' + error.message, 'BookImage_GetImageUrlAndDownload') + } + } } diff --git a/src/main/Service/Book/bookPrompt.ts b/src/main/Service/Book/bookPrompt.ts index 8ac9db7..0bf55cc 100644 --- a/src/main/Service/Book/bookPrompt.ts +++ b/src/main/Service/Book/bookPrompt.ts @@ -7,6 +7,11 @@ import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import { GptService } from "../GPT/gpt"; import { ExecuteConcurrently } from "../../../define/Tools/common"; import { DEFINE_STRING } from "../../../define/define_string"; +import { CheckFileOrDirExist } from "../../../define/Tools/file"; +import fs from 'fs'; +import path from 'path' +import readline from 'readline'; + export class BookPrompt { bookServiceBasic: BookServiceBasic @@ -16,6 +21,74 @@ export class BookPrompt { this.gptService = new GptService() } + //#region 提示词通用 + + /** + * 导入提示功能的函数 + * 该函数用于根据给定的小说任务ID和文本路径来处理一些导入逻辑 + * + * @param bookTaskId 小说任务的唯一标识符,用于跟踪和管理不同的导入任务 + * @param txtPath 待导入的文本文件的路径,指定了要处理的具体资源 + */ + async ImportGPTPrompt(bookTaskId: string, txtPath: string): Promise { + try { + console.log(bookTaskId, txtPath) + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: bookTaskId + }) + + if (isEmpty(txtPath)) { + throw new Error("传入的文件地址不能为空") + } + // 检查文件是不是存在 + if (!await CheckFileOrDirExist(txtPath)) { + throw new Error("传入的文件地址对应的文件不存在"); + } + + async function processLineByLine() { + const fileStream = fs.createReadStream(path.normalize(txtPath)); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + const lines = []; + for await (const line of rl) { + lines.push(line); + } + rl.close(); // 确保关闭 readline 流 + return lines; + } + let result = [] + // 这个就是txt文件里面所有的数据 + let lines = await processLineByLine() + // 这边开始写入 + for (let i = 0; i < bookTaskDetail.length; i++) { + const element = bookTaskDetail[i]; + if (i >= lines.length) { + break + } + // 修改 + this.bookServiceBasic.transaction((realm) => { + let btd = realm.objectForPrimaryKey("BookTaskDetail", element.id) + if (btd == null) { + throw new Error('未找到对应的分镜数据') + } + btd.gptPrompt = lines[i] + }) + result.push({ + id: element.id, + gptPrompt: lines[i] + }) + } + return successMessage(result, "导入提示词数据成功", 'Book_ImportGPTPrompt'); + } catch (error) { + return errorMessage("导入提示词失败,错误信息如下:" + error.message, "Book_ImportGPTPrompt") + } + } + + //#endregion + + //#region 反推的提示词相关 /** * 将MJ反推出来的数据,选择指定的写入到GPT提示词中 diff --git a/src/main/Service/Book/bookTask.ts b/src/main/Service/Book/bookTask.ts index 8a81ab6..c2a002b 100644 --- a/src/main/Service/Book/bookTask.ts +++ b/src/main/Service/Book/bookTask.ts @@ -50,8 +50,8 @@ export class BookTask { name: element.name, bookId: element.bookId, bookTaskId: newBookTask.id, - videoPath: path.relative(define.project_path, element.videoPath), - oldImage: path.relative(define.project_path, element.oldImage), + videoPath: element.videoPath ? path.relative(define.project_path, element.videoPath) : undefined, + oldImage: element.oldImage ? path.relative(define.project_path, element.oldImage) : undefined, adetailer: element.adetailer, sdConifg: element.sdConifg, createTime: new Date(), @@ -130,7 +130,7 @@ export class BookTask { generateVideoPath: undefined, srtPath: bookTask.srtPath, audioPath: bookTask.audioPath, - imageFolder: path.relative(define.project_path, imageFolder), + imageFolder: imageFolder ? path.relative(define.project_path, imageFolder) : undefined, status: BookTaskStatus.WAIT, errorMsg: undefined, updateTime: new Date(), @@ -278,16 +278,16 @@ export class BookTask { throw new Error("没有找到对应的数小说任务,请检查数据") } // 获取所有的出图中最少的 - let bookTaskDetail = (await this.bookServiceBasic.GetBookTaskData({ + let bookTaskDetail = (await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: bookTaskId - })).bookTasks as Book.SelectBookTaskDetail[] + })) as Book.SelectBookTaskDetail[] if (bookTaskDetail == null || bookTaskDetail.length <= 0) { throw new Error("没有对应的小说分镜任务,请先添加分镜任务") } for (let i = 0; i < bookTaskDetail.length; i++) { const element = bookTaskDetail[i]; - if (isEmpty(element.subImagePath)) { + if (!element.subImagePath) { throw new Error("检测到图片没有出完,请先检查出图") } if (element.subImagePath == null || element.subImagePath.length <= 0) { @@ -324,7 +324,7 @@ export class BookTask { // 先处理文件夹的创建,包括小说任务的和小说任务分镜的 for (let i = 0; i < copyCount; i++) { - let no = await this.bookServiceBasic.GetMaxBookTaskNo(sourceBookTask.bookId) + let no = await this.bookServiceBasic.GetMaxBookTaskNo(sourceBookTask.bookId) + i let name = 'output_0000' + no let imageFolder = path.join(define.project_path, `${sourceBookTask.bookId}/tmp/${name}`) await CheckFolderExistsOrCreate(imageFolder) @@ -408,35 +408,35 @@ export class BookTask { } } - let addOneBookTaskDetail = { - id: reverseId, - no: element.no, - name: element.name, - bookId: sourceBookTask.bookId, - bookTaskId: addOneBookTask.id, - videoPath: path.relative(define.project_path, element.videoPath), - word: element.word, - oldImage: path.relative(define.project_path, element.oldImage), - afterGpt: element.afterGpt, - startTime: element.startTime, - endTime: element.endTime, - timeLimit: element.timeLimit, - subValue: element.subValue && element.subValue.length > 0 ? JSON.stringify(element.subValue) : undefined, - characterTags: element.characterTags && element.characterTags.length > 0 ? cloneDeep(element.characterTags) : [], - gptPrompt: element.gptPrompt, - outImagePath: path.relative(define.project_path, outImagePath), - subImagePath: subImagePath || [], - prompt: element.prompt, - adetailer: element.adetailer, - sdConifg: sdConifg, - createTime: new Date(), - updateTime: new Date(), - audioPath: element.audioPath, - subtitlePosition: element.subtitlePosition, - status: element.status, - reversePrompt: reverseMessage, - imageLock: element.imageLock - } as Book.SelectBookTaskDetail + let addOneBookTaskDetail = {} as Book.SelectBookTaskDetail + addOneBookTaskDetail.id = reverseId; + addOneBookTaskDetail.no = element.no; + addOneBookTaskDetail.name = element.name; + addOneBookTaskDetail.bookId = sourceBookTask.bookId; + addOneBookTaskDetail.bookTaskId = addOneBookTask.id; + addOneBookTaskDetail.videoPath = element.videoPath ? path.relative(define.project_path, element.videoPath) : undefined; + addOneBookTaskDetail.word = element.word; + addOneBookTaskDetail.oldImage = element.oldImage ? path.relative(define.project_path, element.oldImage) : undefined; + addOneBookTaskDetail.afterGpt = element.afterGpt; + addOneBookTaskDetail.startTime = element.startTime; + addOneBookTaskDetail.endTime = element.endTime; + addOneBookTaskDetail.timeLimit = element.timeLimit; + addOneBookTaskDetail.subValue = (element.subValue && element.subValue.length > 0 ? JSON.stringify(element.subValue) : undefined) as string; + addOneBookTaskDetail.characterTags = element.characterTags && element.characterTags.length > 0 ? cloneDeep(element.characterTags) : []; + addOneBookTaskDetail.gptPrompt = element.gptPrompt; + addOneBookTaskDetail.outImagePath = outImagePath ? path.relative(define.project_path, outImagePath) : undefined; + addOneBookTaskDetail.subImagePath = subImagePath || []; + addOneBookTaskDetail.prompt = element.prompt; + addOneBookTaskDetail.adetailer = element.adetailer; + addOneBookTaskDetail.sdConifg = sdConifg; + addOneBookTaskDetail.createTime = new Date(); + addOneBookTaskDetail.updateTime = new Date(); + addOneBookTaskDetail.audioPath = element.audioPath; + addOneBookTaskDetail.subtitlePosition = element.subtitlePosition; + addOneBookTaskDetail.status = element.status; + addOneBookTaskDetail.reversePrompt = reverseMessage; + addOneBookTaskDetail.imageLock = element.imageLock + addBookTaskDetail.push(addOneBookTaskDetail) } } diff --git a/src/main/Service/MJ/mj.ts b/src/main/Service/MJ/mj.ts index 50aab0d..09e0382 100644 --- a/src/main/Service/MJ/mj.ts +++ b/src/main/Service/MJ/mj.ts @@ -775,7 +775,7 @@ export class MJOpt { messageId: undefined, id: task.bookTaskDetailId, progress: 0, - message: error.toString(), + message: errorMsg, status: "error" } }, task.messageName) @@ -788,7 +788,7 @@ export class MJOpt { messageId: "", action: MJAction.IMAGINE, status: "error", - message: error.toString() + message: errorMsg }) return errorMessage(errorMsg, "MJReverse_MJImage2Text") } diff --git a/src/main/Service/MJ/mjApi.ts b/src/main/Service/MJ/mjApi.ts index 08a0bde..81da1c9 100644 --- a/src/main/Service/MJ/mjApi.ts +++ b/src/main/Service/MJ/mjApi.ts @@ -9,6 +9,7 @@ import { MJSetting } from "../../../model/Setting/mjSetting" import { GPT } from "../../Public/GPT" import { MJ } from "../../../model/mj" import { LaiAPIType } from "../../../define/enum/softwareEnum" +import { isEmpty } from "lodash" /** * 调用MJ的API类 @@ -96,11 +97,13 @@ class MJApi { let _bookBackTaskListService = await BookBackTaskListService.getInstance() // 失败 if (code == 0) { - _bookBackTaskListService.UpdateTaskStatus({ - id: backTaskId, - status: BookBackTaskStatus.FAIL, - errorMessage: res.data.message - }) + if (!isEmpty(backTaskId)) { + _bookBackTaskListService.UpdateTaskStatus({ + id: backTaskId, + status: BookBackTaskStatus.FAIL, + errorMessage: res.data.message + }) + } } let resObj = { type: MJRespoonseType.UPDATED, diff --git a/src/model/book.d.ts b/src/model/book.d.ts index 77d7349..cc61724 100644 --- a/src/model/book.d.ts +++ b/src/model/book.d.ts @@ -88,9 +88,9 @@ declare namespace Book { // 字幕相关 type Subtitle = { - startTime: number - endTime: number - srtValue: string + start_time: number + end_time: number + srt_value: string id: string } @@ -152,7 +152,7 @@ declare namespace Book { startTime?: number // 开始时间 endTime?: number // 结束时间 timeLimit?: string // 事件实现(0 -- 3000) - subValue?: string // 包含的字幕数据 + subValue?: Subtitle[] | string // 包含的字幕数据 characterTags?: string[] // 角色标签 sceneTags?: string[] // 场景标签 gptPrompt?: string // GPT提示词 @@ -279,8 +279,8 @@ declare namespace Book { type ReplaceDataRes = { bookTaskDetailId: string, - newData: string, - type?: 'reversePrompt' | 'gptPrompt' | 'afterGpt' | 'prompt', + newData: string | Subtitle[], + type?: 'reversePrompt' | 'gptPrompt' | 'afterGpt' | 'prompt' | 'subValue', reversePromptType?: 'prompt' | 'promptCN' reversePromptId?: string } diff --git a/src/preload/book.ts b/src/preload/book.ts index 5be2918..9e35458 100644 --- a/src/preload/book.ts +++ b/src/preload/book.ts @@ -158,6 +158,8 @@ const book = { OriginalGetPrompt: async (id: string, operateBookType: OperateBookType, coverData: boolean) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT, id, operateBookType, coverData), + // 导入提示词 + ImportGPTPrompt: async (bookTaskId: string, txtPath: string) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.IMPORT_GPT_PROMPT, bookTaskId, txtPath), //#endregion //#region 图片相关 @@ -166,6 +168,10 @@ const book = { ResetGenerateImage: async (id: string, operateBookType: OperateBookType, coverData: boolean) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_GENERATE_IMAGE, id, operateBookType, coverData), + // 获取图片的连接,然后下载图片 + GetImageUrlAndDownload: async (id: string, operateBookType: OperateBookType, coverData: boolean) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_IMAGE_URL_AND_DOWNLOAD, id, operateBookType, coverData), + //#endregion //#region 一键反推的单个任务 diff --git a/src/renderer/src/components/Book/Components/DatatableAfterGpt.vue b/src/renderer/src/components/Book/Components/DatatableAfterGpt.vue index ae23ba7..d50f47a 100644 --- a/src/renderer/src/components/Book/Components/DatatableAfterGpt.vue +++ b/src/renderer/src/components/Book/Components/DatatableAfterGpt.vue @@ -1,11 +1,11 @@ diff --git a/src/renderer/src/components/Book/Original/OriginalMainButton.vue b/src/renderer/src/components/Book/Original/OriginalMainButton.vue index afee40f..3fb2e3b 100644 --- a/src/renderer/src/components/Book/Original/OriginalMainButton.vue +++ b/src/renderer/src/components/Book/Original/OriginalMainButton.vue @@ -77,6 +77,7 @@ import { } from '../../../../../define/enum/bookEnum' import { useRouter } from 'vue-router' import { DEFINE_STRING } from '../../../../../define/define_string' +import { isEmpty } from 'lodash' let softwareStore = useSoftwareStore() let reverseManageStore = useReverseManageStore() let dialog = useDialog() @@ -92,8 +93,8 @@ let GenerateImageOptions = ref([ { label: '停止生成图片任务', key: 'stop_generate_image' } ]) let ResetDataOptions = ref([ - { label: '重置GPT提示词', key: 'reset_gpt_prompt' }, - { label: '重置提示词', key: 'reset_prompt' }, + { label: '重置GPT提示词', key: 'reset_prompt' }, + { label: '重置提示词', key: 'reset_merge_prompt' }, { label: '重置图片', key: 'reset_image' } ]) @@ -246,6 +247,39 @@ async function ResetGPTPrompt() { }) } +// 重置所有的合并提示词数据 +async function ResetMergePrompt() { + let da = dialog.warning({ + title: '重置合并提示词提示', + content: '执行该操作会删除所有的合并提示词,并且此操作不可逆,是否继续?', + positiveText: '继续', + negativeText: '取消', + onPositiveClick: async () => { + da?.destroy() + softwareStore.spin.spinning = true + softwareStore.spin.tip = '正在重置推理提示词,请稍后。。。' + for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) { + const element = reverseManageStore.selectBookTaskDetail[i] + let res = await window.db.UpdateBookTaskDetailData(element.id, { + prompt: '' + }) + if (res.code == 1) { + let findIndex = reverseManageStore.selectBookTaskDetail.findIndex( + (item) => item.id == element.id + ) + if (findIndex != -1) { + reverseManageStore.selectBookTaskDetail[findIndex].prompt = '' + } + } else { + message.error(res.message) + } + } + softwareStore.spin.spinning = false + message.success('重置提示词数据成功') + } + }) +} + // 重置所有的生成图片信息 async function ResetImage() { message.info('ResetImage') @@ -295,6 +329,9 @@ async function ButtonSelect(key) { } else if (key == 'generate_space_image') { // 生成未出图分镜 await GenerateImageAll(false) + } else if (key == 'reset_merge_prompt') { + // 重置合并提示词 + await ResetMergePrompt() } else if (key == 'reset_image') { await ResetImage() } else { @@ -454,47 +491,44 @@ async function OpenPromptSetting() { // 导入提示词 async function ImportPrompt() { - message.error('导入提示词该方法暂未实现') - return // 弹窗选择文件 window.api.SelectFile(['txt'], async (value) => { if (value.code == 0) { message.error(value.message) return } - // 拿到提示词文件地址,然后还是获取 - await window.pmpt.OpenPromptFileTxt(value.value, (res) => { - debugger - console.log(res) - if (res.code == 0) { - message.error(res.message) - return - } - // 修改数据 - // 判断获取的数据是不是小于当前的data的行 - if (res.data.length > data.value.length) { - dialog.warning({ - title: '提示', - content: '导入的数据行数大于当前的数据行数,多余的数据会被删除,是否继续导入?', - positiveText: '继续', - negativeText: '取消', - onPositiveClick: async () => { - debugger - // 开始导入 - for (let i = 0; i < data.value.length && i < res.data.length; i++) { - const element = res.data[i] - // 开始修改 - data.value[i].gpt_prompt = element + if (isEmpty(value.value)) { + message.error('返回的文件地址为空') + return + } + + let da = dialog.warning({ + title: '导入提示词提示', + content: `即将开始导入提示词,务必保证提示词文件的行数和分镜的行数相同,否则可能会导致数据丢失,当前的导入的文件地址为 ${value.value},是否继续?`, + positiveText: '继续', + negativeText: '取消', + onPositiveClick: async () => { + da?.destroy() + softwareStore.spin.spinning = true + softwareStore.spin.tip = '正在导入提示词数据中。。。' + let res = await window.book.ImportGPTPrompt( + reverseManageStore.selectBookTask.id, + value.value + ) + softwareStore.spin.spinning = false + if (res.code == 1) { + // 这边还要修改下前端界面 + for (let i = 0; i < res.data.length; i++) { + const element = res.data[i] + let findIndex = reverseManageStore.selectBookTaskDetail.findIndex( + (item) => item.id == element.id + ) + if (findIndex != -1) { + reverseManageStore.selectBookTaskDetail[findIndex].gptPrompt = element.gptPrompt } } - }) - } else { - // 开始导入 - for (let i = 0; i < data.value.length && i < res.data.length; i++) { - const element = res.data[i] - // 开始修改 - data.value[i].gpt_prompt = element } + window.api.showGlobalMessage(res) } }) }) diff --git a/src/renderer/src/components/Book/Original/OriginalMainDatatable.vue b/src/renderer/src/components/Book/Original/OriginalMainDatatable.vue index e8a3e9d..1d1e8e8 100644 --- a/src/renderer/src/components/Book/Original/OriginalMainDatatable.vue +++ b/src/renderer/src/components/Book/Original/OriginalMainDatatable.vue @@ -107,6 +107,7 @@ const createColumns = ({}) => { className: 'empty-margin', fixed: 'left', render(row, index) { + console.log('row', row, index) return h(DatatableAfterGpt, { initData: row, index: index }) } }, @@ -133,7 +134,7 @@ const createColumns = ({}) => { resizable: true, minWidth: 330, maxWidth: 700, - width: '350', + width: '360', render(row, index) { return h(ODataTableGptPrompt, { initData: row, index: index }) } diff --git a/src/stores/reverseManage.ts b/src/stores/reverseManage.ts index ac2472c..49c74c0 100644 --- a/src/stores/reverseManage.ts +++ b/src/stores/reverseManage.ts @@ -230,10 +230,17 @@ export const useReverseManageStore = defineStore('reverseManage', { */ async GetBookTaskDetail(bookTaskId: string, modifyProperty = null): Promise { try { - debugger //@ts-ignore let detailRes = await window.book.GetBookTaskDetail(bookTaskId) + let bookTaskDetail = [] if (detailRes.code == 1) { + bookTaskDetail = detailRes.data.map(item => { + return { + ...item, + outImagePath: item.outImagePath ? item.outImagePath + '?t=' + new Date().getTime() : undefined, + subImagePath: item.subImagePath ? item.subImagePath.map(item => item + '?t=' + new Date().getTime()) : [] + } + }) // 这边开始修改数据, if (this.selectBookTaskDetail && this.selectBookTaskDetail.length > 0) { this.selectBookTaskDetail.splice(0, this.selectBookTaskDetail.length, ...detailRes.data); @@ -243,7 +250,7 @@ export const useReverseManageStore = defineStore('reverseManage', { } else { return errorMessage(detailRes.message) } - return successMessage(detailRes.data) + return successMessage(bookTaskDetail) } catch (error) { return errorMessage("获取小说任务详细数据失败,失败信息如下: " + error.toString()) }