import path from 'path' import fs from 'fs' const util = require('util') const { exec } = require('child_process') const execAsync = util.promisify(exec) import { define } from '../../define/define' import { BookService } from '../../define/db/service/Book/bookService' import { TaskScheduler } from './taskScheduler' import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum' import { errorMessage, successMessage } from '../generalTools' import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from '../../define/Tools/file' import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService' import { BookBackTaskListService } from '../../define/db/service/Book/bookBackTaskListService' import { BookTaskService } from '../../define/db/service/Book/bookTaskService' import { isEmpty, set } from 'lodash' import { TimeStringToMilliseconds, MillisecondsToTimeString } from '../../define/Tools/time' import { FfmpegOptions } from './ffmpegOptions' import { BookBackTaskType, BookTaskStatus, BookType, TaskExecuteType } from '../../define/enum/bookEnum' const fspromises = fs.promises /** * 后台执行的任务函数,直接调用改函数即可,抽帧,分镜,提取字幕等 */ export class BasicReverse { constructor() { this.taskScheduler = new TaskScheduler() this.ffmpegOptions = new FfmpegOptions() } /** * 初始化服务 */ async InitService() { if (!this.bookService) { this.bookService = await BookService.getInstance() } if (!this.bookTaskService) { this.bookTaskService = await BookTaskService.getInstance() } if (!this.bookTaskDetailService) { this.bookTaskDetailService = await BookTaskDetailService.getInstance() } if (!this.bookBackTaskListService) { this.bookBackTaskListService = await BookBackTaskListService.getInstance() } } //#region 计算视频的分镜,操作 /** * 添加分镜计算的任务 * @param {*} bookId */ async AddFrameDataTask(bookId) { try { await this.InitService() // 获取对应的小说小说数据,找到对应的小说视频地址 let bookQuery = { bookId: bookId } let bookData = this.bookService.GetBookData(bookQuery) if (bookData.code == 0) { return bookData } if (bookData.data.book_length <= 0 || bookData.data.res_book.length <= 0) { throw new Error('没有找到对应的小说数据,请检查bookId是否正确') } // 获取小说对应的批次任务数据,默认初始化为第一个 let bookTaskRes = this.bookTaskService.GetBookTaskData({ bookId: bookId, name: 'output_00001' }) if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } // 获取小说的视频地址 let book = bookData.data.res_book[0] let bookTask = bookTaskRes.data.bookTasks[0] // 开始添加任务 let taskRes = await this.bookBackTaskListService.AddBookBackTask( bookId, BookBackTaskType.STORYBOARD, TaskExecuteType.AUTO, bookTask.id, null ) if (taskRes.code == 0) { throw new Error(taskRes.message) } this.taskScheduler.AddLogToDB( bookId, book.type, `添加分镜任务成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage(null, '添加分镜任务成功', 'BasicReverse_AddFrameDataTask') } catch (error) { return errorMessage( '添加分镜任务失败,错误信息如下: ' + error.message, 'BasicReverse_AddFrameDataTask' ) } } /** * 执行分镜任务,通过task获取 * @param {*} task * @returns */ async GetFrameData(task) { try { // 分镜任务一定有对应的小说ID和对应的小说批次任务ID,没有直接报错 if (isEmpty(task.bookId) || isEmpty(task.bookTaskId)) { throw new Error('分镜任务,bookId, bookTaskId不能为空') } await this.InitService() let bookId = task.bookId let bookTaskId = task.bookTaskId let bookRes = this.bookService.GetBookDataById(bookId) if (bookRes.data == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data this.bookTaskService.UpdateBookTaskStatus(bookTaskId, BookTaskStatus.STORYBOARD) // 分镜之前,删除之前的老数据 let deleteBookTaskRes = this.bookTaskDetailService.DeleteBookTaskDetail({ bookId: bookId, bookTaskId: bookTaskId }) let oldVideoPath = book.oldVideoPath let frameJson = oldVideoPath + '.json' let sensitivity = 30 // 开始之前,推送日志 let log_content = `开始进行分镜操作,视频地址:${oldVideoPath},敏感度:${sensitivity},正在调用程序进行处理` await this.taskScheduler.AddLogToDB( bookId, book.type, log_content, OtherData.DEFAULT, LoggerStatus.DOING ) // 小说进行分镜(python进行,将结果写道一个json里面) // 使用异步的方法调用一个python程序,然后写入到指定的json文件中k let command = `"${path.join( define.scripts_path, 'Lai.exe' )}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"` const output = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }) // 有错误输出 if (output.stderr != '') { let error_msg = `分镜成功,但有警告提示:${output.stderr}` await this.taskScheduler.AddLogToDB( bookId, book.type, error_msg, OtherData.DEFAULT, LoggerStatus.FAIL ) } // 分镜成功,处理输出 let josnIsExist = await CheckFileOrDirExist(frameJson) if (!josnIsExist) { let error_message = `分镜失败,没有找到对应的分镜输出文件:${frameJson}` this.bookTaskService.UpdateBookTaskStatus( bookTaskId, BookTaskStatus.STORYBOARD_FAIL, error_message ) await this.taskScheduler.AddLogToDB( bookId, book.type, error_message, OtherData.DEFAULT, LoggerStatus.FAIL ) throw new Error(error_message) } let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8')) if (frameJsonData.length <= 0) { let error_msg = `分镜失败,没有找到对应的分镜数据` this.bookTaskService.UpdateBookTaskStatus( bookTaskId, BookTaskStatus.STORYBOARD_FAIL, error_msg ) await this.taskScheduler.AddLogToDB( bookId, book.type, error_msg, OtherData.DEFAULT, LoggerStatus.FAIL ) throw new Error(error_msg) } // 循环写入小说人物详细数据 for (let i = 0; i < frameJsonData.length; i++) { let dataArray = frameJsonData[i] let bookTaskDetail = { bookId: bookId, bookTaskId: bookTaskId } // 将字符串转换为number bookTaskDetail.startTime = TimeStringToMilliseconds(dataArray[0]) bookTaskDetail.endTime = TimeStringToMilliseconds(dataArray[1]) let res = this.bookTaskDetailService.AddBookTaskDetail(bookTaskDetail) if (res.code == 0) { throw new Error(res.message) } } this.bookTaskService.UpdateBookTaskStatus(task.bookTaskId, BookTaskStatus.STORYBOARD_DONE) // 分镜成功,推送日志 await this.taskScheduler.AddLogToDB( bookId, book.type, `分镜成功,分镜数据如下:${frameJsonData}`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage(null, `分镜成功,分镜信息在 ${frameJson}`, 'BasicReverse_GetFrameData') } catch (error) { return errorMessage(error.message, 'BasicReverse_GetFrameData') } } //#endregion 计算视频的分镜 //#region 裁剪视频的相关操作 /** * 添加裁剪视频的任务 * @param {*} bookId 小说ID * @param {*} frameJson 存放分镜数据的json文件地址 */ async AddCutVideoDataTask(bookId) { try { if (isEmpty(bookId)) { throw new Error('bookId不能为空') } await this.InitService() // 判断小说是不是存在 let bookRes = this.bookService.GetBookDataById(bookId) if (bookRes == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data // 找到对应的小说ID和对应的小说批次任务ID,判断是不是有分镜数据 let bookTaskRes = this.bookTaskService.GetBookTaskData({ bookId: bookId, name: 'output_00001' }) if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } let bookTask = bookTaskRes.data.bookTasks[0] let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({ bookId: bookId, bookTaskId: bookTask.id }) if (bookTaskDetail.data.length <= 0) { // 传入的分镜数据为空,需要重新获取 await this.taskScheduler.AddLogToDB( bookId, book.type, `没有传入分镜数据,开始调用分镜方法`, OtherData.DEFAULT, LoggerStatus.DOING ) let frameRes = this.GetFrameData(bookId) if (frameRes.code == 0) { throw new Error((await frameRes).message) } } bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({ bookId: bookId, bookTaskId: bookTask.id }) if (bookTaskDetail.data.length <= 0) { this.bookTaskService.UpdateBookTaskStatus( bookTask.id, BookTaskStatus.SPLIT_FAIL, '重新调用分镜方法还是没有分镜数据,请检查' ) throw new Error('重新调用分镜方法还是没有分镜数据,请检查') } this.bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT) // 有分镜数据,开始处理 await this.taskScheduler.AddLogToDB( bookId, book.type, `成功获取分镜数据,开始添加裁剪视频任务`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) // 添加裁剪视频任务 for (let i = 0; i < bookTaskDetail.data.length; i++) { const element = bookTaskDetail.data[i] // 创建后台的视频分割任务 let taskRes = await this.bookBackTaskListService.AddBookBackTask( bookId, BookBackTaskType.SPLIT, TaskExecuteType.AUTO, bookTask.id, element.id ) if (taskRes.code == 0) { throw new Error(taskRes.message) } } // 添加日志 await this.taskScheduler.AddLogToDB( bookId, book.type, `添加视频裁剪任务成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage(null, '添加视频裁剪任务成功', 'BasicReverse_AddCutVideoDataTask') } catch (error) { await this.taskScheduler.AddLogToDB( bookId, book.type, error.message, OtherData.DEFAULT, LoggerStatus.FAIL ) return errorMessage( '添加视频裁剪任务失败,错误信息如下: ' + error.message, 'BasicReverse_CutVideoData' ) } } /** * 开始执行指定的任务 * @param {*} task * @returns */ async CutVideoData(task) { try { // 视频分割任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID,没有直接报错 if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) { throw new Error('分镜任务,bookId, bookTaskId, bookTaskDetailId不能为空') } await this.InitService() let bookTaskDetailRes = this.bookTaskDetailService.GetBookTaskDetailDataById( task.bookTaskDetailId ) if (bookTaskDetailRes.code == 0) { throw new Error(bookTaskDetailRes.message) } if (bookTaskDetailRes.data == null) { throw new Error('没有找到对应的分镜数据') } // 开始执行裁剪视频 let bookTaskDetail = bookTaskDetailRes.data let startTime = bookTaskDetail.startTime let endTime = bookTaskDetail.endTime let bookRes = this.bookService.GetBookDataById(task.bookId) if (bookRes.data == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data if (startTime == null || endTime == null) { this.bookTaskService.UpdateBookTaskStatus( task.bookTaskId, BookTaskStatus.SPLIT_FAIL, '开始时间和结束时间不能为空' ) throw new Error('开始时间和结束时间不能为空') } let outVideoFile = path.join(book.bookFolderPath, `data/frame/${bookTaskDetail.name}.mp4`) let res = await this.ffmpegOptions.FfmpegCutVideo( startTime, endTime, book.oldVideoPath, outVideoFile ) if (res.code == 0) { this.bookTaskService.UpdateBookTaskStatus( task.bookTaskId, BookTaskStatus.SPLIT_FAIL, res.message ) throw new Error(res.message) } // 视频裁剪完成,要将裁剪后的视频地址写入到数据库中 this.bookTaskDetailService.UpdateBookTaskDetail(task.bookTaskDetailId, { videoPath: path.relative(define.project_path, outVideoFile) }) // 小改小说批次的状态 this.bookTaskService.UpdateBookTaskStatus(task.bookTaskId, BookTaskStatus.SPLIT_DONE) // 结束,分镜完毕,推送日志,返回成功 await this.taskScheduler.AddLogToDB( task.bookId, book.type, `${task.name}_视频裁剪完成`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage(null, `${task.name}_视频裁剪完成`, 'BasicReverse_CutVideoData') } catch (error) { await this.taskScheduler.AddLogToDB( task.bookId, task.type, error.message, OtherData.DEFAULT, LoggerStatus.FAIL ) return errorMessage( '裁剪视频失败,错误信息如下: ' + error.message, 'BasicReverse_CutVideoData' ) } } //#endregion //#region 分离音频的相关操作 /** * 添加视频分离音频的任务 * @param {*} bookId 小说ID * @param {*} bookTaskId 小说任务ID * @returns */ async AddSplitAudioDataTask(bookId, bookTaskId = null) { try { await this.InitService() let bookRes = this.bookService.GetBookDataById(bookId) if (bookRes == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data let bookTaskRes if (bookTaskId != null) { bookTaskRes = this.bookTaskService.GetBookTaskData({ id: bookTaskId }) } else { bookTaskRes = this.bookTaskService.GetBookTaskData({ bookId: bookId, name: 'output_00001' }) } if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { await this.taskScheduler.AddLogToDB( bookId, book.type, `没有找到对应的小说批次任务数据,请检查bookId是否正确`, OtherData.DEFAULT, LoggerStatus.FAIL ) throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } let bookTask = bookTaskRes.data.bookTasks[0] // 获取对应小说批次任务的分镜信息 let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({ bookId: bookId, bookTaskId: bookTask.id }) if (bookTaskDetails.data.length <= 0) { await this.taskScheduler.AddLogToDB( bookId, book.type, `没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行`, bookTask.id, LoggerStatus.FAIL ) throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行') } // 开始添加任务 for (let i = 0; i < bookTaskDetails.data.length; i++) { const element = bookTaskDetails.data[i] let taskRes = await this.bookBackTaskListService.AddBookBackTask( bookId, BookBackTaskType.AUDIO, TaskExecuteType.AUTO, bookTask.id, element.id ) if (taskRes.code == 0) { throw new Error(taskRes.message) } // 添加日志 await this.taskScheduler.AddLogToDB( bookId, book.type, `添加音频 ${taskRes.data.name} 分离任务成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) } return successMessage(null, `添加所有音频分离任务成功`, 'BasicReverse_AddSplitAudioDataTask') } catch (error) { return errorMessage( '添加音频分离任务失败,错误信息如下: ' + error.message, 'BasicReverse_AddSplitAudioDataTask' ) } } /** * 执行分离音频任务 * @param {*} task 任务对象 * @returns */ async SplitAudioData(task) { try { // 执行分离音频任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID,没有直接报错 if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) { throw new Error('分镜任务,bookId, bookTaskId, bookTaskDetailId不能为空') } await this.InitService() let bookRes = this.bookService.GetBookDataById(task.bookId) if (bookRes.data == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data let bookTaskDetails = this.bookTaskDetailService.GetBookTaskDetailDataById( task.bookTaskDetailId ) if (bookTaskDetails.data == null) { throw new Error('没有找到对应的分镜数据') } let bookTaskDetail = bookTaskDetails.data let videoPath = bookTaskDetail.videoPath let audioPath = path.join(book.bookFolderPath, `data/audio/${bookTaskDetail.name}.wav`) await CheckFolderExistsOrCreate(path.dirname(audioPath)) // 开始分离音频 let audioRes = await this.ffmpegOptions.FfmpegExtractAudio(videoPath, audioPath) if (audioRes.code == 0) { let errorMessage = `分离音频失败,错误信息如下:${audioRes.message}` this.bookTaskService.UpdateBookTaskStatus( task.bookTaskId, BookTaskStatus.AUDIO_FAIL, errorMessage ) throw new Error(audioRes.message) } this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetail.id, { audioPath: path.relative(define.project_path, audioPath) }) // 推送成功消息 await this.taskScheduler.AddLogToDB( task.bookId, book.type, `${bookTaskDetail.name}分离音频成功,输出地址:${audioPath}`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) // 修改状态为分离音频成功 this.bookTaskService.UpdateBookTaskStatus(task.bookTaskId, BookTaskStatus.AUDIO_DONE) return successMessage( null, `${bookTaskDetail.name}分离音频成功,输出地址:${audioPath}`, 'BasicReverse_SplitAudioData' ) } catch (error) { let error_message = `分离音频失败,错误信息如下:${error.message}` await this.taskScheduler.AddLogToDB( task.bookId, task.type, error_message, OtherData.DEFAULT, LoggerStatus.FAIL ) return errorMessage(error_message, 'BasicReverse_SplitAudioData') } } //#endregion //#region 开始抽帧 // 添加抽帧任务 async AddGetFrameTask(bookId, bookTaskId = null) { try { // 开始添加任务 await this.InitService() let bookRes = this.bookService.GetBookDataById(bookId) if (bookRes.data == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data let bookTaskRes if (bookTaskId != null) { bookTaskRes = this.bookTaskService.GetBookTaskData({ id: bookTaskId }) } else { bookTaskRes = this.bookTaskService.GetBookTaskData({ bookId: bookId, name: 'output_00001' }) } if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } let bookTask = bookTaskRes.data.bookTasks[0] let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({ bookId: bookId, bookTaskId: bookTask.id }) if (bookTaskDetails.data.length <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行') } for (let i = 0; i < bookTaskDetails.data.length; i++) { const element = bookTaskDetails.data[i] let taskRes = await this.bookBackTaskListService.AddBookBackTask( bookId, BookBackTaskType.FRAME, TaskExecuteType.AUTO, bookTask.id, element.id ) if (taskRes.code == 0) { throw new Error(taskRes.message) } await this.taskScheduler.AddLogToDB( bookId, book.type, `添加 ${taskRes.data.name} 抽帧任务成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) } return successMessage(null, '添加所有抽帧任务成功', 'BasicReverse_AddGetFrameTask') } catch (error) { return errorMessage( '添加抽帧任务失败,错误信息如下: ' + error.message, 'BasicReverse_AddGetFrameTask' ) } } /** * 开始执行抽帧任务 * @param {*} task 执行的任务 */ async GetFrame(task) { try { // 抽帧任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID,没有直接报错 if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) { throw new Error('分镜任务,bookId, bookTaskId, bookTaskDetailId不能为空') } await this.InitService() let bookRes = this.bookService.GetBookDataById(task.bookId) if (bookRes.data == null) { throw new Error('没有找到对应的小说数据') } let book = bookRes.data let bookTaskDetailRes = this.bookTaskDetailService.GetBookTaskDetailDataById( task.bookTaskDetailId ) if (bookTaskDetailRes.data == null) { throw new Error('没有找到对应的分镜数据') } let bookTaskDetail = bookTaskDetailRes.data let videoPath = bookTaskDetail.videoPath let outputFramePath = path.join( book.bookFolderPath, `data/tmp/input/${bookTaskDetail.name}.png` ) let frameTime = (bookTaskDetail.endTime - bookTaskDetail.startTime) / 2 let res = await this.ffmpegOptions.FfmpegGetFrame(frameTime, videoPath, outputFramePath) if (res.code == 0) { let errorMessage = `抽帧失败,错误信息如下:${res.message}` this.bookTaskService.UpdateBookTaskStatus( task.bookTaskId, BookTaskStatus.FRAME_FAIL, errorMessage ) throw new Error(errorMessage) } // 抽帧成功,将抽帧的地址写入到数据库中 this.bookTaskDetailService.UpdateBookTaskDetail(task.bookTaskDetailId, { oldImage: path.relative(define.project_path, outputFramePath) }) // 推送成功消息 await this.taskScheduler.AddLogToDB( task.bookId, book.type, `${bookTaskDetail.name}抽帧成功,输出地址:${outputFramePath}`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) // 修改状态为抽帧成功 this.bookTaskService.UpdateBookTaskStatus(task.bookTaskId, BookTaskStatus.FRAME_DONE) return successMessage(null, '抽帧成功', 'BasicReverse_GetFrame') } catch (error) { let errorMessage = `抽帧失败,错误信息如下:${error.message}` await this.taskScheduler.AddLogToDB( task.bookId, task.type, errorMessage, OtherData.DEFAULT, LoggerStatus.FAIL ) return errorMessage('抽帧失败,错误信息如下: ' + error.message, 'BasicReverse_GetFrame') } } //#endregion //#region 提取字幕相关操作 /** * 添加提取字幕的任务 * @param {*} bookId 小说ID * @param {*} bookTaskId 小说任务ID * @returns */ async AddExtractSubtitlesDataTask(bookId, bookTaskId = null) { try { await this.InitService() let book = this.bookService.GetBookDataById(bookId) if (book == null) { throw new Error('没有找到对应的小说数据') } let bookTask if (bookTaskId != null) { bookTaskId = this.bookTaskService.GetBookTaskData({ id: bookTaskId }) } else { bookTask = this.bookTaskService.GetBookTaskData({ bookId: bookId, name: 'output_00001' }) } if (bookTask.data.bookTasks.length <= 0 || bookTask.data.total <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确') } bookTask = bookTask.data.bookTasks[0] // 获取对应小说批次任务的分镜信息 let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({ bookId: bookId, bookTaskId: bookTask.id }) if (bookTaskDetails.data.length <= 0) { throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行') } for (let i = 0; i < bookTaskDetails.data.length; i++) { const element = bookTaskDetails.data[i] let taskRes = await this.bookBackTaskListService.AddBookBackTask( bookId, book.type, TaskExecuteType.AUTO, bookTask.id, element.id ) if (taskRes.code == 0) { throw new Error(taskRes.message) } } await this.taskScheduler.AddLogToDB( bookId, book.type, `添加提取字幕任务成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage( null, '添加提取字幕任务成功 ', 'BasicReverse_AddExtractSubtitlesDataTask ' ) } catch (error) { return errorMessage( '添加提取字幕任务失败,错误信息如下: ' + error.message, 'BasicReverse_AddExtractSubtitlesDataTask' ) } } /** * 执行提取字幕任务 * @param {*} task * @returns */ async ExtractSubtitlesData(task) { try { // 执行提取字幕任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID,没有直接报错 if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) { throw new Error('分镜任务,bookId, bookTaskId, bookTaskDetailId不能为空') } await this.InitService() // 获取详细的小说分镜信息 let bookTaskDetailRes = this.bookTaskDetailService.GetBookTaskDetailDataById( task.bookTaskDetailId ) if (bookTaskDetailRes.data == null) { throw new Error('没有找到对应的分镜数据') } let bookTaskDetail = bookTaskDetailRes.data let txt = '' // 开始提取,调用本地的服务识别字幕 let isWisper = true // 判断是不是用本地的wisper服务 if (isWisper) { // 开始调用wisper // 使用异步的方法调用一个python程序,然后写入到指定的json文件中k let out_dir = path.dirname(bookTaskDetail.audioPath) let command = `"${path.join(define.scripts_path, 'Lai.exe')}" "-t" "${out_dir}" "${ bookTaskDetail.audioPath }" "${bookTaskDetail.name}"` const output = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }) // 有错误输出 if (output.stderr != '') { let error_msg = `提取字幕成功,但有警告提示:${output.stderr}` await this.taskScheduler.AddLogToDB( task.bookId, book.type, error_msg, OtherData.DEFAULT, LoggerStatus.FAIL ) } // 没有的话,去读取对应的字幕文件 let outTxtPath = path.join(out_dir, `${bookTaskDetail.name}.txt`) txt = await fspromises.readFile(outTxtPath, 'utf-8') } else { // 使用网络服务 } // 修改分镜数据的字幕 this.bookTaskDetailService.UpdateBookTaskDetail(task.bookTaskDetailId, { word: txt, afterGpt: txt }) // 提取字幕成功,推送日志 await this.taskScheduler.AddLogToDB( bookId, book.type, `${task.name} 提取字幕成功`, OtherData.DEFAULT, LoggerStatus.SUCCESS ) return successMessage(null, `${task.name} 提取字幕成功`, 'BasicReverse_ExtractSubtitlesData') } catch (error) { let errorMessage = `${task.name} 提取字幕失败,错误信息如下:${error.message}` await this.taskScheduler.AddLogToDB( bookId, book.type, errorMessage, OtherData.DEFAULT, LoggerStatus.FAIL ) return errorMessage(errorMessage, 'BasicReverse_ExtractSubtitlesData') } } //#endregion }