import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFolderAllFile } from "../../../define/Tools/file"; import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService"; import { BookService } from "../../../define/db/service/Book/bookService"; import { BookTaskStatus, CopyImageType, OperateBookType } from "../../../define/enum/bookEnum"; import { errorMessage, successMessage } from "../../Public/generalTools"; import { Book } from "../../../model/book"; import path from 'path' import { cloneDeep, isEmpty } from "lodash"; import { define } from '../../../define/define' import { v4 as uuidv4 } from 'uuid' import { GeneralResponse } from "../../../model/generalResponse"; /** * 小说批次相关的操作 */ export class BookTask { bookTaskService: BookTaskService bookTaskDetailService: BookTaskDetailService bookService: BookService constructor() { } async InitService() { if (!this.bookTaskService) { this.bookTaskService = await BookTaskService.getInstance() } if (!this.bookTaskDetailService) { this.bookTaskDetailService = await BookTaskDetailService.getInstance() } if (!this.bookService) { this.bookService = await BookService.getInstance() } } /** * 重置小说任务数据 * @param bookTaskId 小说任务ID */ async ReSetBookTask(bookTaskId: string): Promise { try { console.log(bookTaskId) await this.InitService() let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId); if (bookTask == null) { throw new Error('未找到对应的小说任务') } this.bookTaskService.ResetBookTask(bookTaskId); // 数据库删除完毕,看是删除对应的文件(主要是图片) let imageFolder = bookTask.imageFolder; // 整个删掉在重建 await DeleteFolderAllFile(imageFolder) await CheckFolderExistsOrCreate(imageFolder) return successMessage(null, "重置小说数据成功", "BookTask_ReSetBookTask") } catch (error) { return errorMessage('重置小说批次数据失败,错误信息如下' + error.toString(), "BookTask_ReSetBookTask"); } } /** * 删除对应的小说批次数据 * @param bookTaskId 小说批次ID */ async DeleteBookTask(bookTaskId: string): Promise { try { await this.InitService(); let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId); if (bookTask == null) { throw new Error('未找到对应的小说任务,无法执行删除操作') } let imageFolder = bookTask.imageFolder; // 先删除每个批次对应的数据,然后删除批次 this.bookTaskService.DeleteBookTask(bookTaskId); // 删除成功,直接把对应的出图文件夹删掉 await DeleteFolderAllFile(imageFolder, true) return successMessage(null, "删除小说批次数据成功", "BookTask_DeleteBookTask") } catch (error) { return errorMessage('删除小说批次数据失败,错误信息如下' + error.toString(), "BookTask_DeleteBookTask"); } } /** * 将小说批次任务出图进行一拆四 * @param bookTaskId 操作的小说批次任务ID * @returns */ async OneToFourBookTask(bookTaskId: string) { try { console.log(bookTaskId) await this.InitService(); let copyCount = 100 let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId) if (bookTask == null) { throw new Error("没有找到对应的数小说任务,请检查数据") } // 获取所有的出图中最少的 let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({ bookTaskId: bookTaskId }).data 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)) { throw new Error("检测到图片没有出完,请先检查出图") } if (element.subImagePath == null || element.subImagePath.length <= 0) { throw new Error("检测到图片没有出完,请先检查出图") } if (element.subImagePath.length < copyCount) { copyCount = element.subImagePath.length } } if (copyCount <= 0) { throw new Error("批次设置错误,无法进行一拆四") } // 开始复制 let res = await this.CopyNewBookTask(bookTask, bookTaskDetail, copyCount - 1, CopyImageType.ONE) if (res.code == 0) { throw new Error(res.message) } return successMessage(res.data, "一拆四成功", "BookBasic_OneToFourBookTask") } catch (error) { return errorMessage("一拆四失败,失败信息如下:" + error.message, "BookBasic_OneToFourBookTask") } } /** * 复制一个小说批次任务,创建新的小说批次任务 * @param oldBookTaskId * @param copyCount 复制的数量 * @param isCopyImage 是否复制图片 */ async CopyNewBookTask(sourceBookTask: Book.SelectBookTask, sourceBookTaskDetail: Book.SelectBookTaskDetail[], copyCount: number, copyImageType: CopyImageType) { try { await this.InitService(); let addBookTask = [] as Book.SelectBookTask[] let addBookTaskDetail = [] as Book.SelectBookTaskDetail[] // 先处理文件夹的创建,包括小说任务的和小说任务分镜的 for (let i = 0; i < copyCount; i++) { let maxNo = this.bookTaskService.realm .objects('BookTask') .filtered('bookId = $0', sourceBookTask.bookId) .max('no') let no = maxNo == null ? 1 : Number(maxNo) + 1 + i let name = 'output_0000' + no let imageFolder = path.join(define.project_path, `${sourceBookTask.bookId}/tmp/${name}`) await CheckFolderExistsOrCreate(imageFolder) // 创建对应的文件夹 let addOneBookTask = { id: uuidv4(), bookId: sourceBookTask.bookId, no: no, name: name, generateVideoPath: sourceBookTask.generateVideoPath, srtPath: sourceBookTask.srtPath, audioPath: sourceBookTask.audioPath, draftSrtStyle: sourceBookTask.draftSrtStyle, backgroundMusic: sourceBookTask.backgroundMusic, friendlyReminder: sourceBookTask.friendlyReminder, imageFolder: path.relative(define.project_path, imageFolder), status: sourceBookTask.status, errorMsg: sourceBookTask.errorMsg, updateTime: new Date(), createTime: new Date(), isAuto: sourceBookTask.isAuto, imageStyle: sourceBookTask.imageStyle, autoAnalyzeCharacter: sourceBookTask.autoAnalyzeCharacter, customizeImageStyle: sourceBookTask.customizeImageStyle, videoConfig: sourceBookTask.videoConfig, prefixPrompt: sourceBookTask.prefixPrompt, suffixPrompt: sourceBookTask.suffixPrompt, version: sourceBookTask.version, imageCategory: sourceBookTask.imageCategory, } as Book.SelectBookTask addBookTask.push(addOneBookTask) for (let j = 0; j < sourceBookTaskDetail.length; j++) { const element = sourceBookTaskDetail[j]; let outImagePath = undefined as string let subImagePath = [] as string[] if (copyImageType == CopyImageType.ALL) { // 直接全部复制 outImagePath = element.outImagePath subImagePath = element.subImagePath } else if (copyImageType == CopyImageType.ONE) { // 只复制对应的 let oldImage = element.subImagePath[i + 1] outImagePath = path.join(imageFolder, path.basename(element.outImagePath)) await CopyFileOrFolder(oldImage, outImagePath) subImagePath = [] } else if (copyImageType == CopyImageType.NONE) { outImagePath = undefined subImagePath = [] } else { throw new Error("无效的图片复制类型") } if (outImagePath) { // 单独处理一下显示的图片 let imageBaseName = path.basename(element.outImagePath); let newImageBaseName = path.join(define.project_path, `${sourceBookTask.bookId}/tmp/${name}/${imageBaseName}`) await CopyFileOrFolder(outImagePath, newImageBaseName) } // 处理SD设置 let sdConifg = undefined if (element.sdConifg) { let sdConifg = cloneDeep(element.sdConifg) if (sdConifg.webuiConfig) { let tempSdConfig = cloneDeep(sdConifg.webuiConfig); tempSdConfig.id = uuidv4() sdConifg.webuiConfig = tempSdConfig } } let reverseId = uuidv4() // 处理反推数据 let reverseMessage = [] as Book.ReversePrompt[] if (element.reversePrompt && element.reversePrompt.length > 0) { reverseMessage = cloneDeep(element.reversePrompt) for (let k = 0; k < reverseMessage.length; k++) { reverseMessage[k].id = uuidv4() reverseMessage[k].bookTaskDetailId = reverseId } } 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, 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 addBookTaskDetail.push(addOneBookTaskDetail) } } // 数据处理完毕,开始新增数据 // 将所有的复制才做,全部放在一个事务中 this.bookTaskService.transaction(() => { for (let i = 0; i < addBookTask.length; i++) { const element = addBookTask[i]; this.bookTaskService.realm.create('BookTask', element) } for (let i = 0; i < addBookTaskDetail.length; i++) { const element = addBookTaskDetail[i]; this.bookTaskDetailService.realm.create('BookTaskDetail', element) } }) // 全部创建完成 // 查找到数据,然后全部返回 let returnBookTask = this.bookTaskService.GetBookTaskData({ bookId: sourceBookTask.bookId }).data as Book.SelectBookTask[] return successMessage(returnBookTask, "复制小说任务成功", "BookBasic_CopyNewBookTask") } catch (error) { console.log(error) throw error } } }