LaiTool V3.0.1-preview.7
This commit is contained in:
parent
07f99708da
commit
223678f761
2
.gitignore
vendored
2
.gitignore
vendored
@ -28,3 +28,5 @@ resources/config*
|
|||||||
*Lai_1.exe*
|
*Lai_1.exe*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.log*
|
*.log*
|
||||||
|
resources/scripts/db/book.realm.lock
|
||||||
|
resources/scripts/db/software.realm.lock
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.6",
|
"version": "3.0.1-preview.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.6",
|
"version": "3.0.1-preview.7",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alicloud/alimt20181012": "^1.2.0",
|
"@alicloud/alimt20181012": "^1.2.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.6",
|
"version": "3.0.1-preview.7",
|
||||||
"description": "An AI tool for image processing, video processing, and other functions.",
|
"description": "An AI tool for image processing, video processing, and other functions.",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "laitool.cn",
|
"author": "laitool.cn",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -236,3 +236,20 @@ export async function GetFileSize(filePath: string): Promise<number> {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件夹下的所有子文件夹的完整路径
|
||||||
|
* @param folderPath 文件夹的路径
|
||||||
|
* @returns 返回子文件夹的完整路径数组
|
||||||
|
*/
|
||||||
|
export async function GetSubdirectories(folderPath: string): Promise<string[]> {
|
||||||
|
try {
|
||||||
|
const files = await fs.promises.readdir(folderPath, { withFileTypes: true });
|
||||||
|
const directories = files
|
||||||
|
.filter((fileStat) => fileStat.isDirectory())
|
||||||
|
.map((fileStat) => path.join(folderPath, fileStat.name));
|
||||||
|
return directories;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export class SoftwareModel extends Realm.Object<SoftwareModel> {
|
|||||||
aiSetting: string | null // AI相关的配置的json字符串
|
aiSetting: string | null // AI相关的配置的json字符串
|
||||||
watermarkSetting: string | null // 水印相关的配置的json字符串
|
watermarkSetting: string | null // 水印相关的配置的json字符串
|
||||||
translationSetting: string | null // 翻译相关的配置的json字符串
|
translationSetting: string | null // 翻译相关的配置的json字符串
|
||||||
|
subtitleSetting: string | null // 字幕相关的配置的json字符串
|
||||||
|
|
||||||
static schema: ObjectSchema = {
|
static schema: ObjectSchema = {
|
||||||
name: 'Software',
|
name: 'Software',
|
||||||
@ -27,7 +28,8 @@ export class SoftwareModel extends Realm.Object<SoftwareModel> {
|
|||||||
writeSetting: 'string?',
|
writeSetting: 'string?',
|
||||||
aiSetting: 'string?',
|
aiSetting: 'string?',
|
||||||
watermarkSetting: 'string?',
|
watermarkSetting: 'string?',
|
||||||
translationSetting: 'string?'
|
translationSetting: 'string?',
|
||||||
|
subtitleSetting: "string?"
|
||||||
},
|
},
|
||||||
// 主键为_id
|
// 主键为_id
|
||||||
primaryKey: 'id'
|
primaryKey: 'id'
|
||||||
|
|||||||
@ -135,13 +135,13 @@ export class BookBackTaskListService extends BaseRealmService {
|
|||||||
* 新增一个小说相关的后台任务队列
|
* 新增一个小说相关的后台任务队列
|
||||||
* @param bookBackTask 要添加的小说数据
|
* @param bookBackTask 要添加的小说数据
|
||||||
*/
|
*/
|
||||||
async AddBookBackTask(
|
AddBookBackTask(
|
||||||
bookId: string,
|
bookId: string,
|
||||||
taskType: BookBackTaskType,
|
taskType: BookBackTaskType,
|
||||||
executeType = TaskExecuteType.AUTO,
|
executeType = TaskExecuteType.AUTO,
|
||||||
bookTaskId = null,
|
bookTaskId = null,
|
||||||
bookTaskDetailId = null
|
bookTaskDetailId = null
|
||||||
) {
|
): GeneralResponse.SuccessItem | GeneralResponse.ErrorItem {
|
||||||
try {
|
try {
|
||||||
// 通过bookid获取book信息
|
// 通过bookid获取book信息
|
||||||
let book = this.realm.objectForPrimaryKey('Book', bookId)
|
let book = this.realm.objectForPrimaryKey('Book', bookId)
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { isEmpty } from 'lodash'
|
|||||||
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
|
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
|
||||||
import { version } from '../../../../../package.json'
|
import { version } from '../../../../../package.json'
|
||||||
import { Book } from '../../../../model/book.js'
|
import { Book } from '../../../../model/book.js'
|
||||||
|
import { GeneralResponse } from '../../../../model/generalResponse.js'
|
||||||
|
|
||||||
export class BookService extends BaseRealmService {
|
export class BookService extends BaseRealmService {
|
||||||
static instance: BookService | null = null
|
static instance: BookService | null = null
|
||||||
@ -37,7 +38,7 @@ export class BookService extends BaseRealmService {
|
|||||||
* 获取小说信息,没有找到返回null
|
* 获取小说信息,没有找到返回null
|
||||||
* @param bookId
|
* @param bookId
|
||||||
*/
|
*/
|
||||||
GetBookDataById(bookId): Book.SelectBook | null {
|
GetBookDataById(bookId: string): Book.SelectBook | null {
|
||||||
try {
|
try {
|
||||||
if (isEmpty(bookId)) {
|
if (isEmpty(bookId)) {
|
||||||
throw new Error('获取小说信息失败,缺少小说ID')
|
throw new Error('获取小说信息失败,缺少小说ID')
|
||||||
@ -275,7 +276,7 @@ export class BookService extends BaseRealmService {
|
|||||||
* @param bookId 小说的ID
|
* @param bookId 小说的ID
|
||||||
* @param bookData 要修改的小说数据
|
* @param bookData 要修改的小说数据
|
||||||
*/
|
*/
|
||||||
async UpdateBookData(bookId: string, bookData: Book.SelectBook) {
|
UpdateBookData(bookId: string, bookData: Book.SelectBook): Book.SelectBook {
|
||||||
try {
|
try {
|
||||||
if (bookId == null) {
|
if (bookId == null) {
|
||||||
throw new Error('修改小说数据失败,缺少小说ID')
|
throw new Error('修改小说数据失败,缺少小说ID')
|
||||||
@ -303,8 +304,27 @@ export class BookService extends BaseRealmService {
|
|||||||
if (bookRes == null) {
|
if (bookRes == null) {
|
||||||
throw new Error('获取修改后的小说数据失败,小说ID对应的数据不存在')
|
throw new Error('获取修改后的小说数据失败,小说ID对应的数据不存在')
|
||||||
}
|
}
|
||||||
|
// return successMessage(bookRes, '修改小说数据成功', 'ReverseBook_UpdateBookData')
|
||||||
|
return bookRes;
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return successMessage(bookRes, '修改小说数据成功', 'ReverseBook_UpdateBookData')
|
/**
|
||||||
|
* 删除指定的小说任务
|
||||||
|
* @param bookId 需要删除的小说的ID
|
||||||
|
*/
|
||||||
|
DeleteBookData(bookId: string): void {
|
||||||
|
try {
|
||||||
|
this.transaction(() => {
|
||||||
|
let book = this.realm.objectForPrimaryKey('Book', bookId);
|
||||||
|
if (book == null) {
|
||||||
|
throw new Error('未找到对应的小说')
|
||||||
|
}
|
||||||
|
// 删除对应的小说
|
||||||
|
this.realm.delete(book)
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,7 +72,7 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
return JoinPath(define.project_path, subImage)
|
return JoinPath(define.project_path, subImage)
|
||||||
}),
|
}),
|
||||||
characterTags: item.characterTags ? item.characterTags.map((tag) => tag) : null,
|
characterTags: item.characterTags ? item.characterTags.map((tag) => tag) : null,
|
||||||
subValue: item.subValue,
|
subValue: isEmpty(item.subValue) ? null : JSON.parse(item.subValue),
|
||||||
reversePrompt: item.reversePrompt.map((reversePrompt) => {
|
reversePrompt: item.reversePrompt.map((reversePrompt) => {
|
||||||
return {
|
return {
|
||||||
...reversePrompt
|
...reversePrompt
|
||||||
@ -101,7 +101,6 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
if (bookTaskDetailId == null) {
|
if (bookTaskDetailId == null) {
|
||||||
throw new Error('获取小说任务详细信息失败,缺少ID')
|
throw new Error('获取小说任务详细信息失败,缺少ID')
|
||||||
}
|
}
|
||||||
|
|
||||||
let bookTaskDetails = this.GetBookTaskData({ id: bookTaskDetailId })
|
let bookTaskDetails = this.GetBookTaskData({ id: bookTaskDetailId })
|
||||||
if (bookTaskDetails.data.length <= 0) {
|
if (bookTaskDetails.data.length <= 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -165,7 +164,7 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
* @param bookTaskDetailId
|
* @param bookTaskDetailId
|
||||||
* @param updateData
|
* @param updateData
|
||||||
*/
|
*/
|
||||||
UpdateBookTaskDetail(bookTaskDetailId: string, updateData: Book.SelectBookTaskDetail) {
|
UpdateBookTaskDetail(bookTaskDetailId: string, updateData: Book.SelectBookTaskDetail): Book.SelectBookTaskDetail {
|
||||||
try {
|
try {
|
||||||
this.transaction(() => {
|
this.transaction(() => {
|
||||||
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
|
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
|
||||||
@ -178,18 +177,21 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
}
|
}
|
||||||
bookTaskDetail.updateTime = new Date()
|
bookTaskDetail.updateTime = new Date()
|
||||||
})
|
})
|
||||||
return successMessage(
|
let res = this.GetBookTaskDetailDataById(bookTaskDetailId)
|
||||||
null,
|
return res;
|
||||||
'修改小说任务详细信息成功',
|
|
||||||
'BookTaskDetailService_UpdateBookTaskDetail'
|
|
||||||
)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指定ID的反推提示词数据
|
||||||
|
* @param bookTaskDetailId
|
||||||
|
* @param mjMessage
|
||||||
|
*/
|
||||||
UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage): void {
|
UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage): void {
|
||||||
try {
|
try {
|
||||||
|
console.log('UpdateBookTaskDetailMjMessage', bookTaskDetailId, mjMessage)
|
||||||
this.transaction(() => {
|
this.transaction(() => {
|
||||||
let mjMessageRes = this.realm.objectForPrimaryKey('MJMessage', bookTaskDetailId)
|
let mjMessageRes = this.realm.objectForPrimaryKey('MJMessage', bookTaskDetailId)
|
||||||
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
|
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId)
|
||||||
@ -276,12 +278,20 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
* @param bookTaskDetailId 小说分镜的ID
|
* @param bookTaskDetailId 小说分镜的ID
|
||||||
*/
|
*/
|
||||||
DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): void {
|
DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): void {
|
||||||
let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId);
|
|
||||||
if (bookTaskDetail == null) {
|
|
||||||
throw new Error('删除小说任务详细信息的反推提示词失败,未找到对应的分镜信息')
|
|
||||||
}
|
|
||||||
this.transaction(() => {
|
this.transaction(() => {
|
||||||
this.realm.delete(bookTaskDetail.reversePrompt)
|
let bookTaskDetails = this.realm.objects<BookTaskDetailModel>('BookTaskDetail').filtered('id = $0', bookTaskDetailId);
|
||||||
|
if (bookTaskDetails.length <= 0) {
|
||||||
|
throw new Error('删除小说任务详细信息的反推提示词失败,未找到对应的分镜信息')
|
||||||
|
}
|
||||||
|
let bookTaskDetail = bookTaskDetails[0];
|
||||||
|
|
||||||
|
bookTaskDetail.gptPrompt = undefined;
|
||||||
|
// 删除所有的反推提示词
|
||||||
|
if (bookTaskDetail.reversePrompt) {
|
||||||
|
bookTaskDetail.reversePrompt.forEach(item => {
|
||||||
|
this.realm.delete(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,7 +132,7 @@ export class BookTaskService extends BaseRealmService {
|
|||||||
* @param bookTaskId 小说批次任务Id
|
* @param bookTaskId 小说批次任务Id
|
||||||
* @param status 目标状态
|
* @param status 目标状态
|
||||||
*/
|
*/
|
||||||
UpdateBookTaskStatus(bookTaskId: string, status: BookTaskStatus, errorMsg: string | null = null) {
|
UpdateBookTaskStatus(bookTaskId: string, status: BookTaskStatus, errorMsg: string | null = null): GeneralResponse.SuccessItem {
|
||||||
try {
|
try {
|
||||||
this.transaction(() => {
|
this.transaction(() => {
|
||||||
// 修改对应小说批次任务的状态
|
// 修改对应小说批次任务的状态
|
||||||
|
|||||||
@ -147,6 +147,14 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (oldRealm.schemaVersion < 20) {
|
||||||
|
newRealm.write(() => {
|
||||||
|
const newSoftwares = newRealm.objects('Software')
|
||||||
|
for (let software of newSoftwares) {
|
||||||
|
software.subtitleSetting = null // 字幕的默认设置
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseSoftWareService extends BaseService {
|
export class BaseSoftWareService extends BaseService {
|
||||||
@ -185,7 +193,7 @@ export class BaseSoftWareService extends BaseService {
|
|||||||
MjSettingModel
|
MjSettingModel
|
||||||
],
|
],
|
||||||
path: dbPath,
|
path: dbPath,
|
||||||
schemaVersion: 19, // 当前版本号
|
schemaVersion: 21, // 当前版本号
|
||||||
migration: migration
|
migration: migration
|
||||||
}
|
}
|
||||||
// 判断当前全局是不是又当前这个
|
// 判断当前全局是不是又当前这个
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import Realm, { UpdateMode } from 'realm'
|
import Realm, { UpdateMode } from 'realm'
|
||||||
import { successMessage } from '../../../../main/Public/generalTools'
|
import { successMessage } from '../../../../main/Public/generalTools'
|
||||||
import { BaseSoftWareService } from './softwareBasic.js'
|
import { BaseSoftWareService } from './softwareBasic.js'
|
||||||
|
import { GeneralResponse } from '../../../../model/generalResponse'
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
|
||||||
export class SoftwareService extends BaseSoftWareService {
|
export class SoftwareService extends BaseSoftWareService {
|
||||||
@ -24,7 +25,7 @@ export class SoftwareService extends BaseSoftWareService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改数据库中行中的某个属性数据
|
// 修改数据库中行中的某个属性数据
|
||||||
UpdateSoftware(software) {
|
UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): GeneralResponse.SuccessItem {
|
||||||
try {
|
try {
|
||||||
this.realm.write(() => {
|
this.realm.write(() => {
|
||||||
this.realm.create('Software', software, UpdateMode.Modified)
|
this.realm.create('Software', software, UpdateMode.Modified)
|
||||||
@ -41,7 +42,7 @@ export class SoftwareService extends BaseSoftWareService {
|
|||||||
* @param software 软件配置信息
|
* @param software 软件配置信息
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
AddSfotware(software) {
|
AddSfotware(software: SoftwareSettingModel.SoftwareSetting): GeneralResponse.SuccessItem {
|
||||||
try {
|
try {
|
||||||
software.id = uuidv4()
|
software.id = uuidv4()
|
||||||
this.realm.write(() => {
|
this.realm.write(() => {
|
||||||
@ -56,7 +57,7 @@ export class SoftwareService extends BaseSoftWareService {
|
|||||||
/**
|
/**
|
||||||
* 或软件基础配置信息
|
* 或软件基础配置信息
|
||||||
*/
|
*/
|
||||||
GetSoftwareData() {
|
GetSoftwareData(): GeneralResponse.SuccessItem {
|
||||||
try {
|
try {
|
||||||
let softwares = this.realm.objects('Software')
|
let softwares = this.realm.objects('Software')
|
||||||
|
|
||||||
|
|||||||
@ -123,7 +123,8 @@ export const DEFINE_STRING = {
|
|||||||
GPT: {
|
GPT: {
|
||||||
INIT_SERVER_GPT_OPTIONS: 'INIT_SERVER_GPT_OPTIONS',
|
INIT_SERVER_GPT_OPTIONS: 'INIT_SERVER_GPT_OPTIONS',
|
||||||
GET_AI_SETTING: 'GET_AI_SETTING',
|
GET_AI_SETTING: 'GET_AI_SETTING',
|
||||||
SAVE_AI_SETTING: 'SAVE_AI_SETTING'
|
SAVE_AI_SETTING: 'SAVE_AI_SETTING',
|
||||||
|
SYNC_GPT_KEY: "SYNC_GPT_KEY"
|
||||||
},
|
},
|
||||||
|
|
||||||
QUEUE_BATCH: {
|
QUEUE_BATCH: {
|
||||||
@ -153,7 +154,6 @@ export const DEFINE_STRING = {
|
|||||||
SD: {
|
SD: {
|
||||||
LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
|
LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
|
||||||
TXT2IMG: 'TXT2IMG',
|
TXT2IMG: 'TXT2IMG',
|
||||||
SD_MERGE_PROMPT: "SD_MERGE_PROMPT"
|
|
||||||
},
|
},
|
||||||
MJ: {
|
MJ: {
|
||||||
SAVE_WORD_SRT: 'SAVE_WORD_SRT',
|
SAVE_WORD_SRT: 'SAVE_WORD_SRT',
|
||||||
@ -175,7 +175,6 @@ export const DEFINE_STRING = {
|
|||||||
GET_MJ_IMAGE_ROBOT_MODEL: 'GET_MJ_IMAGE_ROBOT_MODEL',
|
GET_MJ_IMAGE_ROBOT_MODEL: 'GET_MJ_IMAGE_ROBOT_MODEL',
|
||||||
MACTH_USER_RETURN: 'MACTH_USER_RETURN',
|
MACTH_USER_RETURN: 'MACTH_USER_RETURN',
|
||||||
AUTO_MATCH_USER: 'AUTO_MATCH_USER',
|
AUTO_MATCH_USER: 'AUTO_MATCH_USER',
|
||||||
MJ_MERGE_PROMPT: "MJ_MERGE_PROMPT",
|
|
||||||
ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK: "ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK",
|
ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK: "ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK",
|
||||||
MJ_IMAGE: "MJ_IMAGE"
|
MJ_IMAGE: "MJ_IMAGE"
|
||||||
},
|
},
|
||||||
@ -208,6 +207,7 @@ export const DEFINE_STRING = {
|
|||||||
BOOK: {
|
BOOK: {
|
||||||
MAIN_DATA_RETURN: 'MAIN_DATA_RETURN', // 监听任务返回
|
MAIN_DATA_RETURN: 'MAIN_DATA_RETURN', // 监听任务返回
|
||||||
|
|
||||||
|
REPLACE_VIDEO_CURRENT_FRAME: 'REPLACE_VIDEO_CURRENT_FRAME',
|
||||||
GET_BOOK_TYPE: 'GET_BOOK_TYPE',
|
GET_BOOK_TYPE: 'GET_BOOK_TYPE',
|
||||||
ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK',
|
ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK',
|
||||||
GET_BOOK_DATA: 'GET_BOOK_DATA',
|
GET_BOOK_DATA: 'GET_BOOK_DATA',
|
||||||
@ -232,6 +232,10 @@ export const DEFINE_STRING = {
|
|||||||
HD_IMAGE: "HD_IMAGE",
|
HD_IMAGE: "HD_IMAGE",
|
||||||
USE_BOOK_VIDEO_DATA_TO_BOOK_TASK: "USE_BOOK_VIDEO_DATA_TO_BOOK_TASK",
|
USE_BOOK_VIDEO_DATA_TO_BOOK_TASK: "USE_BOOK_VIDEO_DATA_TO_BOOK_TASK",
|
||||||
ADD_JIANYING_DRAFT: "ADD_JIANYING_DRAFT",
|
ADD_JIANYING_DRAFT: "ADD_JIANYING_DRAFT",
|
||||||
|
EXPORT_COPYWRITING: "EXPORT_COPYWRITING",
|
||||||
|
MERGE_PROMPT: "MERGE_PROMPT",
|
||||||
|
RESET_BOOK_DATA: "RESET_BOOK_DATA",
|
||||||
|
DELETE_BOOK_DATA: "DELETE_BOOK_DATA",
|
||||||
|
|
||||||
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',
|
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',
|
||||||
|
|
||||||
@ -291,7 +295,10 @@ export const DEFINE_STRING = {
|
|||||||
WRITE: {
|
WRITE: {
|
||||||
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
|
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
|
||||||
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',
|
SAVE_WRITE_CONFIG: 'SAVE_WRITE_CONFIG',
|
||||||
ACTION_START: 'ACTION_START'
|
ACTION_START: 'ACTION_START',
|
||||||
|
GET_SUBTITLE_SETTING: "GET_SUBTITLE_SETTING",
|
||||||
|
RESET_SUBTITLE_SETTING: "RESET_SUBTITLE_SETTING",
|
||||||
|
SAVE_SUBTITLE_SETTING: "SAVE_SUBTITLE_SETTING",
|
||||||
},
|
},
|
||||||
DB: {
|
DB: {
|
||||||
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
|
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
|
||||||
|
|||||||
@ -207,10 +207,6 @@ export enum TagDefineType {
|
|||||||
SCENE_MAIN = "scene_main",
|
SCENE_MAIN = "scene_main",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MergeType {
|
|
||||||
BOOKTASK = 'bookTask', // 整个小说批次分镜合并
|
|
||||||
BOOKTASKDETAIL = 'bookTaskDetail' // 单个分镜合并
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum OperateBookType {
|
export enum OperateBookType {
|
||||||
BOOK = 'book', // 这个小说的所有批次
|
BOOK = 'book', // 这个小说的所有批次
|
||||||
@ -227,3 +223,14 @@ export enum CopyImageType {
|
|||||||
// 不包含图
|
// 不包含图
|
||||||
NONE = 'none'
|
NONE = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PromptMergeType {
|
||||||
|
// mj 合并
|
||||||
|
MJ_MERGE = 'mj_merge',
|
||||||
|
|
||||||
|
// SD 合并
|
||||||
|
SD_MERGE = 'sd_merge',
|
||||||
|
|
||||||
|
// D3 合并
|
||||||
|
D3_MERGE = 'd3_merge'
|
||||||
|
}
|
||||||
|
|||||||
@ -60,7 +60,8 @@ export enum ResponseMessageType {
|
|||||||
GET_TEXT = 'getText', // 获取文案
|
GET_TEXT = 'getText', // 获取文案
|
||||||
REMOVE_WATERMARK = "REMOVE_WATERMARK",// 删除水印
|
REMOVE_WATERMARK = "REMOVE_WATERMARK",// 删除水印
|
||||||
MJ_REVERSE = 'MJ_REVERSE',// MJ反推,返回反推结果
|
MJ_REVERSE = 'MJ_REVERSE',// MJ反推,返回反推结果
|
||||||
PROMPT_TRANSLATE = 'PROMPT_TRANSLATE',// 提示词翻译
|
REVERSE_PROMPT_TRANSLATE = 'REVERSE_PROMPT_TRANSLATE',// 反推提示词翻译
|
||||||
|
GPT_PROMPT_TRANSLATE = 'GPT_PROMPT_TRANSLATE', // GPT提示词翻译
|
||||||
MJ_IMAGE = 'MJ_IMAGE',// MJ 生成图片
|
MJ_IMAGE = 'MJ_IMAGE',// MJ 生成图片
|
||||||
HD_IMAGE = 'HD_IMAGE',// HD 生成图片
|
HD_IMAGE = 'HD_IMAGE',// HD 生成图片
|
||||||
}
|
}
|
||||||
@ -72,4 +73,11 @@ export enum LaiAPIType {
|
|||||||
HK_PROXY = "hk-proxy",
|
HK_PROXY = "hk-proxy",
|
||||||
// 备用站点
|
// 备用站点
|
||||||
BAK_MAIN = 'bak-main'
|
BAK_MAIN = 'bak-main'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步GPTkey的分类
|
||||||
|
export enum SyncGptKeyType {
|
||||||
|
// 字幕设置
|
||||||
|
SUBTITLE_SETTING = 'subtitle_setting',
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2,7 +2,6 @@
|
|||||||
export enum TranslateType {
|
export enum TranslateType {
|
||||||
// 反推提示词翻译
|
// 反推提示词翻译
|
||||||
REVERSE_PROMPT_TRANSLATE = 'reverse_prompt_translate',
|
REVERSE_PROMPT_TRANSLATE = 'reverse_prompt_translate',
|
||||||
|
|
||||||
// GPT提示词翻译
|
// GPT提示词翻译
|
||||||
GPT_PROMPT_TRANSLATE = 'gpt_prompt_translate',
|
GPT_PROMPT_TRANSLATE = 'gpt_prompt_translate',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,4 +27,14 @@ export enum WaterMarkResponseDateType {
|
|||||||
export enum RemoveWatermarkType {
|
export enum RemoveWatermarkType {
|
||||||
LOCAL_LAMA = 'local_lama',
|
LOCAL_LAMA = 'local_lama',
|
||||||
IOPAINT = 'iopaint'
|
IOPAINT = 'iopaint'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字幕的方法类型
|
||||||
|
export enum GetSubtitleType {
|
||||||
|
// 本地OCR
|
||||||
|
LOCAL_OCR = 'local_ocr',
|
||||||
|
// 本地Whisper
|
||||||
|
LOCAL_WHISPER = 'local_whisper',
|
||||||
|
// LAI WHISPER
|
||||||
|
LAI_WHISPER = 'lai_whisper',
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@ import { ipcMain } from 'electron'
|
|||||||
import { DEFINE_STRING } from '../../define/define_string'
|
import { DEFINE_STRING } from '../../define/define_string'
|
||||||
import { ReverseBook } from '../Service/Book/ReverseBook'
|
import { ReverseBook } from '../Service/Book/ReverseBook'
|
||||||
import { BasicReverse } from '../Service/Book/basicReverse'
|
import { BasicReverse } from '../Service/Book/basicReverse'
|
||||||
import { Subtitle } from '../Service/subtitle'
|
import { Subtitle } from '../Service/Subtitle/subtitle'
|
||||||
import { BookBasic } from '../Service/Book/BooKBasic'
|
import { BookBasic } from '../Service/Book/BooKBasic'
|
||||||
import { MJOpt } from '../Service/MJ/mj'
|
import { MJOpt } from '../Service/MJ/mj'
|
||||||
import { BookImage } from '../Service/Book/bookImage'
|
import { BookImage } from '../Service/Book/bookImage'
|
||||||
@ -10,6 +10,8 @@ import { ImageStyle } from '../Service/Book/imageStyle'
|
|||||||
import { BookTask } from '../Service/Book/bookTask'
|
import { BookTask } from '../Service/Book/bookTask'
|
||||||
import { BookVideo } from '../Service/Book/bookVideo'
|
import { BookVideo } from '../Service/Book/bookVideo'
|
||||||
import { Watermark } from '../Service/watermark'
|
import { Watermark } from '../Service/watermark'
|
||||||
|
import { SubtitleService } from '../Service/Subtitle/subtitleService'
|
||||||
|
import { BookFrame } from '../Service/Book/bookFrame'
|
||||||
let reverseBook = new ReverseBook()
|
let reverseBook = new ReverseBook()
|
||||||
let basicReverse = new BasicReverse()
|
let basicReverse = new BasicReverse()
|
||||||
let subtitle = new Subtitle()
|
let subtitle = new Subtitle()
|
||||||
@ -20,14 +22,16 @@ let imageStyle = new ImageStyle()
|
|||||||
let bookTask = new BookTask()
|
let bookTask = new BookTask()
|
||||||
let bookVideo = new BookVideo()
|
let bookVideo = new BookVideo()
|
||||||
let watermark = new Watermark()
|
let watermark = new Watermark()
|
||||||
|
let subtitleService = new SubtitleService()
|
||||||
|
let bookFrame = new BookFrame()
|
||||||
|
|
||||||
export function BookIpc() {
|
export function BookIpc() {
|
||||||
// 获取样式图片的子列表
|
// 获取样式图片的子列表
|
||||||
ipcMain.handle(DEFINE_STRING.BOOK.GET_BOOK_TYPE, async (event) => reverseBook.GetBookType())
|
ipcMain.handle(DEFINE_STRING.BOOK.GET_BOOK_TYPE, async (event) => bookBasic.GetBookType())
|
||||||
|
|
||||||
// 新增或者是修改小说数据
|
// 新增或者是修改小说数据
|
||||||
ipcMain.handle(DEFINE_STRING.BOOK.ADD_OR_MODIFY_BOOK, async (event, book) =>
|
ipcMain.handle(DEFINE_STRING.BOOK.ADD_OR_MODIFY_BOOK, async (event, book) =>
|
||||||
reverseBook.AddOrModifyBook(book)
|
bookBasic.AddOrModifyBook(book)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 获取小说数据(通过传递的参数进行筛选)
|
// 获取小说数据(通过传递的参数进行筛选)
|
||||||
@ -83,8 +87,7 @@ export function BookIpc() {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 一键反推的单个任务
|
//#region 分镜相关
|
||||||
|
|
||||||
// 开始计算分镜
|
// 开始计算分镜
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.COMPUTE_STORYBOARD,
|
DEFINE_STRING.BOOK.COMPUTE_STORYBOARD,
|
||||||
@ -97,23 +100,46 @@ export function BookIpc() {
|
|||||||
async (event, bookId) => await reverseBook.Framing(bookId)
|
async (event, bookId) => await reverseBook.Framing(bookId)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 开始执行分镜任务
|
// 替换分镜视频的当前帧
|
||||||
|
ipcMain.handle(DEFINE_STRING.BOOK.REPLACE_VIDEO_CURRENT_FRAME, async (event, bookTaskDetailId, currentTime) =>
|
||||||
|
await bookFrame.ReplaceVideoCurrentFrame(bookTaskDetailId, currentTime)
|
||||||
|
)
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 提示词相关
|
||||||
|
|
||||||
|
// 合并提示词
|
||||||
|
ipcMain.handle(DEFINE_STRING.BOOK.MERGE_PROMPT, async (event, id, type, operateBookType) => await reverseBook.MergePrompt(id, type, operateBookType))
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 一键反推的单个任务
|
||||||
|
|
||||||
|
|
||||||
|
// 开始执行获取小说文案的方法
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
||||||
async (event, bookId, bookTaskId) => await reverseBook.GetCopywriting(bookId, bookTaskId)
|
async (event, bookId, bookTaskId, operateBookType) => await subtitleService.GetCopywriting(bookId, bookTaskId, operateBookType)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取小说的文案数据,然后保存到对应的文件中
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.BOOK.EXPORT_COPYWRITING,
|
||||||
|
async (event, bookTaskId) => await subtitleService.ExportCopywriting(bookTaskId)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 执行去除水印
|
// 执行去除水印
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.REMOVE_WATERMARK,
|
DEFINE_STRING.BOOK.REMOVE_WATERMARK,
|
||||||
async (event, id,operateBookType) => await watermark.RemoveWatermark(id,operateBookType)
|
async (event, id, operateBookType) => await watermark.RemoveWatermark(id, operateBookType)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 添加反推任务到任务列表
|
// 添加反推任务到任务列表
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT,
|
DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT,
|
||||||
async (event, bookTaskDetailIds, type) =>
|
async (event, bookTaskDetailIds, operateBookType, type) =>
|
||||||
await reverseBook.AddReversePromptTask(bookTaskDetailIds, type)
|
await reverseBook.AddReversePrompt(bookTaskDetailIds, operateBookType, type)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 将反推出来的提示词写入到GPT提示词里面
|
// 将反推出来的提示词写入到GPT提示词里面
|
||||||
@ -154,9 +180,19 @@ export function BookIpc() {
|
|||||||
// 一拆四,将一个任务拆分成四个任务,并且复制对应的图片
|
// 一拆四,将一个任务拆分成四个任务,并且复制对应的图片
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK,
|
DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK,
|
||||||
async (event, bookTaskDetailId) => await bookBasic.OneToFourBookTask(bookTaskDetailId)
|
async (event, bookTaskDetailId) => await bookTask.OneToFourBookTask(bookTaskDetailId)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//#region 小说相关
|
||||||
|
|
||||||
|
// 重置小说数据
|
||||||
|
ipcMain.handle(DEFINE_STRING.BOOK.RESET_BOOK_DATA, async (event, bookId) => await bookBasic.ResetBookData(bookId))
|
||||||
|
|
||||||
|
// 删除小说数据
|
||||||
|
ipcMain.handle(DEFINE_STRING.BOOK.DELETE_BOOK_DATA, async (event, bookId) => await bookBasic.DeleteBookData(bookId))
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 小说批次任务相关
|
//#region 小说批次任务相关
|
||||||
|
|
||||||
// 重置小说批次数据
|
// 重置小说批次数据
|
||||||
@ -83,6 +83,12 @@ function GptIpc() {
|
|||||||
DEFINE_STRING.GPT.SAVE_AI_SETTING,
|
DEFINE_STRING.GPT.SAVE_AI_SETTING,
|
||||||
async (event, value) => await gptSetting.SaveAISetting(value)
|
async (event, value) => await gptSetting.SaveAISetting(value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 同步GPT Key 到指定的设置
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.GPT.SYNC_GPT_KEY,
|
||||||
|
async (event, syncType) => await gptSetting.SyncGptKey(syncType)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { GptIpc }
|
export { GptIpc }
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { MainIpc } from './mainIpc.js'
|
|||||||
import { GlobalIpc } from './globalIpc.js'
|
import { GlobalIpc } from './globalIpc.js'
|
||||||
import { ImageIpc } from './imageIpc.js'
|
import { ImageIpc } from './imageIpc.js'
|
||||||
import { SystemIpc } from './systemIpc.js'
|
import { SystemIpc } from './systemIpc.js'
|
||||||
import { BookIpc } from './bookIpc.js'
|
import { BookIpc } from './bookIpc'
|
||||||
import { TTSIpc } from './ttsIpc.js'
|
import { TTSIpc } from './ttsIpc.js'
|
||||||
import { DBIpc } from './dbIpc'
|
import { DBIpc } from './dbIpc'
|
||||||
|
|
||||||
|
|||||||
@ -138,12 +138,6 @@ function MjIpc() {
|
|||||||
async (event, value) => await discordSimple.DiscordDeleteMessage(value)
|
async (event, value) => await discordSimple.DiscordDeleteMessage(value)
|
||||||
)
|
)
|
||||||
|
|
||||||
// MJ合并提示词命令
|
|
||||||
ipcMain.handle(
|
|
||||||
DEFINE_STRING.MJ.MJ_MERGE_PROMPT,
|
|
||||||
async (event, id, mergeType) => await mjOpt.MergePrompt(id, mergeType)
|
|
||||||
)
|
|
||||||
|
|
||||||
// MJ出单张图
|
// MJ出单张图
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK,
|
DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK,
|
||||||
|
|||||||
@ -29,11 +29,5 @@ function SdIpc() {
|
|||||||
|
|
||||||
// 文生图,单张
|
// 文生图,单张
|
||||||
ipcMain.handle(DEFINE_STRING.SD.TXT2IMG, async (event, value) => await sd.txt2img(value))
|
ipcMain.handle(DEFINE_STRING.SD.TXT2IMG, async (event, value) => await sd.txt2img(value))
|
||||||
|
|
||||||
// SD合并提示词
|
|
||||||
ipcMain.handle(
|
|
||||||
DEFINE_STRING.SD.SD_MERGE_PROMPT,
|
|
||||||
async (event, id, mergeType) => await sdOpt.MergePrompt(id, mergeType)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
export { SdIpc }
|
export { SdIpc }
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import { Writing } from '../Service/writing'
|
|||||||
let writing = new Writing(global)
|
let writing = new Writing(global)
|
||||||
import { WritingSetting } from '../setting/writeSetting'
|
import { WritingSetting } from '../setting/writeSetting'
|
||||||
let writingSetting = new WritingSetting()
|
let writingSetting = new WritingSetting()
|
||||||
|
import { SubtitleService } from '../Service/Subtitle/subtitleService'
|
||||||
|
let subtitleService = new SubtitleService()
|
||||||
|
|
||||||
function WritingIpc() {
|
function WritingIpc() {
|
||||||
// 监听分镜时间的保存
|
// 监听分镜时间的保存
|
||||||
@ -36,7 +38,7 @@ function WritingIpc() {
|
|||||||
async (event, value) => await writing.ImportSrtAndGetTime(value)
|
async (event, value) => await writing.ImportSrtAndGetTime(value)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 获取文案相关的配置(数据库)
|
// 获取文案格式化相关的配置(数据库)
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.WRITE.GET_WRITE_CONFIG,
|
DEFINE_STRING.WRITE.GET_WRITE_CONFIG,
|
||||||
async (event) => await writingSetting.GetWritingConfig()
|
async (event) => await writingSetting.GetWritingConfig()
|
||||||
@ -48,6 +50,23 @@ function WritingIpc() {
|
|||||||
async (event, value) => await writingSetting.SaveWriteConfig(value)
|
async (event, value) => await writingSetting.SaveWriteConfig(value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 获取提取文案相关的配置(数据库)
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.WRITE.GET_SUBTITLE_SETTING,
|
||||||
|
async (event) => await subtitleService.GetSubtitleSetting()
|
||||||
|
)
|
||||||
|
|
||||||
|
// 重置提取文案相关的配置(数据库)
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.WRITE.RESET_SUBTITLE_SETTING,
|
||||||
|
async (event) => await subtitleService.ResetSubtitleSetting()
|
||||||
|
)
|
||||||
|
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.WRITE.SAVE_SUBTITLE_SETTING,
|
||||||
|
async (event, subtitleSetting) => await subtitleService.SaveSubtitleSetting(subtitleSetting)
|
||||||
|
)
|
||||||
|
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.WRITE.ACTION_START,
|
DEFINE_STRING.WRITE.ACTION_START,
|
||||||
async (event, aiSetting, word) => await writing.ActionStart(aiSetting, word)
|
async (event, aiSetting, word) => await writing.ActionStart(aiSetting, word)
|
||||||
|
|||||||
@ -1,29 +1,19 @@
|
|||||||
import { BookType, OperateBookType, TagDefineType } from '../../../define/enum/bookEnum'
|
import { BookType, OperateBookType, TagDefineType } from '../../../define/enum/bookEnum'
|
||||||
import { errorMessage, successMessage } from '../../Public/generalTools'
|
import { errorMessage, successMessage } from '../../Public/generalTools'
|
||||||
import { BookService } from '../../../define/db/service/Book/bookService'
|
import { BookService } from '../../../define/db/service/Book/bookService'
|
||||||
import { BookTaskService } from '../../../define/db/service/Book/bookTaskService'
|
|
||||||
import { BookTaskDetailService } from '../../../define/db/service/Book/bookTaskDetailService'
|
|
||||||
import { CopyImageType } from '../../../define/enum/bookEnum'
|
|
||||||
const { v4: uuidv4 } = require('uuid')
|
|
||||||
import { define } from '../../../define/define'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../define/Tools/file'
|
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFolderAllFile, GetSubdirectories } from '../../../define/Tools/file'
|
||||||
import { Book } from '../../../model/book'
|
|
||||||
import { GeneralResponse } from '../../../model/generalResponse'
|
import { GeneralResponse } from '../../../model/generalResponse'
|
||||||
import { cloneDeep, isEmpty } from 'lodash'
|
import { BookServiceBasic } from '../ServiceBasic/bookServiceBasic'
|
||||||
|
import { BookTask } from './bookTask'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
export class BookBasic {
|
export class BookBasic {
|
||||||
constructor() { }
|
bookServiceBasic: BookServiceBasic
|
||||||
bookTaskService: BookTaskService
|
bookTask: BookTask
|
||||||
bookTaskDetailService: BookTaskDetailService
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
async InitService() {
|
this.bookTask = new BookTask()
|
||||||
if (!this.bookTaskService) {
|
|
||||||
this.bookTaskService = await BookTaskService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.bookTaskDetailService) {
|
|
||||||
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 小说相关操作
|
//#region 小说相关操作
|
||||||
@ -73,209 +63,112 @@ export class BookBasic {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 小说批次任务相关操作
|
//#region 小说相关操作
|
||||||
|
|
||||||
|
/**
|
||||||
async OneToFourBookTask(bookTaskId: string) {
|
* 重置小说数据
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async ResetBookData(bookId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
console.log(bookTaskId)
|
let book = await this.bookServiceBasic.GetBookDataById(bookId)
|
||||||
await this.InitService();
|
// 获取所有的小说批次
|
||||||
let copyCount = 100
|
let bookTasks = (await this.bookServiceBasic.GetBookTaskData({
|
||||||
let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId)
|
bookId: bookId
|
||||||
if (bookTask == null) {
|
})).bookTasks;
|
||||||
throw new Error("没有找到对应的数小说任务,请检查数据")
|
// 重置批次任务
|
||||||
}
|
for (let i = 0; i < bookTasks.length; i++) {
|
||||||
// 获取所有的出图中最少的
|
const element = bookTasks[i];
|
||||||
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
|
// 第一个重置,后面的删除
|
||||||
bookTaskId: bookTaskId
|
if (i == 0) {
|
||||||
}).data as Book.SelectBookTaskDetail[]
|
let resetBookTaskData = await this.bookTask.ReSetBookTask(element.id);
|
||||||
if (bookTaskDetail == null || bookTaskDetail.length <= 0) {
|
if (resetBookTaskData.code == 0) {
|
||||||
throw new Error("没有对应的小说分镜任务,请先添加分镜任务")
|
throw new Error(resetBookTaskData.message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let deleteBookTaskData = await this.bookTask.DeleteBookTask(element.id);
|
||||||
|
if (deleteBookTaskData.code == 0) {
|
||||||
|
throw new Error(deleteBookTaskData.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < bookTaskDetail.length; i++) {
|
// 开始重置小说数据
|
||||||
const element = bookTaskDetail[i];
|
await this.bookServiceBasic.UpdateBookData(bookId, {
|
||||||
if (isEmpty(element.subImagePath)) {
|
srtPath: undefined,
|
||||||
throw new Error("检测到图片没有出完,请先检查出图")
|
audioPath: undefined,
|
||||||
}
|
subtitlePosition: undefined,
|
||||||
if (element.subImagePath == null || element.subImagePath.length <= 0) {
|
imageStyle: undefined,
|
||||||
throw new Error("检测到图片没有出完,请先检查出图")
|
autoAnalyzeCharacter: undefined,
|
||||||
}
|
customizeImageStyle: undefined,
|
||||||
if (element.subImagePath.length < copyCount) {
|
videoConfig: undefined,
|
||||||
copyCount = element.subImagePath.length
|
prefixPrompt: undefined,
|
||||||
}
|
suffixPrompt: undefined,
|
||||||
|
draftSrtStyle: undefined,
|
||||||
|
backgroundMusic: undefined,
|
||||||
|
friendlyReminder: undefined,
|
||||||
|
watermarkPosition: undefined,
|
||||||
|
})
|
||||||
|
// 文件重置,获取data下面的所有的子文件夹,删除所有的文件夹
|
||||||
|
let dirs = await GetSubdirectories(path.join(book.bookFolderPath, 'data'))
|
||||||
|
for (let i = 0; i < dirs.length; i++) {
|
||||||
|
const element = dirs[i];
|
||||||
|
await DeleteFolderAllFile(element, true)
|
||||||
}
|
}
|
||||||
if (copyCount <= 0) {
|
let scriptPath = path.join(book.bookFolderPath, 'script')
|
||||||
throw new Error("批次设置错误,无法进行一拆四")
|
if (await CheckFileOrDirExist(scriptPath)) {
|
||||||
|
await DeleteFolderAllFile(scriptPath, true)
|
||||||
}
|
}
|
||||||
// 开始复制
|
// 删掉输入的备份文件和input文件
|
||||||
let res = await this.CopyNewBookTask(bookTask, bookTaskDetail, copyCount - 1, CopyImageType.ONE)
|
let bakPath = path.join(book.bookFolderPath, 'tmp/bak');
|
||||||
if (res.code == 0) {
|
if (await CheckFileOrDirExist(bakPath)) {
|
||||||
throw new Error(res.message)
|
await DeleteFolderAllFile(bakPath, true)
|
||||||
}
|
}
|
||||||
return successMessage(res.data, "一拆四成功", "BookBasic_OneToFourBookTask")
|
let inputPath = path.join(book.bookFolderPath, 'tmp/input');
|
||||||
|
if (await CheckFileOrDirExist(inputPath)) {
|
||||||
|
await DeleteFolderAllFile(inputPath, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置完毕,开始返回
|
||||||
|
return successMessage('重置小说数据成功', 'BookBasic_ResetBookData');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("一拆四失败,失败信息如下:" + error.message, "BookBasic_OneToFourBookTask")
|
return errorMessage('重置小说数据失败,失败信息如下:' + error.message, 'BookBasic_ResetBookData');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制一个小说批次任务,创建新的小说批次任务
|
* 删除指定小说数据
|
||||||
* @param oldBookTaskId
|
* @param bookId 要删除的小说ID
|
||||||
* @param copyCount 复制的数量
|
|
||||||
* @param isCopyImage 是否复制图片
|
|
||||||
*/
|
*/
|
||||||
async CopyNewBookTask(sourceBookTask: Book.SelectBookTask, sourceBookTaskDetail: Book.SelectBookTaskDetail[], copyCount: number, copyImageType: CopyImageType) {
|
async DeleteBookData(bookId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService();
|
let book = await this.bookServiceBasic.GetBookDataById(bookId);
|
||||||
let addBookTask = [] as Book.SelectBookTask[]
|
// 先将所有的数据重置
|
||||||
let addBookTaskDetail = [] as Book.SelectBookTaskDetail[]
|
let resetRes = await this.ResetBookData(bookId);
|
||||||
|
if (resetRes.code == 0) {
|
||||||
// 先处理文件夹的创建,包括小说任务的和小说任务分镜的
|
throw new Error(resetRes.message)
|
||||||
for (let i = 0; i < copyCount; i++) {
|
}
|
||||||
let maxNo = this.bookTaskService.realm
|
let bookTasks = (await this.bookServiceBasic.GetBookTaskData({
|
||||||
.objects('BookTask')
|
bookId: bookId
|
||||||
.filtered('bookId = $0', sourceBookTask.bookId)
|
})).bookTasks;
|
||||||
.max('no')
|
// 删除遗留重置的小说批次任务
|
||||||
let no = maxNo == null ? 1 : Number(maxNo) + 1 + i
|
for (let i = 0; i < bookTasks.length; i++) {
|
||||||
let name = 'output_0000' + no
|
const element = bookTasks[i];
|
||||||
let imageFolder = path.join(define.project_path, `${sourceBookTask.bookId}/tmp/${name}`)
|
await this.bookServiceBasic.DeleteBookTaskData(element.id);
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据处理完毕,开始新增数据
|
// 开始删除数据
|
||||||
// 将所有的复制才做,全部放在一个事务中
|
await this.bookServiceBasic.DeleteBookData(bookId);
|
||||||
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")
|
// 开始删除文件
|
||||||
|
let bookPath = book.bookFolderPath;
|
||||||
|
if (await CheckFileOrDirExist(bookPath)) {
|
||||||
|
await DeleteFolderAllFile(bookPath, true)
|
||||||
|
}
|
||||||
|
return successMessage(null, '删除小说数据成功', 'BookBasic_DeleteBookData');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
return errorMessage('删除小说数据失败,失败信息如下:' + error.message, 'BookBasic_DeleteBookData');
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,65 +12,36 @@ import { TaskScheduler } from "../../Service/taskScheduler"
|
|||||||
import { Book } from '../../../model/book'
|
import { Book } from '../../../model/book'
|
||||||
import { LoggerStatus, OtherData, ResponseMessageType } from '../../../define/enum/softwareEnum'
|
import { LoggerStatus, OtherData, ResponseMessageType } from '../../../define/enum/softwareEnum'
|
||||||
import { GeneralResponse } from '../../../model/generalResponse'
|
import { GeneralResponse } from '../../../model/generalResponse'
|
||||||
import { cloneDeep, isEmpty } from 'lodash'
|
import { Subtitle } from '../Subtitle/subtitle'
|
||||||
import { Subtitle } from '../../Service/subtitle'
|
|
||||||
import { Watermark } from '../watermark'
|
import { Watermark } from '../watermark'
|
||||||
import { SubtitleSavePositionType } from '../../../define/enum/waterMarkAndSubtitle'
|
import { BookBackTaskType, BookType, OperateBookType, PromptMergeType, TagDefineType, TaskExecuteType } from '../../../define/enum/bookEnum'
|
||||||
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, CopyFileOrFolder, GetFilesWithExtensions } from '../../../define/Tools/file'
|
|
||||||
import { ValidateJson } from '../../../define/Tools/validate'
|
|
||||||
import { GetImageBase64, ProcessImage } from '../../../define/Tools/image'
|
|
||||||
import { BookBackTaskType, BookType, TagDefineType, TaskExecuteType } from '../../../define/enum/bookEnum'
|
|
||||||
import { BookBackTaskListService } from '../../../define/db/service/Book/bookBackTaskListService'
|
|
||||||
import { MJOpt } from '../MJ/mj'
|
import { MJOpt } from '../MJ/mj'
|
||||||
import { TagDefine } from '../../../define/tagDefine'
|
import { TagDefine } from '../../../define/tagDefine'
|
||||||
import { ImageStyleDefine } from '../../../define/iamgeStyleDefine'
|
import { BookServiceBasic } from '../ServiceBasic/bookServiceBasic'
|
||||||
|
import { SDOpt } from '../SD/sd'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一键反推的相关操作
|
* 一键反推的相关操作
|
||||||
*/
|
*/
|
||||||
export class ReverseBook extends BookBasic {
|
export class ReverseBook {
|
||||||
basicReverse: BasicReverse
|
basicReverse: BasicReverse
|
||||||
bookTaskService: BookTaskService
|
|
||||||
taskScheduler: TaskScheduler
|
taskScheduler: TaskScheduler
|
||||||
bookService: BookService
|
|
||||||
bookTaskDetailService: BookTaskDetailService
|
|
||||||
bookBackTaskListService: BookBackTaskListService
|
|
||||||
mjOpt: MJOpt = new MJOpt()
|
mjOpt: MJOpt = new MJOpt()
|
||||||
|
sdOpt: SDOpt = new SDOpt()
|
||||||
tagDefine: TagDefine
|
tagDefine: TagDefine
|
||||||
subtitle: Subtitle
|
subtitle: Subtitle
|
||||||
watermark: Watermark
|
watermark: Watermark
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
|
||||||
this.basicReverse = new BasicReverse()
|
this.basicReverse = new BasicReverse()
|
||||||
this.tagDefine = new TagDefine()
|
this.tagDefine = new TagDefine()
|
||||||
|
this.subtitle = new Subtitle()
|
||||||
|
this.watermark = new Watermark()
|
||||||
|
this.taskScheduler = new TaskScheduler()
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitService() {
|
|
||||||
if (!this.bookTaskService) {
|
|
||||||
this.bookTaskService = await BookTaskService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.taskScheduler) {
|
|
||||||
this.taskScheduler = new TaskScheduler()
|
|
||||||
}
|
|
||||||
if (!this.bookService) {
|
|
||||||
this.bookService = await BookService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.bookTaskDetailService) {
|
|
||||||
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.subtitle) {
|
|
||||||
this.subtitle = new Subtitle()
|
|
||||||
}
|
|
||||||
if (!this.watermark) {
|
|
||||||
this.watermark = new Watermark()
|
|
||||||
}
|
|
||||||
if (!this.bookBackTaskListService) {
|
|
||||||
this.bookBackTaskListService = await BookBackTaskListService.getInstance()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主动返回前端的消息
|
// 主动返回前端的消息
|
||||||
sendReturnMessage(data: GeneralResponse.MessageResponse, message_name = DEFINE_STRING.BOOK.GET_COPYWRITING_RETURN) {
|
sendReturnMessage(data: GeneralResponse.MessageResponse, message_name = DEFINE_STRING.BOOK.GET_COPYWRITING_RETURN) {
|
||||||
global.newWindow[0].win.webContents.send(message_name, data)
|
global.newWindow[0].win.webContents.send(message_name, data)
|
||||||
@ -104,15 +75,9 @@ export class ReverseBook extends BookBasic {
|
|||||||
* 获取小说的任务列表
|
* 获取小说的任务列表
|
||||||
* @param {*} bookTaskCondition 查询任务列表的条件
|
* @param {*} bookTaskCondition 查询任务列表的条件
|
||||||
*/
|
*/
|
||||||
async GetBookTaskData(bookTaskCondition): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async GetBookTaskData(bookTaskCondition: Book.QueryBookTaskCondition): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
let res = await this.bookServiceBasic.GetBookTaskData(bookTaskCondition)
|
||||||
let _bookTaskService = await BookTaskService.getInstance()
|
|
||||||
let res = _bookTaskService.GetBookTaskData(bookTaskCondition)
|
|
||||||
if (res.code == 0) {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// //TODO 这个后面是不是将所有的数据都是用数据库
|
// //TODO 这个后面是不是将所有的数据都是用数据库
|
||||||
// // 这边加载自定义风格
|
// // 这边加载自定义风格
|
||||||
// let styleLists = await this.tagDefine.getTagDataByTypeAndProperty('dynamic', "style_tags");
|
// let styleLists = await this.tagDefine.getTagDataByTypeAndProperty('dynamic', "style_tags");
|
||||||
@ -142,10 +107,10 @@ export class ReverseBook extends BookBasic {
|
|||||||
// }
|
// }
|
||||||
// res.data.bookTasks[index].styleList = styleList;
|
// res.data.bookTasks[index].styleList = styleList;
|
||||||
// }
|
// }
|
||||||
return successMessage(res.data, '获取小说任务成功', 'ReverseBook_GetBookTaskData')
|
return successMessage(res, '获取小说任务成功', 'ReverseBook_GetBookTaskData')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(
|
return errorMessage(
|
||||||
'获取小说对应批次错误,错误信息入校:' + error.message,
|
'获取小说对应批次错误,错误信息入下:' + error.message,
|
||||||
'ReverseBook_GetBookTaskData'
|
'ReverseBook_GetBookTaskData'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -153,20 +118,15 @@ export class ReverseBook extends BookBasic {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取小说的所有的任务详情
|
* 获取小说的所有的任务详情
|
||||||
* @param bookTaskId
|
* @param bookTaskId 小说任务的ID
|
||||||
*/
|
*/
|
||||||
async GetBookTaskDetail(bookTaskId: string) {
|
async GetBookTaskDetail(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
let res = await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: bookTaskId })
|
||||||
let _bookTaskDetailService = await BookTaskDetailService.getInstance()
|
return successMessage(res, '获取小说任务详情成功', 'ReverseBook_GetBookTaskDetail')
|
||||||
let res = _bookTaskDetailService.GetBookTaskData({ bookTaskId: bookTaskId })
|
|
||||||
if (res.code == 0) {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(
|
return errorMessage(
|
||||||
'获取小说对应批次错误,错误信息入校:' + error.message,
|
'获取小说对应批次错误,错误信息入下:' + error.message,
|
||||||
'ReverseBook_GetBookTaskData'
|
'ReverseBook_GetBookTaskData'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -236,10 +196,7 @@ export class ReverseBook extends BookBasic {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetBookAndTask(bookId: string, bookTaskName: string) {
|
async GetBookAndTask(bookId: string, bookTaskName: string) {
|
||||||
let book = this.bookService.GetBookDataById(bookId)
|
let book = await this.bookServiceBasic.GetBookDataById(bookId)
|
||||||
if (book == null) {
|
|
||||||
throw new Error("查找小说数据失败");
|
|
||||||
}
|
|
||||||
// 获取小说对应的批次任务数据,默认初始化为第一个
|
// 获取小说对应的批次任务数据,默认初始化为第一个
|
||||||
let condition = {
|
let condition = {
|
||||||
bookId: bookId
|
bookId: bookId
|
||||||
@ -249,20 +206,14 @@ export class ReverseBook extends BookBasic {
|
|||||||
} else {
|
} else {
|
||||||
condition["id"] = bookTaskName
|
condition["id"] = bookTaskName
|
||||||
}
|
}
|
||||||
let bookTaskRes = await this.bookTaskService.GetBookTaskData(condition)
|
let bookTaskRes = await this.bookServiceBasic.GetBookTaskData(condition)
|
||||||
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
|
return { book: book as Book.SelectBook, bookTask: bookTaskRes.bookTasks[0] as Book.SelectBookTask }
|
||||||
let msg = "没有找到对应的小说批次任务数据"
|
|
||||||
this.taskScheduler.AddLogToDB(bookId, book.type, msg, OtherData.DEFAULT, LoggerStatus.FAIL)
|
|
||||||
throw new Error(msg)
|
|
||||||
}
|
|
||||||
return { book: book as Book.SelectBook, bookTask: bookTaskRes.data.bookTasks[0] as Book.SelectBookTask }
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 开始分镜任务
|
* 开始分镜任务
|
||||||
*/
|
*/
|
||||||
async ComputeStoryboard(bookId: string): Promise<any> {
|
async ComputeStoryboard(bookId: string): Promise<any> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
let { book, bookTask } = await this.GetBookAndTask(bookId, 'output_00001')
|
let { book, bookTask } = await this.GetBookAndTask(bookId, 'output_00001')
|
||||||
let res = await this.basicReverse.ComputeStoryboardFunc(bookId, bookTask.id);
|
let res = await this.basicReverse.ComputeStoryboardFunc(bookId, bookTask.id);
|
||||||
// 分镜成功直接返回
|
// 分镜成功直接返回
|
||||||
@ -279,15 +230,15 @@ export class ReverseBook extends BookBasic {
|
|||||||
*/
|
*/
|
||||||
async Framing(bookId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async Framing(bookId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
let { book, bookTask } = await this.GetBookAndTask(bookId, 'output_00001')
|
let { book, bookTask } = await this.GetBookAndTask(bookId, 'output_00001')
|
||||||
|
let bookTaskDetail = undefined as Book.SelectBookTaskDetail[]
|
||||||
// 获取所有的分镜数据
|
try {
|
||||||
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
|
// 获取所有的分镜数据
|
||||||
bookId: bookId,
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookTaskId: bookTask.id
|
bookId: bookId,
|
||||||
})
|
bookTaskId: bookTask.id
|
||||||
if (bookTaskDetail.data.length <= 0) {
|
})
|
||||||
|
} catch (error) {
|
||||||
// 传入的分镜数据为空,需要重新获取
|
// 传入的分镜数据为空,需要重新获取
|
||||||
await this.taskScheduler.AddLogToDB(
|
await this.taskScheduler.AddLogToDB(
|
||||||
bookId,
|
bookId,
|
||||||
@ -298,9 +249,7 @@ export class ReverseBook extends BookBasic {
|
|||||||
)
|
)
|
||||||
throw new Error("没有传入分镜数据,请先进行分镜计算");
|
throw new Error("没有传入分镜数据,请先进行分镜计算");
|
||||||
}
|
}
|
||||||
|
let bookTaskDetails = bookTaskDetail;
|
||||||
let bookTaskDetails = bookTaskDetail.data as Book.SelectBookTaskDetail[]
|
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < bookTaskDetails.length; i++) {
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
const item = bookTaskDetails[i];
|
const item = bookTaskDetails[i];
|
||||||
@ -314,12 +263,12 @@ export class ReverseBook extends BookBasic {
|
|||||||
LoggerStatus.SUCCESS
|
LoggerStatus.SUCCESS
|
||||||
)
|
)
|
||||||
|
|
||||||
bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookId: bookId,
|
bookId: bookId,
|
||||||
bookTaskId: bookTask.id
|
bookTaskId: bookTask.id
|
||||||
})
|
})
|
||||||
|
|
||||||
bookTaskDetails = bookTaskDetail.data as Book.SelectBookTaskDetail[]
|
bookTaskDetails = bookTaskDetail as Book.SelectBookTaskDetail[]
|
||||||
for (let i = 0; i < bookTaskDetails.length; i++) {
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
const item = bookTaskDetails[i];
|
const item = bookTaskDetails[i];
|
||||||
let res = await this.basicReverse.FrameFunc(book, item);
|
let res = await this.basicReverse.FrameFunc(book, item);
|
||||||
@ -331,96 +280,70 @@ export class ReverseBook extends BookBasic {
|
|||||||
return errorMessage("开始切割视频并抽帧失败,失败信息如下:" + error.message, 'ReverseBook_Framing')
|
return errorMessage("开始切割视频并抽帧失败,失败信息如下:" + error.message, 'ReverseBook_Framing')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 提起文案
|
|
||||||
*/
|
|
||||||
async GetCopywriting(bookId: string, bookTaskId: string = null): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
|
||||||
try {
|
|
||||||
await this.InitService()
|
|
||||||
let { book, bookTask } = await this.GetBookAndTask(bookId, bookTaskId ? bookTaskId : 'output_00001')
|
|
||||||
if (isEmpty(book.subtitlePosition)) {
|
|
||||||
throw new Error("请先设置小说的字幕位置")
|
|
||||||
}
|
|
||||||
// 获取所有的分镜数据
|
|
||||||
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
|
|
||||||
)
|
|
||||||
throw new Error("没有传入分镜数据,请先进行分镜计算");
|
|
||||||
}
|
|
||||||
|
|
||||||
let bookTaskDetails = bookTaskDetail.data as Book.SelectBookTaskDetail[]
|
|
||||||
for (let i = 0; i < bookTaskDetails.length; i++) {
|
|
||||||
const item = bookTaskDetails[i];
|
|
||||||
|
|
||||||
let res = await this.subtitle.GetVideoFrameText({
|
|
||||||
id: item.id,
|
|
||||||
videoPath: item.videoPath,
|
|
||||||
type: SubtitleSavePositionType.STORYBOARD_VIDEO,
|
|
||||||
subtitlePosition: book.subtitlePosition
|
|
||||||
})
|
|
||||||
if (res.code == 0) {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
// 修改数据
|
|
||||||
this.bookTaskDetailService.UpdateBookTaskDetail(item.id, {
|
|
||||||
word: res.data,
|
|
||||||
afterGpt: res.data
|
|
||||||
});
|
|
||||||
|
|
||||||
// let res = await this.basicReverse.GetCopywritingFunc(book, item);
|
|
||||||
// 将当前的数据实时返回,前端进行修改
|
|
||||||
this.sendReturnMessage({
|
|
||||||
code: 1,
|
|
||||||
id: item.id,
|
|
||||||
type: ResponseMessageType.GET_TEXT,
|
|
||||||
data: res.data // 返回识别到的文案
|
|
||||||
})
|
|
||||||
|
|
||||||
// 添加日志
|
|
||||||
await this.taskScheduler.AddLogToDB(
|
|
||||||
bookId,
|
|
||||||
book.type,
|
|
||||||
`${item.name} 识别文案成功`,
|
|
||||||
bookTask.id,
|
|
||||||
LoggerStatus.SUCCESS
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return successMessage(null, "识别是所有文案成功", "ReverseBook_GetCopywriting")
|
|
||||||
} catch (error) {
|
|
||||||
return errorMessage("获取分镜数据失败,失败信息如下:" + error.message, 'ReverseBook_GetCopywriting')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 反推相关任务
|
//#region 反推相关任务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有的反推任务的入口
|
||||||
|
* @param id 需要反推的ID,可以是小说任务ID,也可以是小说分镜ID
|
||||||
|
* @param operateBookType 操作的分类
|
||||||
|
* @param type 反推的类型
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async AddReversePrompt(id: string, operateBookType: OperateBookType, type: BookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let bookTaskDetailIds: string[] = []
|
||||||
|
let bookTaskDetails = [] as Book.SelectBookTaskDetail[]
|
||||||
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
|
bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: id
|
||||||
|
})
|
||||||
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id);
|
||||||
|
bookTaskDetails = [bookTaskDetail]
|
||||||
|
} else if (operateBookType == OperateBookType.UNDERBOOKTASK) {
|
||||||
|
// 下生图
|
||||||
|
let tempBooktaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id);
|
||||||
|
let tempBooktaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: tempBooktaskDetail.bookTaskId
|
||||||
|
});
|
||||||
|
for (let i = 0; i < tempBooktaskDetails.length; i++) {
|
||||||
|
const element = tempBooktaskDetails[i];
|
||||||
|
if (tempBooktaskDetail.no <= element.no) {
|
||||||
|
bookTaskDetails.push(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("未知的操作模式,请检查");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const element = bookTaskDetails[i];
|
||||||
|
bookTaskDetailIds.push(element.id)
|
||||||
|
}
|
||||||
|
if (bookTaskDetailIds.length <= 0) {
|
||||||
|
throw new Error("没有需要反推的数据,请检查")
|
||||||
|
}
|
||||||
|
await this.AddReversePromptTask(bookTaskDetailIds, type);
|
||||||
|
return successMessage(null, "添加反推任务成功", 'ReverseBook_AddReversePrompt')
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("添加反推任务失败,错误信息如下:" + error.message, "ReverseBook_AddReversePrompt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加单句生图任务
|
* 添加单句生图任务
|
||||||
* @param bookTaskDetailId 小说单个分镜的ID
|
* @param bookTaskDetailId 小说单个分镜的ID
|
||||||
* @param type 反推的类型
|
* @param type 反推的类型
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async AddReversePromptTask(bookTaskDetailIds: string[], type: BookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async AddReversePromptTask(bookTaskDetailIds: string[], type: BookType): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
for (let index = 0; index < bookTaskDetailIds.length; index++) {
|
for (let index = 0; index < bookTaskDetailIds.length; index++) {
|
||||||
const bookTaskDetailId = bookTaskDetailIds[index];
|
const bookTaskDetailId = bookTaskDetailIds[index];
|
||||||
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(bookTaskDetailId)
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskDetailId)
|
||||||
if (bookTaskDetail == null) {
|
let book = await this.bookServiceBasic.GetBookDataById(bookTaskDetail.bookId)
|
||||||
throw new Error("没有找到对应的分镜数据")
|
|
||||||
}
|
|
||||||
let book = this.bookService.GetBookDataById(bookTaskDetail.bookId)
|
|
||||||
// 是不是又额外的类型,没有的话试用小说的类型
|
// 是不是又额外的类型,没有的话试用小说的类型
|
||||||
let task_type = undefined as BookBackTaskType
|
let task_type = undefined as BookBackTaskType
|
||||||
if (!type) {
|
if (!type) {
|
||||||
@ -436,17 +359,14 @@ export class ReverseBook extends BookBasic {
|
|||||||
default:
|
default:
|
||||||
throw new Error("暂不支持的推理类型")
|
throw new Error("暂不支持的推理类型")
|
||||||
}
|
}
|
||||||
let taskRes = await this.bookBackTaskListService.AddBookBackTask(book.id, task_type, TaskExecuteType.AUTO, bookTaskDetail.bookTaskId, bookTaskDetail.id
|
// 添加后台任务
|
||||||
|
await this.bookServiceBasic.AddBookBackTask(book.id, task_type, TaskExecuteType.AUTO, bookTaskDetail.bookTaskId, bookTaskDetail.id
|
||||||
);
|
);
|
||||||
if (taskRes.code == 0) {
|
|
||||||
throw new Error(taskRes.message)
|
|
||||||
}
|
|
||||||
// 添加返回日志
|
// 添加返回日志
|
||||||
await this.taskScheduler.AddLogToDB(book.id, book.type, `添加 ${task_type} 反推任务成功`, bookTaskDetail.bookTaskId, LoggerStatus.SUCCESS)
|
await this.taskScheduler.AddLogToDB(book.id, book.type, `添加 ${task_type} 反推任务成功`, bookTaskDetail.bookTaskId, LoggerStatus.SUCCESS)
|
||||||
}
|
}
|
||||||
return successMessage(null, "添加反推任务成功", "ReverseBook_AddReversePromptTask")
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("添加单个反推失败,错误信息如下:" + error.message, "ReverseBook_SingleReversePrompt")
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,14 +401,12 @@ export class ReverseBook extends BookBasic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定的提示词数据
|
* 删除指定的提示词数据
|
||||||
* @param bookTaskDetailIds 要删除的提示词ID
|
* @param bookTaskDetailIds 要删除的提示词ID
|
||||||
*/
|
*/
|
||||||
async RemoveReverseData(bookTaskDetailIds: string[]) {
|
async RemoveReverseData(bookTaskDetailIds: string[]) {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
// 开始删除
|
// 开始删除
|
||||||
if (bookTaskDetailIds.length <= 0) {
|
if (bookTaskDetailIds.length <= 0) {
|
||||||
throw new Error("没有传入要删除的数据")
|
throw new Error("没有传入要删除的数据")
|
||||||
@ -496,7 +414,7 @@ export class ReverseBook extends BookBasic {
|
|||||||
|
|
||||||
for (let i = 0; i < bookTaskDetailIds.length; i++) {
|
for (let i = 0; i < bookTaskDetailIds.length; i++) {
|
||||||
const element = bookTaskDetailIds[i];
|
const element = bookTaskDetailIds[i];
|
||||||
this.bookTaskDetailService.DeleteBookTaskDetailReversePromptById(element)
|
await this.bookServiceBasic.DeleteBookTaskDetailReversePromptById(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全部删除完毕
|
// 全部删除完毕
|
||||||
@ -505,6 +423,30 @@ export class ReverseBook extends BookBasic {
|
|||||||
return errorMessage("删除反推数据失败,错误信息如下:" + error.message, "ReverseBook_RemoveReverseData")
|
return errorMessage("删除反推数据失败,错误信息如下:" + error.message, "ReverseBook_RemoveReverseData")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 提示词相关操作
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并提示词的入口函数
|
||||||
|
* @param id 合并的ID,可以是小说任务ID,也可以是小说分镜ID
|
||||||
|
* @param operateBookType 操作的类型
|
||||||
|
* @param type 合并的类型(MJ。SD 。D3)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async MergePrompt(id: string, type: PromptMergeType, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
if (type == PromptMergeType.MJ_MERGE) {
|
||||||
|
return await this.mjOpt.MergePrompt(id, operateBookType);
|
||||||
|
} else if (type == PromptMergeType.SD_MERGE) {
|
||||||
|
return await this.sdOpt.MergePrompt(id, operateBookType)
|
||||||
|
} else {
|
||||||
|
throw new Error("未知的合并模式,请检查")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("合并提示词失败,错误信息如下:" + error.message, "ReverseBook_MergePrompt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
59
src/main/Service/Book/bookFrame.ts
Normal file
59
src/main/Service/Book/bookFrame.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import { GeneralResponse } from "../../../model/generalResponse";
|
||||||
|
import { errorMessage, successMessage } from "../../Public/generalTools";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import path from 'path';
|
||||||
|
import { FfmpegOptions } from "../ffmpegOptions";
|
||||||
|
import { CheckFileOrDirExist, CopyFileOrFolder, DeleteFolderAllFile } from "../../../define/Tools/file";
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
export class BookFrame {
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
ffmpegOptions: FfmpegOptions
|
||||||
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
|
this.ffmpegOptions = new FfmpegOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换指定分镜的视频当前帧
|
||||||
|
* @param bookTaskDetailId 指定的小说分镜ID
|
||||||
|
* @param current 要替换的帧
|
||||||
|
*/
|
||||||
|
async ReplaceVideoCurrentFrame(bookTaskDetailId: string, current: number): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskDetailId);
|
||||||
|
let videoPath = bookTaskDetail.videoPath;
|
||||||
|
if (isEmpty(videoPath)) {
|
||||||
|
throw new Error('未找到对应的视频路径,请检查');
|
||||||
|
}
|
||||||
|
let oldImagePath = bookTaskDetail.oldImage;
|
||||||
|
let tempOldImagePath = path.join(path.dirname(oldImagePath), `temp_${bookTaskDetail.name}.png`);
|
||||||
|
// 删除之前的图片
|
||||||
|
if (await CheckFileOrDirExist(tempOldImagePath)) {
|
||||||
|
await fs.promises.unlink(tempOldImagePath);
|
||||||
|
}
|
||||||
|
// 开始裁剪
|
||||||
|
let res = await this.ffmpegOptions.FfmpegGetFrame(current, videoPath, tempOldImagePath);
|
||||||
|
if (res.code == 0) {
|
||||||
|
// 抽帧失败
|
||||||
|
global.logger.error('BookFrame_ReplaceVideoCurrentFrame', '抽取视频指定帧失败,请检查');
|
||||||
|
throw new Error('抽取视频指定帧失败,请检查');
|
||||||
|
}
|
||||||
|
// 成功。开始替换
|
||||||
|
let fileExist = await CheckFileOrDirExist(tempOldImagePath);
|
||||||
|
if (!fileExist) {
|
||||||
|
throw new Error('抽帧出来的图片不存在,请检查');
|
||||||
|
}
|
||||||
|
await fs.promises.unlink(oldImagePath);
|
||||||
|
// 重命名
|
||||||
|
await CopyFileOrFolder(tempOldImagePath, oldImagePath);
|
||||||
|
await fs.promises.unlink(tempOldImagePath);
|
||||||
|
return successMessage(oldImagePath + '?t=' + new Date().getTime(), '视频指定的视频帧成功', 'BookFrame_ReplaceVideoCurrentFrame');
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage('替换指定分镜的视频当前帧失败,失败信息如下:' + error.toString(), 'BookFrame_ReplaceVideoCurrentFrame');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,10 +1,15 @@
|
|||||||
import { CheckFolderExistsOrCreate, DeleteFolderAllFile } from "../../../define/Tools/file";
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFolderAllFile } from "../../../define/Tools/file";
|
||||||
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
|
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
|
||||||
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
||||||
import { BookService } from "../../../define/db/service/Book/bookService";
|
import { BookService } from "../../../define/db/service/Book/bookService";
|
||||||
import { BookTaskStatus, OperateBookType } from "../../../define/enum/bookEnum";
|
import { BookTaskStatus, CopyImageType, OperateBookType } from "../../../define/enum/bookEnum";
|
||||||
import { errorMessage, successMessage } from "../../Public/generalTools";
|
import { errorMessage, successMessage } from "../../Public/generalTools";
|
||||||
import { Book } from "../../../model/book";
|
import { Book } from "../../../model/book";
|
||||||
|
import path from 'path'
|
||||||
|
import { cloneDeep, isEmpty } from "lodash";
|
||||||
|
import { define } from '../../../define/define'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { GeneralResponse } from "../../../model/generalResponse";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小说批次相关的操作
|
* 小说批次相关的操作
|
||||||
@ -33,7 +38,7 @@ export class BookTask {
|
|||||||
* 重置小说任务数据
|
* 重置小说任务数据
|
||||||
* @param bookTaskId 小说任务ID
|
* @param bookTaskId 小说任务ID
|
||||||
*/
|
*/
|
||||||
async ReSetBookTask(bookTaskId: string) {
|
async ReSetBookTask(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
console.log(bookTaskId)
|
console.log(bookTaskId)
|
||||||
await this.InitService()
|
await this.InitService()
|
||||||
@ -57,7 +62,7 @@ export class BookTask {
|
|||||||
* 删除对应的小说批次数据
|
* 删除对应的小说批次数据
|
||||||
* @param bookTaskId 小说批次ID
|
* @param bookTaskId 小说批次ID
|
||||||
*/
|
*/
|
||||||
async DeleteBookTask(bookTaskId: string) {
|
async DeleteBookTask(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId);
|
let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId);
|
||||||
@ -75,4 +80,212 @@ export class BookTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将小说批次任务出图进行一拆四
|
||||||
|
* @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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -10,14 +10,17 @@ import { CheckFolderExistsOrCreate } from "../../../define/Tools/file";
|
|||||||
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { ClipDraft } from '../../Public/clipDraft'
|
import { ClipDraft } from '../../Public/clipDraft'
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
|
||||||
export class BookVideo {
|
export class BookVideo {
|
||||||
bookService: BookService
|
bookService: BookService
|
||||||
bookTaskService: BookTaskService
|
bookTaskService: BookTaskService
|
||||||
setting: Setting
|
setting: Setting
|
||||||
bookTaskDetailService: BookTaskDetailService
|
bookTaskDetailService: BookTaskDetailService
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
constructor() {
|
constructor() {
|
||||||
this.setting = new Setting(global)
|
this.setting = new Setting(global)
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitService() {
|
async InitService() {
|
||||||
@ -71,17 +74,16 @@ export class BookVideo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将修改数据放在一个事务中
|
// 将修改数据放在一个事务中
|
||||||
this.bookService.transaction(() => {
|
for (let i = 0; i < bookTasks.length; i++) {
|
||||||
for (let i = 0; i < bookTasks.length; i++) {
|
const element = bookTasks[i];
|
||||||
const element = bookTasks[i];
|
this.bookServiceBasic.UpdetedBookTaskData(element.id, {
|
||||||
let modifyBookTask = this.bookService.realm.objectForPrimaryKey('BookTask', element.id);
|
backgroundMusic: book.backgroundMusic,
|
||||||
modifyBookTask.backgroundMusic = book.backgroundMusic;
|
friendlyReminder: book.friendlyReminder,
|
||||||
modifyBookTask.friendlyReminder = book.friendlyReminder;
|
draftSrtStyle: book.draftSrtStyle,
|
||||||
modifyBookTask.draftSrtStyle = book.draftSrtStyle;
|
srtPath: book.srtPath,
|
||||||
modifyBookTask.srtPath = book.srtPath;
|
audioPath: book.audioPath,
|
||||||
modifyBookTask.audioPath = book.audioPath;
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
return successMessage({
|
return successMessage({
|
||||||
backgroundMusic: book.backgroundMusic,
|
backgroundMusic: book.backgroundMusic,
|
||||||
friendlyReminder: book.friendlyReminder,
|
friendlyReminder: book.friendlyReminder,
|
||||||
|
|||||||
178
src/main/Service/GPT/gpt.ts
Normal file
178
src/main/Service/GPT/gpt.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import { gptDefine } from "../../../define/gptDefine";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一些GPT相关的服务都在这边
|
||||||
|
*/
|
||||||
|
export class GptService {
|
||||||
|
gptUrl: string = undefined
|
||||||
|
gptModel: string = undefined
|
||||||
|
gptApiKey: string = undefined
|
||||||
|
|
||||||
|
|
||||||
|
//#region GPT 设置
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取GPT的所有的服务商
|
||||||
|
* @param type 获取的类型,就是all
|
||||||
|
* @param callback 这个是个回调函数,干嘛的不知道
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private async GetGPTBusinessOption(type: string, callback: Function = null): Promise<any> {
|
||||||
|
let res = await gptDefine.getGptDataByTypeAndProperty(type, "gpt_options", []);
|
||||||
|
if (res.code == 0) {
|
||||||
|
throw new Error(res.message)
|
||||||
|
} else {
|
||||||
|
if (callback) {
|
||||||
|
callback(res.data)
|
||||||
|
}
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async RefreshGptSetting() {
|
||||||
|
let all_options = await this.GetGPTBusinessOption("all", (value) => value.gpt_url);
|
||||||
|
let index = all_options.findIndex(item => item.value == global.config.gpt_business && item.gpt_url)
|
||||||
|
if (index < 0) {
|
||||||
|
throw new Error("没有找到指定的GPT服务商的配置,请检查")
|
||||||
|
}
|
||||||
|
this.gptUrl = all_options[index].gpt_url;
|
||||||
|
this.gptApiKey = global.config.gpt_key;
|
||||||
|
this.gptModel = global.config.gpt_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化GPT的设置
|
||||||
|
*/
|
||||||
|
async InitGptSetting(refresh = false) {
|
||||||
|
if (refresh) {
|
||||||
|
await this.RefreshGptSetting()
|
||||||
|
} else {
|
||||||
|
// 判断是不是存在必要信息
|
||||||
|
if (isEmpty(this.gptUrl) || isEmpty(this.gptModel) || isEmpty(this.gptApiKey)) {
|
||||||
|
await this.RefreshGptSetting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 适配一些请求体中的参数
|
||||||
|
* @param data
|
||||||
|
* @param gpt_url
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
ModifyData(data: any, gpt_url: string = null) {
|
||||||
|
let res = data;
|
||||||
|
if (!gpt_url) {
|
||||||
|
gpt_url = this.gptUrl
|
||||||
|
}
|
||||||
|
if (gpt_url.includes("dashscope.aliyuncs.com")) {
|
||||||
|
res = {
|
||||||
|
"model": data.model,
|
||||||
|
"input": {
|
||||||
|
"messages": data.messages,
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"result_format": "message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 适配返回来的数据
|
||||||
|
* @param res 返回的数据
|
||||||
|
* @param gpt_url 请求的URL
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
GetResponseContent(res: any, gpt_url: string = null) {
|
||||||
|
let content = "";
|
||||||
|
if (!gpt_url) {
|
||||||
|
gpt_url = this.gptUrl
|
||||||
|
}
|
||||||
|
if (gpt_url.includes("dashscope.aliyuncs.com")) {
|
||||||
|
content = res.data.output.choices[0].message.content;
|
||||||
|
} else {
|
||||||
|
content = res.data.choices[0].message.content;
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GPT请求
|
||||||
|
* @param {*} message 请求的信息
|
||||||
|
* @param {*} gpt_url gpt的url,默认在global中取
|
||||||
|
* @param {*} gpt_key gpt的key,默认在global中取
|
||||||
|
* @param {*} gpt_model gpt的model,默认在global中取
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async FetchGpt(message: any, gpt_model: string = null, gpt_key: string = null, gpt_url: string = null): Promise<string> {
|
||||||
|
try {
|
||||||
|
await this.InitGptSetting();
|
||||||
|
let data = {
|
||||||
|
"model": gpt_model ? gpt_model : this.gptModel,
|
||||||
|
"messages": message
|
||||||
|
};
|
||||||
|
|
||||||
|
data = this.ModifyData(data, gpt_url);
|
||||||
|
let config = {
|
||||||
|
method: 'post',
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
url: gpt_url ? gpt_url : this.gptUrl,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${gpt_key ? gpt_key : this.gptApiKey}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = await axios.request(config);
|
||||||
|
let content = this.GetResponseContent(res, this.gptUrl);
|
||||||
|
return content;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region 繁体中文 -> 简体中文
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将繁体中文转换为简体中文
|
||||||
|
* @param traditionalText 繁体中文文本
|
||||||
|
* @param apiKey Lai API的 Key
|
||||||
|
* @param baseUrl 请求的baseurl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async ChineseTraditionalToSimplified(traditionalText: string, apiKey: string, baseUrl: string = null): Promise<string> {
|
||||||
|
try {
|
||||||
|
let message = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": '我想让你充当中文繁体转简体专家,用简体中文100%还原繁体中文,不要加其他的联想,只把原有的繁体中文转换为简体中文,请检查所有信息是否准确,并在回答时保持简活,不需要任何其他反馈。'
|
||||||
|
}, {
|
||||||
|
"role": "user",
|
||||||
|
"content": '上研究生後,發現導師竟然是曾經網戀的前男友。'
|
||||||
|
}, {
|
||||||
|
"role": "assistant",
|
||||||
|
"content": '上研究生后,发现导师竟然是曾经网恋的前男友。'
|
||||||
|
}, {
|
||||||
|
"role": "user",
|
||||||
|
"content": traditionalText
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
let baseSubUrl = baseUrl ? (baseUrl.endsWith('/') ? baseUrl + 'v1/chat/completions' : baseUrl + '/v1/chat/completions') : null;
|
||||||
|
let url = baseSubUrl ? baseSubUrl : "https://api.laitool.cc/v1/chat/completions"
|
||||||
|
// 开始请求,这个默认是使用的是LAI API的gpt-4o-mini
|
||||||
|
let content = await this.FetchGpt(message, 'gpt-4o-mini', apiKey, url)
|
||||||
|
return content
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ import { CheckFolderExistsOrCreate, CopyFileOrFolder, JoinPath } from "../../../
|
|||||||
import { define } from "../../../define/define"
|
import { define } from "../../../define/define"
|
||||||
import { GetImageBase64, ImageSplit } from "../../../define/Tools/image";
|
import { GetImageBase64, ImageSplit } from "../../../define/Tools/image";
|
||||||
import MJApi from "./mjApi"
|
import MJApi from "./mjApi"
|
||||||
import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, DialogType, MJAction, MergeType, OperateBookType, TaskExecuteType } from "../../../define/enum/bookEnum";
|
import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, DialogType, MJAction, OperateBookType, TaskExecuteType } from "../../../define/enum/bookEnum";
|
||||||
import { DEFINE_STRING } from "../../../define/define_string";
|
import { DEFINE_STRING } from "../../../define/define_string";
|
||||||
import { MJ } from "../../../model/mj";
|
import { MJ } from "../../../model/mj";
|
||||||
import { MJRespoonseType } from "../../../define/enum/mjEnum";
|
import { MJRespoonseType } from "../../../define/enum/mjEnum";
|
||||||
@ -21,6 +21,7 @@ import { TaskScheduler } from "../taskScheduler";
|
|||||||
import { BookService } from "../../../define/db/service/Book/bookService";
|
import { BookService } from "../../../define/db/service/Book/bookService";
|
||||||
import { Tools } from "../../../main/tools"
|
import { Tools } from "../../../main/tools"
|
||||||
import { MJSettingService } from "../../../define/db/service/SoftWare/mjSettingService";
|
import { MJSettingService } from "../../../define/db/service/SoftWare/mjSettingService";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
@ -39,10 +40,12 @@ export class MJOpt {
|
|||||||
bookService: BookService
|
bookService: BookService
|
||||||
tools: Tools;
|
tools: Tools;
|
||||||
mjSettingService: MJSettingService;
|
mjSettingService: MJSettingService;
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
constructor() {
|
constructor() {
|
||||||
this.imageStyle = new ImageStyle()
|
this.imageStyle = new ImageStyle()
|
||||||
this.taskScheduler = new TaskScheduler()
|
this.taskScheduler = new TaskScheduler()
|
||||||
this.tools = new Tools()
|
this.tools = new Tools()
|
||||||
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
}
|
}
|
||||||
async InitService() {
|
async InitService() {
|
||||||
if (!this.reverseBook) {
|
if (!this.reverseBook) {
|
||||||
@ -208,7 +211,8 @@ export class MJOpt {
|
|||||||
|
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.REVERSE_DONE,
|
status: BookTaskStatus.REVERSE_DONE,
|
||||||
reversePrompt: reversePrompt
|
reversePrompt: reversePrompt,
|
||||||
|
gptPrompt: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
task_res.prompt = JSON.stringify(reversePrompt);
|
task_res.prompt = JSON.stringify(reversePrompt);
|
||||||
@ -331,20 +335,35 @@ export class MJOpt {
|
|||||||
* @param id 合并的ID
|
* @param id 合并的ID
|
||||||
* @param mergeType 合并的类型
|
* @param mergeType 合并的类型
|
||||||
*/
|
*/
|
||||||
async MergePrompt(id: string, mergeType: MergeType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async MergePrompt(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
await this.InitService()
|
||||||
|
|
||||||
let bookTaskDetail = undefined as Book.SelectBookTaskDetail[];
|
let bookTaskDetail = undefined as Book.SelectBookTaskDetail[];
|
||||||
let bookTask = undefined as Book.SelectBookTask;
|
let bookTask = undefined as Book.SelectBookTask;
|
||||||
|
|
||||||
if (mergeType == MergeType.BOOKTASK) {
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
bookTaskDetail = this.bookTaskDetail.GetBookTaskData({
|
bookTaskDetail = this.bookTaskDetail.GetBookTaskData({
|
||||||
bookTaskId: id
|
bookTaskId: id
|
||||||
}).data
|
}).data
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
||||||
} else if (mergeType == MergeType.BOOKTASKDETAIL) {
|
// 判断是不是有为空的
|
||||||
bookTaskDetail = [this.bookTaskDetail.GetBookTaskDetailDataById(id)]
|
let emptyName = [] as string[]
|
||||||
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
||||||
|
const element = bookTaskDetail[i];
|
||||||
|
if (isEmpty(element.gptPrompt)) {
|
||||||
|
emptyName.push(element.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (emptyName.length > 0) {
|
||||||
|
throw new Error("有空的提示词,请先推理")
|
||||||
|
}
|
||||||
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let tempBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id);
|
||||||
|
if (isEmpty(tempBookTaskDetail.gptPrompt)) {
|
||||||
|
throw new Error("当前分镜没有推理提示词,请先生成")
|
||||||
|
}
|
||||||
|
bookTaskDetail = [tempBookTaskDetail]
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("未知的合并类型")
|
throw new Error("未知的合并类型")
|
||||||
@ -371,7 +390,6 @@ export class MJOpt {
|
|||||||
|
|
||||||
for (let i = 0; i < bookTaskDetail.length; i++) {
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
||||||
const element = bookTaskDetail[i];
|
const element = bookTaskDetail[i];
|
||||||
|
|
||||||
let promptStr = '';
|
let promptStr = '';
|
||||||
for (let i = 0; i < promptSort.length; i++) {
|
for (let i = 0; i < promptSort.length; i++) {
|
||||||
const element = promptSort[i];
|
const element = promptSort[i];
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { MergeType } from "../../../define/enum/bookEnum";
|
|
||||||
import { Book } from "../../../model/book";
|
import { Book } from "../../../model/book";
|
||||||
import { GeneralResponse } from "../../../model/generalResponse";
|
import { GeneralResponse } from "../../../model/generalResponse";
|
||||||
import { checkStringValueAddSuffix, errorMessage, successMessage } from "../../Public/generalTools";
|
import { checkStringValueAddSuffix, errorMessage, successMessage } from "../../Public/generalTools";
|
||||||
@ -8,14 +7,19 @@ import { define } from '../../../define/define'
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { ImageStyleDefine } from "../../../define/iamgeStyleDefine";
|
import { ImageStyleDefine } from "../../../define/iamgeStyleDefine";
|
||||||
import { ImageStyle } from "../Book/imageStyle";
|
import { ImageStyle } from "../Book/imageStyle";
|
||||||
|
import { OperateBookType } from "../../../define/enum/bookEnum";
|
||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
const fspromise = fs.promises
|
const fspromise = fs.promises
|
||||||
|
|
||||||
export class SDOpt {
|
export class SDOpt {
|
||||||
bookTaskDetailService: BookTaskDetailService
|
bookTaskDetailService: BookTaskDetailService
|
||||||
bookTaskService: BookTaskService
|
bookTaskService: BookTaskService
|
||||||
imageStyle: ImageStyle
|
imageStyle: ImageStyle
|
||||||
constructor() {
|
|
||||||
|
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -34,22 +38,37 @@ export class SDOpt {
|
|||||||
/**
|
/**
|
||||||
* SD的提示词合并
|
* SD的提示词合并
|
||||||
* @param id 要处理的ID
|
* @param id 要处理的ID
|
||||||
* @param mergeType 合并的类型(用于判断是单个还是批量)
|
* @param operateBookType 合并的类型(用于判断是单个还是批量)
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async MergePrompt(id: string, mergeType: MergeType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async MergePrompt(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
await this.InitService()
|
||||||
let bookTaskDetail = undefined as Book.SelectBookTaskDetail[];
|
let bookTaskDetail = undefined as Book.SelectBookTaskDetail[];
|
||||||
let bookTask = undefined as Book.SelectBookTask;
|
let bookTask = undefined as Book.SelectBookTask;
|
||||||
|
|
||||||
if (mergeType == MergeType.BOOKTASK) {
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
|
bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
|
||||||
bookTaskId: id
|
bookTaskId: id
|
||||||
}).data
|
}).data
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
||||||
} else if (mergeType == MergeType.BOOKTASKDETAIL) {
|
// 判断是不是有为空的
|
||||||
bookTaskDetail = [this.bookTaskDetailService.GetBookTaskDetailDataById(id)];
|
let emptyName = [] as string[]
|
||||||
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
||||||
|
const element = bookTaskDetail[i];
|
||||||
|
if (isEmpty(element.gptPrompt)) {
|
||||||
|
emptyName.push(element.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (emptyName.length > 0) {
|
||||||
|
throw new Error("有空的提示词,请先推理")
|
||||||
|
}
|
||||||
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let tempBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id);
|
||||||
|
if (isEmpty(tempBookTaskDetail.gptPrompt)) {
|
||||||
|
throw new Error("当前分镜没有推理提示词,请先生成")
|
||||||
|
}
|
||||||
|
bookTaskDetail = [tempBookTaskDetail];
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("未知的合并类型")
|
throw new Error("未知的合并类型")
|
||||||
|
|||||||
256
src/main/Service/ServiceBasic/bookServiceBasic.ts
Normal file
256
src/main/Service/ServiceBasic/bookServiceBasic.ts
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
import { DEFINE_STRING } from "../../../define/define_string";
|
||||||
|
import { GeneralResponse } from "../../../model/generalResponse";
|
||||||
|
import { BookService } from "../../../define/db/service/Book/bookService";
|
||||||
|
import { Book } from "../../../model/book";
|
||||||
|
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
|
||||||
|
import { TaskScheduler } from "../taskScheduler";
|
||||||
|
import { LoggerStatus, OtherData } from "../../../define/enum/softwareEnum";
|
||||||
|
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
||||||
|
import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService";
|
||||||
|
import { BookBackTaskType, BookTaskStatus, TaskExecuteType } from "../../../define/enum/bookEnum";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 该类中封装了小说的基础服务,主要是检查每次引入对应的服务类
|
||||||
|
* 这边进行一个统一的调用,方便后续的维护
|
||||||
|
*/
|
||||||
|
export class BookServiceBasic {
|
||||||
|
bookService: BookService
|
||||||
|
bookTaskService: BookTaskService;
|
||||||
|
taskScheduler: TaskScheduler
|
||||||
|
bookTaskDetailService: BookTaskDetailService
|
||||||
|
bookBackTaskListService: BookBackTaskListService
|
||||||
|
constructor() {
|
||||||
|
this.taskScheduler = new TaskScheduler()
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主动返回前端的消息
|
||||||
|
sendReturnMessage(data: GeneralResponse.MessageResponse, message_name = DEFINE_STRING.BOOK.GET_COPYWRITING_RETURN) {
|
||||||
|
global.newWindow[0].win.webContents.send(message_name, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region 小说相关的基础服务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过小说ID获取小说数据
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetBookDataById(bookId: string): Promise<Book.SelectBook> {
|
||||||
|
await this.InitService();
|
||||||
|
let book = this.bookService.GetBookDataById(bookId);
|
||||||
|
if (book == null) {
|
||||||
|
let msg = '未找到对应的小说数据,请检查'
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
return book
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新小说指定ID的数据
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param data 小说要更新的数据
|
||||||
|
*/
|
||||||
|
async UpdateBookData(bookId: string, data: Book.SelectBook): Promise<Book.SelectBook> {
|
||||||
|
await this.InitService();
|
||||||
|
let res = this.bookService.UpdateBookData(bookId, data)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定的小说数据
|
||||||
|
* @param bookId 需要删除的小说ID
|
||||||
|
*/
|
||||||
|
async DeleteBookData(bookId: string): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookService.DeleteBookData(bookId)
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 小说批次任务相关的基础服务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过小说ID获取小说批次任务数据
|
||||||
|
* @param bookTaskId 小说批次任务ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetBookTaskDataId(bookTaskId: string): Promise<Book.SelectBookTask> {
|
||||||
|
await this.InitService();
|
||||||
|
let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskId);
|
||||||
|
if (bookTask == null) {
|
||||||
|
let msg = '未找到对应的小说批次任务数据,请检查';
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
return bookTask
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过查询条件获取小说批次任务数据
|
||||||
|
* @param bookTaskCondition 小说批次的查询条件
|
||||||
|
*/
|
||||||
|
async GetBookTaskData(bookTaskCondition: Book.QueryBookTaskCondition): Promise<{ bookTasks: Book.SelectBookTask[], total: number }> {
|
||||||
|
await this.InitService();
|
||||||
|
let bookTasks = this.bookTaskService.GetBookTaskData(bookTaskCondition)
|
||||||
|
if (bookTasks.data.bookTasks.length <= 0 || bookTasks.data.total <= 0) {
|
||||||
|
throw new Error("未找到对应的小说批次任务数据,请检查")
|
||||||
|
}
|
||||||
|
return bookTasks.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新小说批次任务的数据
|
||||||
|
* @param bookTaskId 小说批次任务ID
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
async UpdetedBookTaskData(bookTaskId: string, data: Book.SelectBookTask): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskService.UpdetedBookTaskData(bookTaskId, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定的小说批次任务的数据
|
||||||
|
* @param bookTaskId 需要删除的指定的小说批次任务ID
|
||||||
|
*/
|
||||||
|
async DeleteBookTaskData(bookTaskId: string): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskService.DeleteBookTask(bookTaskId)
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 小说批次任务对应的分镜的相关的基础服务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定的小说批次任务分镜数据,通过分镜ID
|
||||||
|
* @param bookTaskDetailId 小说批次任务分镜ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetBookTaskDetailDataById(bookTaskDetailId: string): Promise<Book.SelectBookTaskDetail> {
|
||||||
|
await this.InitService();
|
||||||
|
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(bookTaskDetailId)
|
||||||
|
if (bookTaskDetail == null) {
|
||||||
|
let msg = "未找到对应的小说批次任务分镜数据,请检查"
|
||||||
|
global.logger.error('BookServiceBasic_GetBookTaskDetailDataById', msg);
|
||||||
|
throw new Error("未找到对应的小说批次任务分镜数据,请检查")
|
||||||
|
}
|
||||||
|
return bookTaskDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定的小说批次任务分镜数据,通过查询条件
|
||||||
|
* @param condition
|
||||||
|
*/
|
||||||
|
async GetBookTaskDetailData(condition: Book.QueryBookTaskDetailCondition): Promise<Book.SelectBookTaskDetail[]> {
|
||||||
|
await this.InitService();
|
||||||
|
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData(condition)
|
||||||
|
if (bookTaskDetails.data.length <= 0) {
|
||||||
|
let msg = "未找到对应的小说批次任务分镜数据,请检查";
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
return bookTaskDetails.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改小说的分镜详细数据,通过ID
|
||||||
|
* @param bookTaskDetailId 小说分镜的ID
|
||||||
|
* @param data 要修改的数据,是个对象,会修改全部
|
||||||
|
*/
|
||||||
|
async UpdateBookTaskDetail(bookTaskDetailId: string, data: Book.SelectBookTaskDetail): Promise<Book.SelectBookTaskDetail> {
|
||||||
|
await this.InitService();
|
||||||
|
let res = this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetailId, data)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更行小说批次的状态
|
||||||
|
* @param bookTaskId 小说批次的ID
|
||||||
|
* @param status 修改后的状态
|
||||||
|
* @param errorMsg 错误消息
|
||||||
|
*/
|
||||||
|
async UpdateBookTaskStatus(bookTaskId: string, status: BookTaskStatus, errorMsg: string | null = null): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskService.UpdateBookTaskStatus(bookTaskId, status, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定的小说分镜的反推提示词
|
||||||
|
* @param bookTaskDetail
|
||||||
|
*/
|
||||||
|
async DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskDetailService.DeleteBookTaskDetailReversePromptById(bookTaskDetailId)
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 小说后台任务相关操作
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个后台任务
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param taskType 后台任务类型
|
||||||
|
* @param executeType 执行的类型,是不是自动执行
|
||||||
|
* @param bookTaskId 小说批次任务ID
|
||||||
|
* @param bookTaskDetailId 小说批次任务分镜ID
|
||||||
|
*/
|
||||||
|
async AddBookBackTask(bookId: string,
|
||||||
|
taskType: BookBackTaskType,
|
||||||
|
executeType = TaskExecuteType.AUTO,
|
||||||
|
bookTaskId = null,
|
||||||
|
bookTaskDetailId = null): Promise<TaskModal.Task> {
|
||||||
|
|
||||||
|
await this.InitService();
|
||||||
|
let res = this.bookBackTaskListService.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId)
|
||||||
|
if (res.code == 0) {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
return res.data as TaskModal.Task
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过小说ID和小说批次任务ID获取小说和小说批次任务数据
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param bookTaskName 小说批次的名字,或者是小说批次任务的ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetBookAndTask(bookId: string, bookTaskName: string) {
|
||||||
|
await this.InitService();
|
||||||
|
let book = this.bookService.GetBookDataById(bookId)
|
||||||
|
if (book == null) {
|
||||||
|
throw new Error("查找小说数据失败");
|
||||||
|
}
|
||||||
|
// 获取小说对应的批次任务数据,默认初始化为第一个
|
||||||
|
let condition = {
|
||||||
|
bookId: bookId
|
||||||
|
} as Book.QueryBookBackTaskCondition
|
||||||
|
if (bookTaskName == "output_00001") {
|
||||||
|
condition["name"] = bookTaskName
|
||||||
|
} else {
|
||||||
|
condition["id"] = bookTaskName
|
||||||
|
}
|
||||||
|
let bookTaskRes = this.bookTaskService.GetBookTaskData(condition)
|
||||||
|
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
|
||||||
|
let msg = "没有找到对应的小说批次任务数据"
|
||||||
|
this.taskScheduler.AddLogToDB(bookId, book.type, msg, OtherData.DEFAULT, LoggerStatus.FAIL)
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
return { book: book as Book.SelectBook, bookTask: bookTaskRes.data.bookTasks[0] as Book.SelectBookTask }
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/main/Service/ServiceBasic/softwareServiceBasic.ts
Normal file
76
src/main/Service/ServiceBasic/softwareServiceBasic.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService';
|
||||||
|
|
||||||
|
|
||||||
|
export class SoftWareServiceBasic {
|
||||||
|
softwareService: SoftwareService
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
async InitService() {
|
||||||
|
if (!this.softwareService) {
|
||||||
|
this.softwareService = await SoftwareService.getInstance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region software相关的基础服务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新软件配置信息
|
||||||
|
* @param software
|
||||||
|
*/
|
||||||
|
async UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.softwareService.UpdateSoftware(software)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新的软件配置信息
|
||||||
|
* @param software
|
||||||
|
*/
|
||||||
|
async AddSfotware(software: SoftwareSettingModel.SoftwareSetting): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.softwareService.AddSfotware(software);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取软件配置信息
|
||||||
|
* 软件配置信息只有一个,所以直接返回第一个
|
||||||
|
*/
|
||||||
|
async GetSoftwareData(): Promise<SoftwareSettingModel.SoftwareSetting> {
|
||||||
|
await this.InitService();
|
||||||
|
let softwares = this.softwareService.GetSoftwareData();
|
||||||
|
if (softwares.data.length <= 0) {
|
||||||
|
let msg = "未找到软件配置信息,请检查";
|
||||||
|
global.logger.error(
|
||||||
|
'SoftWareServiceBasic_GetSoftwareData',
|
||||||
|
'获取软件的基础设置失败 ,错误信息如下:' + msg
|
||||||
|
)
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
return softwares.data[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取软件配置指定的属性数据
|
||||||
|
* @param property 属性的名称
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetSoftWarePropertyData(property: string): Promise<string> {
|
||||||
|
await this.InitService();
|
||||||
|
let res = this.softwareService.GetSoftWarePropertyData(property)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存软件的指定属性的设置信息,数据一般是字符串
|
||||||
|
* @param property 要保存的属性的名称
|
||||||
|
* @param data 要保存的数据信息
|
||||||
|
*/
|
||||||
|
async SaveSoftwarePropertyData(property: string, data: string): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.softwareService.SaveSoftwarePropertyData(property, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,45 +1,47 @@
|
|||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { BookService } from '../../define/db/service/Book/bookService'
|
import { errorMessage, successMessage } from '../../Public/generalTools'
|
||||||
import { errorMessage, successMessage } from '../Public/generalTools'
|
import { FfmpegOptions } from '../ffmpegOptions'
|
||||||
import { FfmpegOptions } from './ffmpegOptions'
|
import { SubtitleSavePositionType } from '../../../define/enum/waterMarkAndSubtitle'
|
||||||
import { SubtitleSavePositionType } from '../../define/enum/waterMarkAndSubtitle'
|
import { define } from '../../../define/define'
|
||||||
import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService'
|
|
||||||
import { define } from '../../define/define'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import {
|
import {
|
||||||
CheckFileOrDirExist,
|
CheckFileOrDirExist,
|
||||||
CheckFolderExistsOrCreate,
|
CheckFolderExistsOrCreate,
|
||||||
DeleteFolderAllFile,
|
DeleteFolderAllFile,
|
||||||
GetFilesWithExtensions
|
GetFilesWithExtensions
|
||||||
} from '../../define/Tools/file'
|
} from '../../../define/Tools/file'
|
||||||
import { shell } from 'electron'
|
import { shell } from 'electron'
|
||||||
import { Book } from '../../model/book'
|
import { Book } from '../../../model/book'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import { GeneralResponse } from '../../../model/generalResponse'
|
||||||
|
import { BookServiceBasic } from '../ServiceBasic/bookServiceBasic'
|
||||||
|
import { LoggerStatus, OtherData, ResponseMessageType } from '../../../define/enum/softwareEnum'
|
||||||
|
import { TaskScheduler } from '../taskScheduler'
|
||||||
|
import { SubtitleModel } from '../../../model/subtitle'
|
||||||
|
import { BookTaskStatus, OperateBookType } from '../../../define/enum/bookEnum'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { GptService } from '../GPT/gpt'
|
||||||
|
import FormData from 'form-data'
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
const { exec } = require('child_process')
|
const { exec } = require('child_process')
|
||||||
const execAsync = util.promisify(exec)
|
const execAsync = util.promisify(exec)
|
||||||
const fspromises = fs.promises
|
const fspromises = fs.promises
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 去除水印和获取字幕相关操作
|
* 去除水印和获取字幕相关操作
|
||||||
*/
|
*/
|
||||||
export class Subtitle {
|
export class Subtitle {
|
||||||
bookService: BookService
|
|
||||||
bookTaskDetailService: BookTaskDetailService
|
|
||||||
ffmpegOptions: FfmpegOptions
|
ffmpegOptions: FfmpegOptions
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
taskScheduler: TaskScheduler
|
||||||
|
gptService: GptService
|
||||||
|
|
||||||
constructor() { }
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
async InitService() {
|
this.taskScheduler = new TaskScheduler()
|
||||||
if (!this.bookService) {
|
this.ffmpegOptions = new FfmpegOptions()
|
||||||
this.bookService = await BookService.getInstance()
|
this.gptService = new GptService()
|
||||||
}
|
|
||||||
if (!this.bookTaskDetailService) {
|
|
||||||
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.ffmpegOptions) {
|
|
||||||
this.ffmpegOptions = new FfmpegOptions()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 通用方法
|
//#region 通用方法
|
||||||
@ -50,7 +52,7 @@ export class Subtitle {
|
|||||||
* @param {*} framesPerSecond 每秒截取多少帧
|
* @param {*} framesPerSecond 每秒截取多少帧
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
GenerateFrameTimes(videoDurationMs, framesPerSecond) {
|
GenerateFrameTimes(videoDurationMs: number, framesPerSecond: number): number[] {
|
||||||
// 直接使用视频总时长(毫秒),不进行向下取整
|
// 直接使用视频总时长(毫秒),不进行向下取整
|
||||||
const videoDurationSec = videoDurationMs / 1000
|
const videoDurationSec = videoDurationMs / 1000
|
||||||
|
|
||||||
@ -67,117 +69,70 @@ export class Subtitle {
|
|||||||
let timePoint = Math.min(Math.round(interval * i), videoDurationMs)
|
let timePoint = Math.min(Math.round(interval * i), videoDurationMs)
|
||||||
frameTimes.push(timePoint)
|
frameTimes.push(timePoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return frameTimes
|
return frameTimes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载指定的的小说相关的所有的数据
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param bookTaskId 小说任务ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetBookAllData(bookId: string, bookTaskId: string = null): Promise<{ book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetails: Book.SelectBookTaskDetail[] }> {
|
||||||
|
let { book, bookTask } = await this.bookServiceBasic.GetBookAndTask(bookId, bookTaskId ? bookTaskId : 'output_00001')
|
||||||
|
if (isEmpty(book.subtitlePosition)) {
|
||||||
|
throw new Error("请先设置小说的字幕位置")
|
||||||
|
}
|
||||||
|
// 获取所有的分镜数据
|
||||||
|
let bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookId: bookId,
|
||||||
|
bookTaskId: bookTask.id
|
||||||
|
})
|
||||||
|
if (bookTaskDetails.length <= 0) {
|
||||||
|
throw new Error("没有找到对应的分镜数据,请先执行对应的操作")
|
||||||
|
}
|
||||||
|
return { book, bookTask, bookTaskDetails }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的小说获取分案的返回方法
|
||||||
|
* @param content 获取的文案内容
|
||||||
|
* @param book 小说实体类
|
||||||
|
* @param bookTask 小说任务实体类
|
||||||
|
* @param bookTaskDetail 小说任务分镜实体类
|
||||||
|
*/
|
||||||
|
async GetSubtitleLoggerAndResponse(content: string, progress: GeneralResponse.ProgressResponse, book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetail: Book.SelectBookTaskDetail): Promise<void> {
|
||||||
|
// 修改数据
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
word: content,
|
||||||
|
afterGpt: content
|
||||||
|
});
|
||||||
|
|
||||||
|
// let res = await this.basicReverse.GetCopywritingFunc(book, item);
|
||||||
|
// 将当前的数据实时返回,前端进行修改
|
||||||
|
this.bookServiceBasic.sendReturnMessage({
|
||||||
|
code: 1,
|
||||||
|
id: bookTaskDetail.id,
|
||||||
|
type: ResponseMessageType.GET_TEXT,
|
||||||
|
data: {
|
||||||
|
content: content,
|
||||||
|
progress: progress
|
||||||
|
} as GeneralResponse.SubtitleProgressResponse // 返回识别到的文案
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加日志
|
||||||
|
await this.taskScheduler.AddLogToDB(
|
||||||
|
book.id,
|
||||||
|
book.type,
|
||||||
|
`${bookTaskDetail.name} 识别文案成功`,
|
||||||
|
bookTask.id,
|
||||||
|
LoggerStatus.SUCCESS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
/**
|
//#region 获取字幕位置信息相关操作
|
||||||
* 获取当前视频中所有的字幕信息
|
|
||||||
* @param {*} value 需要的参数的对象,包含下面的参数
|
|
||||||
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
|
||||||
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
|
||||||
* @param {*} value.videoPath 视频路径
|
|
||||||
* @param {*} value.subtitlePosition 字幕位置信息
|
|
||||||
*/
|
|
||||||
async GetVideoFrameText(value: Book.GetVideoFrameTextParams) {
|
|
||||||
try {
|
|
||||||
await this.InitService()
|
|
||||||
let videoPath
|
|
||||||
let tempImageFolder
|
|
||||||
let position
|
|
||||||
if (value.type == SubtitleSavePositionType.MAIN_VIDEO) {
|
|
||||||
let bookRes = this.bookService.GetBookDataById(value.id)
|
|
||||||
if (bookRes == null) {
|
|
||||||
throw new Error('没有找到小说对应的的视频地址')
|
|
||||||
}
|
|
||||||
let book = bookRes
|
|
||||||
tempImageFolder = path.join(define.project_path, `${book.id}/data/subtitle/${book.id}/temp`)
|
|
||||||
if (isEmpty(book.subtitlePosition)) {
|
|
||||||
throw new Error('请先保存位置信息')
|
|
||||||
}
|
|
||||||
position = JSON.parse(book.subtitlePosition)
|
|
||||||
videoPath = book.oldVideoPath
|
|
||||||
} else if (value.type == SubtitleSavePositionType.STORYBOARD_VIDEO) {
|
|
||||||
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(value.id);
|
|
||||||
if (bookTaskDetail == null) {
|
|
||||||
throw new Error("没有找到小说分镜详细信息")
|
|
||||||
}
|
|
||||||
|
|
||||||
tempImageFolder = path.join(define.project_path, `${bookTaskDetail.bookId}/data/subtitle/${bookTaskDetail.name}_${bookTaskDetail.id}/temp`)
|
|
||||||
if (isEmpty(value.subtitlePosition)) {
|
|
||||||
throw new Error('请先保存位置信息')
|
|
||||||
}
|
|
||||||
position = JSON.parse(value.subtitlePosition)
|
|
||||||
videoPath = bookTaskDetail.videoPath
|
|
||||||
} else {
|
|
||||||
throw new Error("不支持的操作");
|
|
||||||
}
|
|
||||||
|
|
||||||
await CheckFolderExistsOrCreate(tempImageFolder)
|
|
||||||
// 判断文件夹是不是存在,存在的话,将里面的所有文件删除
|
|
||||||
await DeleteFolderAllFile(tempImageFolder)
|
|
||||||
|
|
||||||
// 将视频进行抽帧,(目前是每秒1帧,时间小于一秒,抽一帧)
|
|
||||||
let getDurationRes = await this.ffmpegOptions.FfmpegGetVideoDuration(videoPath)
|
|
||||||
if (getDurationRes.code == 0) {
|
|
||||||
throw new Error(getDurationRes.message)
|
|
||||||
}
|
|
||||||
let videoDuration = getDurationRes.data
|
|
||||||
let frameTime = this.GenerateFrameTimes(videoDuration, 1)
|
|
||||||
for (let i = 0; i < frameTime.length; i++) {
|
|
||||||
const item = frameTime[i];
|
|
||||||
let name = i.toString().padStart(6, '0')
|
|
||||||
let imagePath = path.join(tempImageFolder, `frame_${name}.png`)
|
|
||||||
// 开始抽帧
|
|
||||||
let res = await this.ffmpegOptions.FfmpegGetVideoFramdAndClip(
|
|
||||||
videoPath,
|
|
||||||
item,
|
|
||||||
imagePath,
|
|
||||||
position
|
|
||||||
)
|
|
||||||
if (res.code == 0) {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始识别
|
|
||||||
let textRes = await this.GetCurrentFrameText({
|
|
||||||
id: value.id,
|
|
||||||
type: value.type,
|
|
||||||
imageFolder: tempImageFolder
|
|
||||||
})
|
|
||||||
|
|
||||||
let allTextData = [] as string[]
|
|
||||||
// 开始获取所有的数据
|
|
||||||
let jsonPaths = await GetFilesWithExtensions(tempImageFolder, ['.json'])
|
|
||||||
for (let i = 0; i < jsonPaths.length; i++) {
|
|
||||||
const element = jsonPaths[i]
|
|
||||||
// 开始拼接
|
|
||||||
let texts = JSON.parse(await fspromises.readFile(element, 'utf-8'))
|
|
||||||
for (let j = 0; j < texts.length; j++) {
|
|
||||||
const text = texts[j][1][0]
|
|
||||||
allTextData.includes(text) ? null : allTextData.push(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(allTextData.join(','))
|
|
||||||
// 这边计算相似度,返回过于相似的数据
|
|
||||||
// let res = await RemoveSimilarTexts(allTextData)
|
|
||||||
|
|
||||||
return successMessage(
|
|
||||||
allTextData.join(','),
|
|
||||||
'获取视频的的文案信息成功',
|
|
||||||
'WatermarkAndSubtitle_GetVideoFrameText'
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
return errorMessage(
|
|
||||||
'提取视频的的文案信息失败,错误消息如下:' + error.toString(),
|
|
||||||
'WatermarkAndSubtitle_GetCurrentFrameText'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前帧的文字信息
|
* 获取当前帧的文字信息
|
||||||
@ -185,9 +140,8 @@ export class Subtitle {
|
|||||||
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
||||||
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
||||||
*/
|
*/
|
||||||
async GetCurrentFrameText(value) {
|
async GetCurrentFrameText(value: { id: any; type?: SubtitleSavePositionType; imageFolder: any }): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
let iamgePaths = []
|
let iamgePaths = []
|
||||||
let imageFolder = value.imageFolder
|
let imageFolder = value.imageFolder
|
||||||
? value.imageFolder
|
? value.imageFolder
|
||||||
@ -249,7 +203,7 @@ export class Subtitle {
|
|||||||
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
||||||
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
||||||
*/
|
*/
|
||||||
async OpenBookSubtitlePositionScreenshot(value) {
|
async OpenBookSubtitlePositionScreenshot(value: { type: SubtitleSavePositionType; id: any }) {
|
||||||
try {
|
try {
|
||||||
let folder
|
let folder
|
||||||
if (
|
if (
|
||||||
@ -291,9 +245,8 @@ export class Subtitle {
|
|||||||
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async SaveBookSubtitlePosition(value) {
|
async SaveBookSubtitlePosition(value: { type: SubtitleSavePositionType; id: string; bookSubtitlePosition: string | any[]; currentTime: number }) {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
let saveData = []
|
let saveData = []
|
||||||
let videoPath
|
let videoPath
|
||||||
let outImagePath
|
let outImagePath
|
||||||
@ -307,7 +260,7 @@ export class Subtitle {
|
|||||||
throw new Error('小说ID不能为空')
|
throw new Error('小说ID不能为空')
|
||||||
}
|
}
|
||||||
// 获取指定的小说
|
// 获取指定的小说
|
||||||
let bookRes = this.bookService.GetBookDataById(value.id)
|
let bookRes = await this.bookServiceBasic.GetBookDataById(value.id)
|
||||||
if (bookRes == null) {
|
if (bookRes == null) {
|
||||||
throw new Error('没有找到小说信息')
|
throw new Error('没有找到小说信息')
|
||||||
}
|
}
|
||||||
@ -353,19 +306,16 @@ export class Subtitle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 数据保存
|
// 数据保存
|
||||||
let saveRes = await this.bookService.UpdateBookData(value.id, {
|
let saveRes = await this.bookServiceBasic.UpdateBookData(value.id, {
|
||||||
subtitlePosition: JSON.stringify(saveData)
|
subtitlePosition: JSON.stringify(saveData)
|
||||||
})
|
})
|
||||||
if (saveRes.code == 0) {
|
|
||||||
throw new Error(saveRes.message)
|
|
||||||
}
|
|
||||||
} else if (value.type == SubtitleSavePositionType.STORYBOARD_VIDEO) {
|
} else if (value.type == SubtitleSavePositionType.STORYBOARD_VIDEO) {
|
||||||
// 小说分镜详细信息保存
|
// 小说分镜详细信息保存
|
||||||
if (value.id == null) {
|
if (value.id == null) {
|
||||||
throw new Error('小说分镜详细信息ID不能为空')
|
throw new Error('小说分镜详细信息ID不能为空')
|
||||||
}
|
}
|
||||||
// 获取指定的小说分镜详细信息
|
// 获取指定的小说分镜详细信息
|
||||||
let bookStoryboard = this.bookTaskDetailService.GetBookTaskDetailDataById(value.id)
|
let bookStoryboard = await this.bookServiceBasic.GetBookTaskDetailDataById(value.id)
|
||||||
if (bookStoryboard == null) {
|
if (bookStoryboard == null) {
|
||||||
throw new Error('没有找到小说分镜信息')
|
throw new Error('没有找到小说分镜信息')
|
||||||
}
|
}
|
||||||
@ -414,12 +364,9 @@ export class Subtitle {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 数据保存
|
// 数据保存
|
||||||
let saveRes = this.bookTaskDetailService.UpdateBookTaskDetail(bookStoryboard.id, {
|
let saveRes = this.bookServiceBasic.UpdateBookTaskDetail(bookStoryboard.id, {
|
||||||
subtitlePosition: JSON.stringify(saveData)
|
subtitlePosition: JSON.stringify(saveData)
|
||||||
})
|
})
|
||||||
if (saveRes.code == 0) {
|
|
||||||
throw new Error(saveRes.message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始设置裁剪出来的图片位置
|
// 开始设置裁剪出来的图片位置
|
||||||
@ -445,4 +392,272 @@ export class Subtitle {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 本地OCR识别字幕相关操作
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前视频中所有的字幕信息
|
||||||
|
* @param {*} value 需要的参数的对象,包含下面的参数
|
||||||
|
* @param {*} value.id 小说ID/小说分镜详细信息ID/null
|
||||||
|
* @param {*} value.type 保存的类型(主视频/分镜视频/后续会添加外部单独的视频提取)
|
||||||
|
* @param {*} value.videoPath 视频路径
|
||||||
|
* @param {*} value.subtitlePosition 字幕位置信息
|
||||||
|
*/
|
||||||
|
async GetVideoFrameText(value: Book.GetVideoFrameTextParams): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let videoPath = undefined
|
||||||
|
let tempImageFolder = undefined
|
||||||
|
let position = undefined
|
||||||
|
if (value.type == SubtitleSavePositionType.MAIN_VIDEO) {
|
||||||
|
let bookRes = await this.bookServiceBasic.GetBookDataById(value.id)
|
||||||
|
if (bookRes == null) {
|
||||||
|
throw new Error('没有找到小说对应的的视频地址')
|
||||||
|
}
|
||||||
|
let book = bookRes
|
||||||
|
tempImageFolder = path.join(define.project_path, `${book.id}/data/subtitle/${book.id}/temp`)
|
||||||
|
if (isEmpty(book.subtitlePosition)) {
|
||||||
|
throw new Error('请先保存位置信息')
|
||||||
|
}
|
||||||
|
position = JSON.parse(book.subtitlePosition)
|
||||||
|
videoPath = book.oldVideoPath
|
||||||
|
} else if (value.type == SubtitleSavePositionType.STORYBOARD_VIDEO) {
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(value.id);
|
||||||
|
if (bookTaskDetail == null) {
|
||||||
|
throw new Error("没有找到小说分镜详细信息")
|
||||||
|
}
|
||||||
|
|
||||||
|
tempImageFolder = path.join(define.project_path, `${bookTaskDetail.bookId}/data/subtitle/${bookTaskDetail.name}_${bookTaskDetail.id}/temp`)
|
||||||
|
if (isEmpty(value.subtitlePosition)) {
|
||||||
|
throw new Error('请先保存位置信息')
|
||||||
|
}
|
||||||
|
position = JSON.parse(value.subtitlePosition)
|
||||||
|
videoPath = bookTaskDetail.videoPath
|
||||||
|
} else {
|
||||||
|
throw new Error("不支持的操作");
|
||||||
|
}
|
||||||
|
|
||||||
|
await CheckFolderExistsOrCreate(tempImageFolder)
|
||||||
|
// 判断文件夹是不是存在,存在的话,将里面的所有文件删除
|
||||||
|
await DeleteFolderAllFile(tempImageFolder)
|
||||||
|
|
||||||
|
// 将视频进行抽帧,(目前是每秒1帧,时间小于一秒,抽一帧)
|
||||||
|
let getDurationRes = await this.ffmpegOptions.FfmpegGetVideoDuration(videoPath)
|
||||||
|
if (getDurationRes.code == 0) {
|
||||||
|
throw new Error(getDurationRes.message)
|
||||||
|
}
|
||||||
|
let videoDuration = getDurationRes.data
|
||||||
|
let frameTime = this.GenerateFrameTimes(videoDuration, 1)
|
||||||
|
for (let i = 0; i < frameTime.length; i++) {
|
||||||
|
const item = frameTime[i];
|
||||||
|
let name = i.toString().padStart(6, '0')
|
||||||
|
let imagePath = path.join(tempImageFolder, `frame_${name}.png`)
|
||||||
|
// 开始抽帧
|
||||||
|
let res = await this.ffmpegOptions.FfmpegGetVideoFramdAndClip(
|
||||||
|
videoPath,
|
||||||
|
item,
|
||||||
|
imagePath,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
if (res.code == 0) {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始识别
|
||||||
|
let textRes = await this.GetCurrentFrameText({
|
||||||
|
id: value.id,
|
||||||
|
type: value.type,
|
||||||
|
imageFolder: tempImageFolder
|
||||||
|
})
|
||||||
|
|
||||||
|
let allTextData = [] as string[]
|
||||||
|
// 开始获取所有的数据
|
||||||
|
let jsonPaths = await GetFilesWithExtensions(tempImageFolder, ['.json'])
|
||||||
|
for (let i = 0; i < jsonPaths.length; i++) {
|
||||||
|
const element = jsonPaths[i]
|
||||||
|
// 开始拼接
|
||||||
|
let texts = JSON.parse(await fspromises.readFile(element, 'utf-8'))
|
||||||
|
for (let j = 0; j < texts.length; j++) {
|
||||||
|
const text = texts[j][1][0]
|
||||||
|
allTextData.includes(text) ? null : allTextData.push(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 这边计算相似度,返回过于相似的数据
|
||||||
|
// let res = await RemoveSimilarTexts(allTextData)
|
||||||
|
|
||||||
|
return successMessage(
|
||||||
|
allTextData.join(','),
|
||||||
|
'获取视频的的文案信息成功',
|
||||||
|
'WatermarkAndSubtitle_GetVideoFrameText'
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage(
|
||||||
|
'提取视频的的文案信息失败,错误消息如下:' + error.toString(),
|
||||||
|
'WatermarkAndSubtitle_GetCurrentFrameText'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用本地OCR识别字幕文案
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param bookTaskId 小说任务ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetCopywritingByLocalOcr(book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetails: Book.SelectBookTaskDetail[]): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const item = bookTaskDetails[i];
|
||||||
|
let res = await this.GetVideoFrameText({
|
||||||
|
id: item.id,
|
||||||
|
videoPath: item.videoPath,
|
||||||
|
type: SubtitleSavePositionType.STORYBOARD_VIDEO,
|
||||||
|
subtitlePosition: book.subtitlePosition
|
||||||
|
})
|
||||||
|
if (res.code == 0) {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
// 修改数据,并返回
|
||||||
|
await this.GetSubtitleLoggerAndResponse(res.data, {
|
||||||
|
total: bookTaskDetails.length,
|
||||||
|
current: i + 1
|
||||||
|
}, book, bookTask, item)
|
||||||
|
}
|
||||||
|
return successMessage(null, "识别是所有文案成功", "Subtitle_GetCopywriting")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取分镜数据失败,失败信息如下:" + error.message, 'Subtitle_GetCopywriting')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region Lai_WHISPER识别字幕相关操作
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单个分离音频的方法
|
||||||
|
* @param book 小说数据
|
||||||
|
* @param bookTask 小说任务数据
|
||||||
|
* @param bookTaskDetail 小说任务详细信息数据
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async SplitAudio(book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetail: Book.SelectBookTaskDetail) {
|
||||||
|
// 开始分离音频
|
||||||
|
let videoPath = bookTaskDetail.videoPath
|
||||||
|
let audioPath = path.join(path.dirname(videoPath), bookTaskDetail.name + '.mp3');
|
||||||
|
let audioRes = await this.ffmpegOptions.FfmpegExtractAudio(bookTaskDetail.videoPath, audioPath)
|
||||||
|
if (audioRes.code == 0) {
|
||||||
|
let errorMessage = `分离音频失败,错误信息如下:${audioRes.message}`
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskStatus(
|
||||||
|
bookTask.id,
|
||||||
|
BookTaskStatus.AUDIO_FAIL,
|
||||||
|
errorMessage
|
||||||
|
)
|
||||||
|
throw new Error(audioRes.message)
|
||||||
|
}
|
||||||
|
this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
audioPath: path.relative(define.project_path, audioPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 推送成功消息
|
||||||
|
await this.taskScheduler.AddLogToDB(
|
||||||
|
book.id,
|
||||||
|
book.type,
|
||||||
|
`${bookTaskDetail.name}分离音频成功,输出地址:${audioPath}`,
|
||||||
|
OtherData.DEFAULT,
|
||||||
|
LoggerStatus.SUCCESS
|
||||||
|
)
|
||||||
|
// 修改状态为分离音频成功
|
||||||
|
this.bookServiceBasic.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.AUDIO_DONE)
|
||||||
|
return audioPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用LAI Whisper 进行文本识别,然后将繁体转换为简体
|
||||||
|
* @param audioPath 要识别的音频地址
|
||||||
|
* @param subtitleSetting 识别字幕设置
|
||||||
|
*/
|
||||||
|
async LaiWhisperApi(audioPath: string, subtitleSetting: SubtitleModel.subtitleSettingModel): Promise<string> {
|
||||||
|
// 开始调用LAI API识别
|
||||||
|
let formdata = new FormData()
|
||||||
|
formdata.append("file", fs.createReadStream(audioPath)); // 如果是Node.js环境,可以使用fs.createReadStream方法
|
||||||
|
formdata.append("model", "whisper-1");
|
||||||
|
formdata.append("response_format", "srt");
|
||||||
|
formdata.append("temperature", "0");
|
||||||
|
formdata.append("language", "zh");
|
||||||
|
formdata.append("prompt", isEmpty(subtitleSetting.laiWhisper.prompt) ? "eiusmod nulla" : subtitleSetting.laiWhisper.prompt);
|
||||||
|
let url = subtitleSetting.laiWhisper.url
|
||||||
|
if (!url.endsWith('/')) {
|
||||||
|
url = url + '/'
|
||||||
|
}
|
||||||
|
const config = {
|
||||||
|
method: 'post',
|
||||||
|
url: url + 'v1/audio/transcriptions',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': subtitleSetting.laiWhisper.apiKey,
|
||||||
|
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
...formdata.getHeaders() // 在Node.js环境中需要添加这一行
|
||||||
|
},
|
||||||
|
data: formdata
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = await axios(config)
|
||||||
|
let text = res.data.text;
|
||||||
|
// 但是这边是繁体,需要转化为简体
|
||||||
|
let simpleText = await this.gptService.ChineseTraditionalToSimplified(text, subtitleSetting.laiWhisper.apiKey, url);
|
||||||
|
|
||||||
|
console.log(res.data)
|
||||||
|
return simpleText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用LAI Whisper识别字幕
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param bookTaskId 小说任务ID
|
||||||
|
* @param subtitleSetting 提取文案相关设置
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetCopywritingByLaiWhisper(book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetails: Book.SelectBookTaskDetail[], subtitleSetting: SubtitleModel.subtitleSettingModel): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let emptyVideoPaths = [] as string[]
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const element = bookTaskDetails[i];
|
||||||
|
// 将所有的分镜视频音频分开
|
||||||
|
if (isEmpty(element.videoPath)) {
|
||||||
|
emptyVideoPaths.push(element.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (emptyVideoPaths.length > 0) {
|
||||||
|
throw new Error(`以下分镜视频没有找到对应的视频路径:${emptyVideoPaths.join(",")} \n 请先计算分镜`)
|
||||||
|
}
|
||||||
|
// 拆分音频和视频
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const bookTaskDetail = bookTaskDetails[i];
|
||||||
|
// 开始分离音频
|
||||||
|
let audioPath = await this.SplitAudio(book, bookTask, bookTaskDetail)
|
||||||
|
let fileExist = await CheckFileOrDirExist(audioPath)
|
||||||
|
if (!fileExist) {
|
||||||
|
throw new Error('没有找到对应的音频文件');
|
||||||
|
}
|
||||||
|
// 开始调用LAI API识别
|
||||||
|
let content = await this.LaiWhisperApi(audioPath, subtitleSetting);
|
||||||
|
// 向前端发送数据
|
||||||
|
await this.GetSubtitleLoggerAndResponse(content, {
|
||||||
|
total: bookTaskDetails.length,
|
||||||
|
current: i + 1
|
||||||
|
}, book, bookTask, bookTaskDetail)
|
||||||
|
}
|
||||||
|
return successMessage(
|
||||||
|
null,
|
||||||
|
`所有音频识别成功`,
|
||||||
|
'Subtitle_GetCopywritingByLaiWhisper'
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取分镜数据失败,失败信息如下:" + error.message, 'Subtitle_GetCopywritingByLaiWhisper')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
227
src/main/Service/Subtitle/subtitleService.ts
Normal file
227
src/main/Service/Subtitle/subtitleService.ts
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import { GetSubtitleType, SubtitleSavePositionType } from "../../../define/enum/waterMarkAndSubtitle"
|
||||||
|
import { errorMessage, successMessage } from "../../Public/generalTools"
|
||||||
|
import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic"
|
||||||
|
import { ValidateJson } from "../../../define/Tools/validate";
|
||||||
|
import { GeneralResponse } from "../../../model/generalResponse";
|
||||||
|
import { SubtitleModel } from "../../../model/subtitle";
|
||||||
|
import { define } from '../../../define/define'
|
||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import { CheckFileOrDirExist } from "../../../define/Tools/file";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { Subtitle } from "./subtitle";
|
||||||
|
import { LoggerStatus, ResponseMessageType } from "../../../define/enum/softwareEnum";
|
||||||
|
import { TaskScheduler } from "../taskScheduler";
|
||||||
|
import { OperationType } from "realm/dist/public-types/internal";
|
||||||
|
import { OperateBookType } from "../../../define/enum/bookEnum";
|
||||||
|
import { Book } from "../../../model/book";
|
||||||
|
|
||||||
|
export class SubtitleService {
|
||||||
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
subtitle: Subtitle
|
||||||
|
taskScheduler: TaskScheduler
|
||||||
|
constructor() {
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic();
|
||||||
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
|
this.subtitle = new Subtitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region 设置相关的方法
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化字幕设置
|
||||||
|
*/
|
||||||
|
async InitSubtitleSetting(): Promise<SubtitleModel.subtitleSettingModel> {
|
||||||
|
let defauleSetting = {
|
||||||
|
selectModel: GetSubtitleType.LAI_WHISPER,
|
||||||
|
laiWhisper: {
|
||||||
|
url: 'https://api.laitool.cc/',
|
||||||
|
apiKey: '你的LAI API KEY',
|
||||||
|
syncGPTAPIKey: false,
|
||||||
|
prompt: undefined
|
||||||
|
}
|
||||||
|
} as SubtitleModel.subtitleSettingModel
|
||||||
|
await this.softWareServiceBasic.SaveSoftwarePropertyData("subtitleSetting", JSON.stringify(defauleSetting));
|
||||||
|
return defauleSetting
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取提起字幕的设置
|
||||||
|
*/
|
||||||
|
async GetSubtitleSetting(): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let subtitleSetting = undefined as SubtitleModel.subtitleSettingModel
|
||||||
|
let subtitleSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('subtitleSetting');
|
||||||
|
if (isEmpty(subtitleSettingString)) {
|
||||||
|
// 初始化
|
||||||
|
subtitleSetting = await this.InitSubtitleSetting();
|
||||||
|
} else {
|
||||||
|
if (ValidateJson(subtitleSettingString)) {
|
||||||
|
subtitleSetting = JSON.parse(subtitleSettingString)
|
||||||
|
} else {
|
||||||
|
throw new Error("提起字幕设置解析失败,请重置后重新配置")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successMessage(subtitleSetting, '获取提取字幕设置成功', "SubtitleService_GetSubtitleSetting")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取字幕设置失败,失败信息如下:" + error.message, "SubtitleService_GetSubtitleSetting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置识别字幕设置
|
||||||
|
*/
|
||||||
|
async ResetSubtitleSetting(): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let subtitleSetting = await this.InitSubtitleSetting();
|
||||||
|
return successMessage(subtitleSetting, "重置字幕设置成功", "SubtitleService_ResetSubtitleSetting")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("重置字幕设置失败,失败信息如下:" + error.message, "SubtitleService_ResetSubtitleSetting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存提取字幕设置,并作相应的一些简单的检查
|
||||||
|
* @param subtitleSetting 要保存的数据结构体
|
||||||
|
*/
|
||||||
|
async SaveSubtitleSetting(subtitleSetting: SubtitleModel.subtitleSettingModel): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
// 判断模式,通过不同的模式判断是不是又必要检查
|
||||||
|
if (subtitleSetting.selectModel == GetSubtitleType.LOCAL_OCR) {
|
||||||
|
let localOcrPath = path.join(define.scripts_path, 'LaiOcr/LaiOcr.exe');
|
||||||
|
let fileIsExists = await CheckFileOrDirExist(localOcrPath);
|
||||||
|
if (!fileIsExists) {
|
||||||
|
throw new Error("当前模式未本地OCR,但是没有检查到对应的执行文件,请查看教程,安装对应的拓展");
|
||||||
|
}
|
||||||
|
} else if (subtitleSetting.selectModel == GetSubtitleType.LOCAL_WHISPER) {
|
||||||
|
// let localWhisper = path.join(define.scripts_path,'')
|
||||||
|
// 这个好像没有什么可以检查的
|
||||||
|
} else if (subtitleSetting.selectModel == GetSubtitleType.LAI_WHISPER) {
|
||||||
|
// 判断是不是laitool的,不是的话报错
|
||||||
|
if (!subtitleSetting.laiWhisper.url.includes('laitool')) {
|
||||||
|
throw new Error('该模式只能试用LAI API的接口请求');
|
||||||
|
}
|
||||||
|
if (isEmpty(subtitleSetting.laiWhisper.apiKey)) {
|
||||||
|
throw new Error("当前模式为LAI API的接口请求,请输入LAI API KEY")
|
||||||
|
}
|
||||||
|
if (isEmpty(subtitleSetting.laiWhisper.url)) {
|
||||||
|
throw new Error("当前模式为LAI API的接口请求,请输入LAI API URL")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("未知的识别字幕模式")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查做完,开始保存数据
|
||||||
|
await this.softWareServiceBasic.SaveSoftwarePropertyData('subtitleSetting', JSON.stringify(subtitleSetting))
|
||||||
|
return successMessage(null, "保存提取文案设置成功", "SubtitleService_SaveSubtitleSetting");
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("保存提取文案设置失败,失败信息如下:" + error.message, "SubtitleService_SaveSubtitleSetting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#region 语音转文案或者是字幕识别
|
||||||
|
/**
|
||||||
|
* 反推提取文案
|
||||||
|
*/
|
||||||
|
async GetCopywriting(bookId: string, bookTaskId: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let subtitleSettingRes = await this.GetSubtitleSetting();
|
||||||
|
if (subtitleSettingRes.code == 0) {
|
||||||
|
throw new Error(subtitleSettingRes.message)
|
||||||
|
}
|
||||||
|
let subtitleSetting = subtitleSettingRes.data as SubtitleModel.subtitleSettingModel;
|
||||||
|
let res = undefined as GeneralResponse.ErrorItem | GeneralResponse.SuccessItem
|
||||||
|
|
||||||
|
let bookTaskDetails = undefined as Book.SelectBookTaskDetail[]
|
||||||
|
|
||||||
|
let tempBookTaskId = bookTaskId
|
||||||
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
|
bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookId: bookId,
|
||||||
|
bookTaskId: bookTaskId
|
||||||
|
})
|
||||||
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let tempBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskId)
|
||||||
|
tempBookTaskId = tempBookTaskDetail.bookTaskId
|
||||||
|
bookTaskDetails = [tempBookTaskDetail]
|
||||||
|
} else {
|
||||||
|
throw new Error("未知的操作类型")
|
||||||
|
}
|
||||||
|
if (bookTaskDetails.length <= 0) {
|
||||||
|
throw new Error("分镜信息不存在");
|
||||||
|
}
|
||||||
|
let { book, bookTask } = await this.bookServiceBasic.GetBookAndTask(bookId, tempBookTaskId)
|
||||||
|
|
||||||
|
switch (subtitleSetting.selectModel) {
|
||||||
|
case GetSubtitleType.LOCAL_OCR:
|
||||||
|
res = await this.subtitle.GetCopywritingByLocalOcr(book, bookTask, bookTaskDetails)
|
||||||
|
break;
|
||||||
|
case GetSubtitleType.LOCAL_WHISPER:
|
||||||
|
throw new Error("本地Whisper暂时不支持")
|
||||||
|
break;
|
||||||
|
case GetSubtitleType.LAI_WHISPER:
|
||||||
|
res = await this.subtitle.GetCopywritingByLaiWhisper(book, bookTask, bookTaskDetails, subtitleSetting)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("未知的识别字幕模式")
|
||||||
|
}
|
||||||
|
if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskId)
|
||||||
|
return successMessage(bookTaskDetail.afterGpt, "获取文案成功", "ReverseBook_GetCopywriting")
|
||||||
|
} else {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取分镜数据失败,失败信息如下:" + error.message, 'ReverseBook_GetCopywriting')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出指定导出指定小说的文案
|
||||||
|
* @param bookTaskId 小说批次任务ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async ExportCopywriting(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataId(bookTaskId)
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId)
|
||||||
|
let bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookId: book.id,
|
||||||
|
bookTaskId: bookTaskId
|
||||||
|
})
|
||||||
|
|
||||||
|
let emptyList = []
|
||||||
|
let content = []
|
||||||
|
|
||||||
|
// 检查是不是所有的里面都有文案
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const element = bookTaskDetails[i];
|
||||||
|
if (isEmpty(element.afterGpt)) {
|
||||||
|
emptyList.push(element.name)
|
||||||
|
} else {
|
||||||
|
content.push(element.afterGpt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (emptyList.length > 0) {
|
||||||
|
throw new Error(`以下分镜没有文案:${emptyList.join("\n")}`);
|
||||||
|
}
|
||||||
|
// 写出文案
|
||||||
|
let contentStr = content.join("。\n");
|
||||||
|
contentStr = contentStr + '。'
|
||||||
|
let wordPath = path.join(book.bookFolderPath, "文案.txt")
|
||||||
|
await fs.promises.writeFile(wordPath, contentStr, 'utf-8')
|
||||||
|
return successMessage(wordPath, "导出文案成功", "ReverseBook_ExportCopywriting")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("导出文案失败,失败信息如下:" + error.message, 'ReverseBook_ExportCopywriting')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import { ResponseMessageType } from "../../../define/enum/softwareEnum";
|
|||||||
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService'
|
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService'
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import { ValidateJson } from "../../../define/Tools/validate";
|
import { ValidateJson } from "../../../define/Tools/validate";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 翻译实现服务
|
* 翻译实现服务
|
||||||
@ -18,8 +19,10 @@ export class TranslateService {
|
|||||||
translate: Translate
|
translate: Translate
|
||||||
bookTaskDetail: BookTaskDetailService;
|
bookTaskDetail: BookTaskDetailService;
|
||||||
softwareService: SoftwareService
|
softwareService: SoftwareService
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitService() {
|
async InitService() {
|
||||||
@ -107,7 +110,7 @@ export class TranslateService {
|
|||||||
// 解析
|
// 解析
|
||||||
let tryParse = ValidateJson(translateSettingString)
|
let tryParse = ValidateJson(translateSettingString)
|
||||||
if (!tryParse) {
|
if (!tryParse) {
|
||||||
throw new Error("翻译设置数据解析失败")
|
throw new Error("翻译设置数据解析失败,请重置后重新配置")
|
||||||
}
|
}
|
||||||
translateSetting = JSON.parse(translateSettingString);
|
translateSetting = JSON.parse(translateSettingString);
|
||||||
}
|
}
|
||||||
@ -175,7 +178,7 @@ export class TranslateService {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反推翻译提示词处理
|
* 翻译反推提示词处理
|
||||||
* @param bookTaskDetailId 对应的分镜ID
|
* @param bookTaskDetailId 对应的分镜ID
|
||||||
* @param reversePromptId 对应的反推提示词数据ID
|
* @param reversePromptId 对应的反推提示词数据ID
|
||||||
* @param to 目标语言
|
* @param to 目标语言
|
||||||
@ -200,6 +203,12 @@ export class TranslateService {
|
|||||||
case TranslateType.REVERSE_PROMPT_TRANSLATE:
|
case TranslateType.REVERSE_PROMPT_TRANSLATE:
|
||||||
await this.TranslateProcessReversePrompt(value.bookTaskDetailId, value.reversePromptId, to, dstString)
|
await this.TranslateProcessReversePrompt(value.bookTaskDetailId, value.reversePromptId, to, dstString)
|
||||||
break;
|
break;
|
||||||
|
case TranslateType.GPT_PROMPT_TRANSLATE:
|
||||||
|
// 这个直接改就行
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(value.bookTaskDetailId, {
|
||||||
|
gptPrompt: dstString
|
||||||
|
})
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("未知的翻译类型");
|
throw new Error("未知的翻译类型");
|
||||||
}
|
}
|
||||||
@ -228,11 +237,15 @@ export class TranslateService {
|
|||||||
// 写回数据库
|
// 写回数据库
|
||||||
await this.TranslateReturnProcess(element, data.to, srcString);
|
await this.TranslateReturnProcess(element, data.to, srcString);
|
||||||
|
|
||||||
|
let responseType = ResponseMessageType.REVERSE_PROMPT_TRANSLATE;
|
||||||
|
if (element.type == TranslateType.GPT_PROMPT_TRANSLATE) {
|
||||||
|
responseType = ResponseMessageType.GPT_PROMPT_TRANSLATE
|
||||||
|
}
|
||||||
// 做个返回数据
|
// 做个返回数据
|
||||||
this.sendTranslateReturn(element.windowId, {
|
this.sendTranslateReturn(element.windowId, {
|
||||||
code: 1,
|
code: 1,
|
||||||
id: element.bookTaskDetailId,
|
id: element.bookTaskDetailId,
|
||||||
type: ResponseMessageType.PROMPT_TRANSLATE,
|
type: responseType,
|
||||||
data: {
|
data: {
|
||||||
progress: i + 1,
|
progress: i + 1,
|
||||||
total: value.length,
|
total: value.length,
|
||||||
|
|||||||
15
src/main/Service/d3.ts
Normal file
15
src/main/Service/d3.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
export class D3 {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
//#region D3进行画图的基础方法
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 软件相关的方法
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
}
|
||||||
@ -172,7 +172,7 @@ export class FfmpegOptions {
|
|||||||
* @param {*} outAudioPath 输出音频地址
|
* @param {*} outAudioPath 输出音频地址
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async FfmpegExtractAudio(videoPath, outAudioPath) {
|
async FfmpegExtractAudio(videoPath: string, outAudioPath: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
// 判断视频地址是不是存在
|
// 判断视频地址是不是存在
|
||||||
let videoIsExist = await CheckFileOrDirExist(videoPath)
|
let videoIsExist = await CheckFileOrDirExist(videoPath)
|
||||||
@ -205,13 +205,12 @@ export class FfmpegOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ffmpeg提取视频帧(只提取一帧)
|
* Ffmpeg提取视频指定时间的帧(只提取一帧)
|
||||||
* 根据point判断提取什么位置的帧
|
|
||||||
* @param {*} frameTime 视频的时间点
|
* @param {*} frameTime 视频的时间点
|
||||||
* @param {*} videoPath 视频地址
|
* @param {*} videoPath 视频地址
|
||||||
* @param {*} outFramePath 输出帧地址
|
* @param {*} outFramePath 输出帧地址
|
||||||
*/
|
*/
|
||||||
async FfmpegGetFrame(frameTime, videoPath, outFramePath) {
|
async FfmpegGetFrame(frameTime: number, videoPath: string, outFramePath: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
let videoIsExist = await CheckFileOrDirExist(videoPath)
|
let videoIsExist = await CheckFileOrDirExist(videoPath)
|
||||||
if (videoIsExist == false) {
|
if (videoIsExist == false) {
|
||||||
@ -238,7 +237,7 @@ export class FfmpegOptions {
|
|||||||
.run()
|
.run()
|
||||||
})
|
})
|
||||||
let res_msg = `视频抽帧完成,输出地址:${res}`
|
let res_msg = `视频抽帧完成,输出地址:${res}`
|
||||||
return successMessage(res, '视频抽帧成功', 'BasicReverse_FfmpegGetFrame')
|
return successMessage(res, res_msg, 'BasicReverse_FfmpegGetFrame')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(error.message, 'BasicReverse_FfmpegGetFrame')
|
return errorMessage(error.message, 'BasicReverse_FfmpegGetFrame')
|
||||||
}
|
}
|
||||||
@ -328,7 +327,7 @@ export class FfmpegOptions {
|
|||||||
throw new Error(frameRes.message)
|
throw new Error(frameRes.message)
|
||||||
}
|
}
|
||||||
let outImagePaths = []
|
let outImagePaths = []
|
||||||
if(await CheckFileOrDirExist(outImagePath) == false){
|
if (await CheckFileOrDirExist(outImagePath) == false) {
|
||||||
return successMessage(
|
return successMessage(
|
||||||
outImagePaths,
|
outImagePaths,
|
||||||
'获取指定位置的帧和裁剪成功',
|
'获取指定位置的帧和裁剪成功',
|
||||||
|
|||||||
@ -124,6 +124,12 @@ export class TaskManager {
|
|||||||
for (let index = 0; index < tasks.data.length; index++) {
|
for (let index = 0; index < tasks.data.length; index++) {
|
||||||
const element = tasks.data[index];
|
const element = tasks.data[index];
|
||||||
if (element.type == BookBackTaskType.MJ_IMAGE || element.type == BookBackTaskType.MJ_REVERSE) {
|
if (element.type == BookBackTaskType.MJ_IMAGE || element.type == BookBackTaskType.MJ_REVERSE) {
|
||||||
|
// 判断任务数量是不是又修改
|
||||||
|
let taskNumber = global.mjQueue.getConcurrencyLimit();
|
||||||
|
if (taskNumber != this.mjOpt.mjSetting.taskCount) {
|
||||||
|
global.mjQueue.concurrencyLimit = this.mjOpt.mjSetting.taskCount // 重置并发执行的数量
|
||||||
|
}
|
||||||
|
|
||||||
if (global.mjQueue.getWaitingQueue() > 10) {
|
if (global.mjQueue.getWaitingQueue() > 10) {
|
||||||
console.log('MJ等待中的任务太多,等待中的任务数量:', global.mjQueue.getWaitingQueue());
|
console.log('MJ等待中的任务太多,等待中的任务数量:', global.mjQueue.getWaitingQueue());
|
||||||
this.spaceTime = 20000;
|
this.spaceTime = 20000;
|
||||||
@ -275,11 +281,6 @@ export class TaskManager {
|
|||||||
* @param task
|
* @param task
|
||||||
*/
|
*/
|
||||||
async AddImageMJImage(task: TaskModal.Task) {
|
async AddImageMJImage(task: TaskModal.Task) {
|
||||||
// 判断任务数量是不是又修改
|
|
||||||
let taskNumber = global.mjQueue.getConcurrencyLimit();
|
|
||||||
if (taskNumber != this.mjOpt.mjSetting.taskCount) {
|
|
||||||
global.mjQueue.concurrencyLimit = this.mjOpt.mjSetting.taskCount // 重置并发执行的数量
|
|
||||||
}
|
|
||||||
// 判断是不是MJ的任务
|
// 判断是不是MJ的任务
|
||||||
let batch = DEFINE_STRING.MJ.MJ_IMAGE;
|
let batch = DEFINE_STRING.MJ.MJ_IMAGE;
|
||||||
global.mjQueue.enqueue(async () => {
|
global.mjQueue.enqueue(async () => {
|
||||||
|
|||||||
@ -352,7 +352,11 @@ export class Watermark {
|
|||||||
bookId: bookTask.bookId
|
bookId: bookTask.bookId
|
||||||
}).data as Book.SelectBookTaskDetail[]
|
}).data as Book.SelectBookTaskDetail[]
|
||||||
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(id)
|
||||||
|
if (bookTaskDetail == null) {
|
||||||
|
throw new Error("指定的小说任务分镜信息不存在,请检查")
|
||||||
|
}
|
||||||
|
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail.bookTaskId);
|
||||||
if (bookTask == null) {
|
if (bookTask == null) {
|
||||||
throw new Error('指定的小说任务数据不存在')
|
throw new Error('指定的小说任务数据不存在')
|
||||||
}
|
}
|
||||||
@ -360,10 +364,7 @@ export class Watermark {
|
|||||||
if (book == null) {
|
if (book == null) {
|
||||||
throw new Error("小说数据不存在,请检查")
|
throw new Error("小说数据不存在,请检查")
|
||||||
}
|
}
|
||||||
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(id)
|
|
||||||
if (bookTaskDetail == null) {
|
|
||||||
throw new Error("指定的小说任务分镜信息不存在,请检查")
|
|
||||||
}
|
|
||||||
bookTaskDetails = [bookTaskDetail];
|
bookTaskDetails = [bookTaskDetail];
|
||||||
} else {
|
} else {
|
||||||
throw new Error("未知的操作类型")
|
throw new Error("未知的操作类型")
|
||||||
@ -451,7 +452,11 @@ export class Watermark {
|
|||||||
this.taskScheduler.AddLogToDB(book.id, book.type, `${element.name} 去除水印完成`, element.bookTaskId, LoggerStatus.SUCCESS)
|
this.taskScheduler.AddLogToDB(book.id, book.type, `${element.name} 去除水印完成`, element.bookTaskId, LoggerStatus.SUCCESS)
|
||||||
}
|
}
|
||||||
// 全部完毕
|
// 全部完毕
|
||||||
return successMessage(null, "全部图片去除水印完成", "ReverseBook_RemoveWatermark")
|
if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
return successMessage(bookTaskDetails[0].oldImage + '?t=' + new Date().getTime(), "去除水印完成", "ReverseBook_RemoveWatermark")
|
||||||
|
} else {
|
||||||
|
return successMessage(null, "全部图片去除水印完成", "ReverseBook_RemoveWatermark")
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("去除水印失败,错误信息如下:" + error.message, "ReverseBook_RemoveWatermark")
|
return errorMessage("去除水印失败,错误信息如下:" + error.message, "ReverseBook_RemoveWatermark")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,20 @@ import axios from 'axios'
|
|||||||
import { ServiceBase } from '../../define/db/service/serviceBase'
|
import { ServiceBase } from '../../define/db/service/serviceBase'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { ValidateJson } from '../../define/Tools/validate'
|
import { ValidateJson } from '../../define/Tools/validate'
|
||||||
|
import { SyncGptKeyType } from '../../define/enum/softwareEnum'
|
||||||
|
import { GeneralResponse } from '../../model/generalResponse'
|
||||||
|
import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic'
|
||||||
|
import { SubtitleService } from '../Service/Subtitle/subtitleService'
|
||||||
|
import { SubtitleModel } from '../../model/subtitle'
|
||||||
|
|
||||||
export class GptSetting extends ServiceBase {
|
export class GptSetting extends ServiceBase {
|
||||||
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
|
subtitleService: SubtitleService
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
axios.defaults.baseURL = define.serverUrl
|
axios.defaults.baseURL = define.serverUrl
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic();
|
||||||
|
this.subtitleService = new SubtitleService()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,4 +114,19 @@ export class GptSetting extends ServiceBase {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步GPT的Key到其他的设置中
|
||||||
|
* @param syncTpye
|
||||||
|
*/
|
||||||
|
async SyncGptKey(syncTpye: SyncGptKeyType): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
|
try {
|
||||||
|
let globalGptKey = global.config.gpt_key;
|
||||||
|
console.log(globalGptKey);
|
||||||
|
return successMessage(globalGptKey, '获取全局配置成功', 'GptSetting_SyncGptKey')
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("同步GPT的Key到其他的设置中失败,失败信息如下:" + error.toString(), "GptSetting_SyncGptKey")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/model/Setting/softwareSetting.d.ts
vendored
Normal file
17
src/model/Setting/softwareSetting.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
declare namespace SoftwareSettingModel {
|
||||||
|
type SoftwareSetting = {
|
||||||
|
id?: string
|
||||||
|
theme?: SoftwareThemeType
|
||||||
|
reverse_display_show?: boolean
|
||||||
|
reverse_show_book_striped?: boolean
|
||||||
|
reverse_data_table_size?: ComponentSize
|
||||||
|
globalSetting?: string
|
||||||
|
ttsSetting?: string
|
||||||
|
writeSetting?: string
|
||||||
|
aiSetting?: string
|
||||||
|
watermarkSetting?: string
|
||||||
|
translationSetting?: string
|
||||||
|
subtitleSetting?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/model/book.d.ts
vendored
16
src/model/book.d.ts
vendored
@ -30,6 +30,22 @@ declare namespace Book {
|
|||||||
suffixPrompt?: string | null // 后缀
|
suffixPrompt?: string | null // 后缀
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BookBackTaskList = {
|
||||||
|
id?: string
|
||||||
|
bookId?: string
|
||||||
|
bookTaskId?: string
|
||||||
|
bookTaskDetailId?: string
|
||||||
|
name?: string // 任务名称,小说名+批次名+分镜名
|
||||||
|
type?: BookBackTaskType
|
||||||
|
status?: BookBackTaskStatus
|
||||||
|
errorMessage?: string
|
||||||
|
executeType?: TaskExecuteType // 任务执行类型,手动还是自动
|
||||||
|
createTime?: Date
|
||||||
|
updateTime?: Date
|
||||||
|
startTime?: number
|
||||||
|
endTime?: number
|
||||||
|
}
|
||||||
|
|
||||||
type SelectBookTask = {
|
type SelectBookTask = {
|
||||||
no?: number,
|
no?: number,
|
||||||
id?: string,
|
id?: string,
|
||||||
|
|||||||
7
src/model/generalResponse.d.ts
vendored
7
src/model/generalResponse.d.ts
vendored
@ -21,6 +21,11 @@ declare namespace GeneralResponse {
|
|||||||
current: number, // 当前进度
|
current: number, // 当前进度
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SubtitleProgressResponse = {
|
||||||
|
content: string, // 文案内容
|
||||||
|
progress: ProgressResponse
|
||||||
|
}
|
||||||
|
|
||||||
// 主线程主动返回前端的消息类
|
// 主线程主动返回前端的消息类
|
||||||
type MessageResponse = {
|
type MessageResponse = {
|
||||||
code: number,
|
code: number,
|
||||||
@ -28,6 +33,6 @@ declare namespace GeneralResponse {
|
|||||||
type: ResponseMessageType,
|
type: ResponseMessageType,
|
||||||
dialogType?: DialogType = DialogType.MESSAGE,
|
dialogType?: DialogType = DialogType.MESSAGE,
|
||||||
message?: string,
|
message?: string,
|
||||||
data?: MJ.MJResponseToFront | Buffer | string | TranslateModel.TranslateResponseMessageModel | ProgressResponse
|
data?: MJ.MJResponseToFront | Buffer | string | TranslateModel.TranslateResponseMessageModel | ProgressResponse | SubtitleProgressResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/model/subtitle.d.ts
vendored
Normal file
13
src/model/subtitle.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { GetSubtitleType } from "../define/enum/waterMarkAndSubtitle"
|
||||||
|
|
||||||
|
declare namespace SubtitleModel {
|
||||||
|
type subtitleSettingModel = {
|
||||||
|
selectModel: GetSubtitleType,
|
||||||
|
laiWhisper: {
|
||||||
|
url: string,
|
||||||
|
apiKey: string,
|
||||||
|
syncGPTAPIKey: boolean,
|
||||||
|
prompt: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,7 +51,7 @@ const book = {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 一键反推的单个任务
|
//#region 分镜
|
||||||
|
|
||||||
// 开始计算分镜数据
|
// 开始计算分镜数据
|
||||||
ComputeStoryboard: async (bookId) =>
|
ComputeStoryboard: async (bookId) =>
|
||||||
@ -60,17 +60,57 @@ const book = {
|
|||||||
// 开始执行分镜,切分视频
|
// 开始执行分镜,切分视频
|
||||||
Framing: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.FRAMING, bookId),
|
Framing: async (bookId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.FRAMING, bookId),
|
||||||
|
|
||||||
|
// 替换指定的分镜的视频的当前帧
|
||||||
|
ReplaceVideoCurrentFrame: async (bookTaskDetailId, currentTime) =>
|
||||||
|
await ipcRenderer.invoke(
|
||||||
|
DEFINE_STRING.BOOK.REPLACE_VIDEO_CURRENT_FRAME,
|
||||||
|
bookTaskDetailId,
|
||||||
|
currentTime
|
||||||
|
),
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 文案相关信息
|
||||||
|
|
||||||
// 获取文案信息
|
// 获取文案信息
|
||||||
GetCopywriting: async (bookId, bookTaskId) =>
|
GetCopywriting: async (bookId, bookTaskId, operateBookType) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.GET_COPYWRITING, bookId, bookTaskId),
|
await ipcRenderer.invoke(
|
||||||
|
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
||||||
|
bookId,
|
||||||
|
bookTaskId,
|
||||||
|
operateBookType
|
||||||
|
),
|
||||||
|
|
||||||
|
// 将文案信息导出,方便修改
|
||||||
|
ExportCopywriting: async (bookTaskId) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.EXPORT_COPYWRITING, bookTaskId),
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 水印
|
||||||
|
|
||||||
// 去除所有水印
|
// 去除所有水印
|
||||||
RemoveWatermark: async (id,operateBookType) =>
|
RemoveWatermark: async (id, operateBookType) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_WATERMARK, id,operateBookType),
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_WATERMARK, id, operateBookType),
|
||||||
|
|
||||||
// 添加单句推理的
|
//#endregion
|
||||||
AddReversePrompt: async (bookTaskDetailIds, type) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT, bookTaskDetailIds, type),
|
//#region 提示词
|
||||||
|
|
||||||
|
MergePrompt: async (id, type, operateBookType) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.MERGE_PROMPT, id, type, operateBookType),
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 一键反推的单个任务
|
||||||
|
|
||||||
|
// 添加单句反推的
|
||||||
|
AddReversePrompt: async (bookTaskDetailIds, operateBookType, type) =>
|
||||||
|
await ipcRenderer.invoke(
|
||||||
|
DEFINE_STRING.BOOK.ADD_REVERSE_PROMPT,
|
||||||
|
bookTaskDetailIds,
|
||||||
|
operateBookType,
|
||||||
|
type
|
||||||
|
),
|
||||||
|
|
||||||
// 将反推的数据指定的位置的提示词写入到GPT提示词中
|
// 将反推的数据指定的位置的提示词写入到GPT提示词中
|
||||||
ReversePromptToGptPrompt: async (bookId, bookTaskId, index) =>
|
ReversePromptToGptPrompt: async (bookId, bookTaskId, index) =>
|
||||||
@ -115,6 +155,18 @@ const book = {
|
|||||||
OneToFourBookTask: async (bookTaskId) =>
|
OneToFourBookTask: async (bookTaskId) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK, bookTaskId),
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.ONE_TO_FOUR_BOOK_TASK, bookTaskId),
|
||||||
|
|
||||||
|
//#region 小说相关
|
||||||
|
|
||||||
|
// 重置小说数据
|
||||||
|
ResetBookData: async (bookId) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.RESET_BOOK_DATA, bookId),
|
||||||
|
|
||||||
|
// 删除小说数据
|
||||||
|
DeleteBookData: async (bookId) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.DELETE_BOOK_DATA, bookId),
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 小说批次任务相关
|
//#region 小说批次任务相关
|
||||||
|
|
||||||
// 重置小说批次数据
|
// 重置小说批次数据
|
||||||
@ -142,7 +194,7 @@ const book = {
|
|||||||
HDImage: async (id, scale, operateBookType) =>
|
HDImage: async (id, scale, operateBookType) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.HD_IMAGE, id, scale, operateBookType),
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.HD_IMAGE, id, scale, operateBookType),
|
||||||
|
|
||||||
// 讲小说视频相关的设置添加到小说任务批次
|
// 将小说视频相关的设置添加到小说任务批次
|
||||||
UseBookVideoDataToBookTask: async (id, operateBookType) =>
|
UseBookVideoDataToBookTask: async (id, operateBookType) =>
|
||||||
await ipcRenderer.invoke(
|
await ipcRenderer.invoke(
|
||||||
DEFINE_STRING.BOOK.USE_BOOK_VIDEO_DATA_TO_BOOK_TASK,
|
DEFINE_STRING.BOOK.USE_BOOK_VIDEO_DATA_TO_BOOK_TASK,
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const gpt = {
|
|||||||
return await ipcRenderer.invoke(DEFINE_STRING.GPT.INIT_SERVER_GPT_OPTIONS)
|
return await ipcRenderer.invoke(DEFINE_STRING.GPT.INIT_SERVER_GPT_OPTIONS)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
//#region GPT 设置相关
|
//#region GPT 设置相关
|
||||||
// 获取软件设置里面的GPT设置
|
// 获取软件设置里面的GPT设置
|
||||||
GetAISetting: async () => {
|
GetAISetting: async () => {
|
||||||
@ -17,6 +16,11 @@ const gpt = {
|
|||||||
// 保存软件设置里面的GPT设置
|
// 保存软件设置里面的GPT设置
|
||||||
SaveAISetting: async (data) => {
|
SaveAISetting: async (data) => {
|
||||||
return await ipcRenderer.invoke(DEFINE_STRING.GPT.SAVE_AI_SETTING, data)
|
return await ipcRenderer.invoke(DEFINE_STRING.GPT.SAVE_AI_SETTING, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 同步GPT Key 到指定的设置
|
||||||
|
SyncGptKey: async (syncType) => {
|
||||||
|
return await ipcRenderer.invoke(DEFINE_STRING.GPT.SYNC_GPT_KEY, syncType)
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -69,10 +69,6 @@ const mj = {
|
|||||||
AutoMatchUser: async (value, callback) =>
|
AutoMatchUser: async (value, callback) =>
|
||||||
callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.AUTO_MATCH_USER, value)),
|
callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.AUTO_MATCH_USER, value)),
|
||||||
|
|
||||||
// 合并提示词
|
|
||||||
MergePrompt: async (id, mergeType) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.MJ.MJ_MERGE_PROMPT, id, mergeType),
|
|
||||||
|
|
||||||
// 单个出图
|
// 单个出图
|
||||||
AddMJGenerateImageTask: async (id, operateBookType) =>
|
AddMJGenerateImageTask: async (id, operateBookType) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK, id, operateBookType)
|
await ipcRenderer.invoke(DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK, id, operateBookType)
|
||||||
|
|||||||
@ -9,9 +9,5 @@ const sd = {
|
|||||||
// 文生图,单张
|
// 文生图,单张
|
||||||
txt2img: async (value, callback) =>
|
txt2img: async (value, callback) =>
|
||||||
callback(await ipcRenderer.invoke(DEFINE_STRING.SD.TXT2IMG, value)),
|
callback(await ipcRenderer.invoke(DEFINE_STRING.SD.TXT2IMG, value)),
|
||||||
|
|
||||||
// 合并提示词
|
|
||||||
MergePrompt: async (id, mergeType) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.SD.SD_MERGE_PROMPT, id, mergeType)
|
|
||||||
}
|
}
|
||||||
export { sd }
|
export { sd }
|
||||||
|
|||||||
@ -11,6 +11,18 @@ const write = {
|
|||||||
SaveWriteConfig: async (data) =>
|
SaveWriteConfig: async (data) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.WRITE.SAVE_WRITE_CONFIG, data),
|
await ipcRenderer.invoke(DEFINE_STRING.WRITE.SAVE_WRITE_CONFIG, data),
|
||||||
|
|
||||||
|
// 获取当前的识别字幕设置的数据
|
||||||
|
GetSubtitleSetting: async () =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.WRITE.GET_SUBTITLE_SETTING),
|
||||||
|
|
||||||
|
// 重置识别字幕设置的数据
|
||||||
|
ResetSubtitleSetting: async () =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.WRITE.RESET_SUBTITLE_SETTING),
|
||||||
|
|
||||||
|
// 保存识别字幕设置的数据
|
||||||
|
SaveSubtitleSetting: async (subtitleSetting) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.WRITE.SAVE_SUBTITLE_SETTING, subtitleSetting),
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region AI相关的任务
|
//#region AI相关的任务
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-config-provider
|
<n-spin style="z-index: 1000 !important;" :show="softwareStore.spin.spinning">
|
||||||
:hljs="hljs"
|
<template #description> {{ softwareStore.spin.tip }} </template>
|
||||||
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
|
<n-config-provider
|
||||||
>
|
:hljs="hljs"
|
||||||
<n-message-provider>
|
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
|
||||||
<n-dialog-provider>
|
>
|
||||||
<n-notification-provider>
|
<n-message-provider>
|
||||||
<n-spin style="z-index: 1000;" :show="softwareStore.spin.spinning">
|
<n-dialog-provider>
|
||||||
|
<n-notification-provider>
|
||||||
<RouterView></RouterView>
|
<RouterView></RouterView>
|
||||||
<template #description> {{ softwareStore.spin.tip }} </template>
|
</n-notification-provider>
|
||||||
</n-spin>
|
</n-dialog-provider>
|
||||||
</n-notification-provider>
|
</n-message-provider>
|
||||||
</n-dialog-provider>
|
</n-config-provider>
|
||||||
</n-message-provider>
|
</n-spin>
|
||||||
</n-config-provider>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -7,21 +7,13 @@
|
|||||||
@click="EditBook"
|
@click="EditBook"
|
||||||
>编辑</n-button
|
>编辑</n-button
|
||||||
>
|
>
|
||||||
<n-button
|
|
||||||
:size="softwareStore.softWare.reverse_data_table_size"
|
|
||||||
strong
|
|
||||||
secondary
|
|
||||||
style="margin-left: 5px"
|
|
||||||
type="info"
|
|
||||||
>任务</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
<n-button
|
||||||
:size="softwareStore.softWare.reverse_data_table_size"
|
:size="softwareStore.softWare.reverse_data_table_size"
|
||||||
strong
|
strong
|
||||||
secondary
|
secondary
|
||||||
style="margin-left: 5px"
|
style="margin-left: 5px"
|
||||||
type="warning"
|
type="warning"
|
||||||
@click="EditBook"
|
@click="ResetBookData"
|
||||||
>重置</n-button
|
>重置</n-button
|
||||||
>
|
>
|
||||||
<n-button
|
<n-button
|
||||||
@ -30,58 +22,108 @@
|
|||||||
strong
|
strong
|
||||||
secondary
|
secondary
|
||||||
type="error"
|
type="error"
|
||||||
|
@click="DeleteBookData"
|
||||||
>删除
|
>删除
|
||||||
</n-button>
|
</n-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
|
import { ref, h, toRaw } from 'vue'
|
||||||
import { useMessage, NButton, useDialog } from 'naive-ui'
|
import { useMessage, useDialog, NButton } from 'naive-ui'
|
||||||
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
|
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
|
||||||
import { useSoftwareStore } from '../../../../../stores/software'
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
import { BookType } from '../../../../../define/enum/bookEnum'
|
|
||||||
import AddBook from '../Components/AddBook.vue'
|
import AddBook from '../Components/AddBook.vue'
|
||||||
|
let props = defineProps({
|
||||||
export default defineComponent({
|
book: undefined
|
||||||
components: {
|
|
||||||
NButton
|
|
||||||
},
|
|
||||||
|
|
||||||
props: ['book'],
|
|
||||||
setup(props) {
|
|
||||||
let message = useMessage()
|
|
||||||
let dialog = useDialog()
|
|
||||||
let book = ref(props.book)
|
|
||||||
let reverseManageStore = useReverseManageStore()
|
|
||||||
let softwareStore = useSoftwareStore()
|
|
||||||
|
|
||||||
onMounted(async () => {})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编辑小说数据
|
|
||||||
*/
|
|
||||||
async function EditBook(e) {
|
|
||||||
e.stopPropagation()
|
|
||||||
// 修改选中的数据
|
|
||||||
reverseManageStore.SetSelectBook(toRaw(book.value))
|
|
||||||
// 一个弹窗添加数据
|
|
||||||
let dialogWidth = 600
|
|
||||||
// ImportWordAndSrt
|
|
||||||
dialog.create({
|
|
||||||
showIcon: false,
|
|
||||||
closeOnEsc: false,
|
|
||||||
title: '编辑小说',
|
|
||||||
content: () => h(AddBook, { type: 'edit' }),
|
|
||||||
style: `width : ${dialogWidth}px;`,
|
|
||||||
maskClosable: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
book,
|
|
||||||
reverseManageStore,
|
|
||||||
softwareStore,
|
|
||||||
EditBook
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
let message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
|
let book = ref(props.book)
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑小说数据
|
||||||
|
*/
|
||||||
|
async function EditBook(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
// 修改选中的数据
|
||||||
|
reverseManageStore.SetSelectBook(toRaw(book.value))
|
||||||
|
// 一个弹窗添加数据
|
||||||
|
let dialogWidth = 600
|
||||||
|
// ImportWordAndSrt
|
||||||
|
dialog.create({
|
||||||
|
showIcon: false,
|
||||||
|
closeOnEsc: false,
|
||||||
|
title: '编辑小说',
|
||||||
|
content: () => h(AddBook, { type: 'edit' }),
|
||||||
|
style: `width : ${dialogWidth}px;`,
|
||||||
|
maskClosable: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ResetBookData(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
message.info('重置小说数据 ' + book.value.id)
|
||||||
|
let da = dialog.warning({
|
||||||
|
title: '重置小说数据警告',
|
||||||
|
content:
|
||||||
|
'是否重置小说数据,重置后数据将恢复至新建状态,所有的批次数据和文件数据都会被删除,请确认是否继续!',
|
||||||
|
positiveText: '确认',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
da?.destroy()
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在重置小说数据。。。'
|
||||||
|
let res = await window.book.ResetBookData(book.value.id)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在重新加载小说批次任务数据。。。'
|
||||||
|
// 这边修改还是在哪里修改啊// 加载任务列表
|
||||||
|
let bookTaskRes = await reverseManageStore.GetBookTaskDataFromDB({
|
||||||
|
bookId: book.value.id
|
||||||
|
})
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (bookTaskRes.code == 0) {
|
||||||
|
message.error(bookTaskRes.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('重置小说数据成功')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function DeleteBookData(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
message.info('删除小说数据 ' + book.value.id)
|
||||||
|
let da = dialog.warning({
|
||||||
|
title: '删除小说数据警告',
|
||||||
|
content:
|
||||||
|
'是否删除小说数据,删除后数据将被永久删除,所有的批次数据和文件数据都会被删除,请确认是否继续!',
|
||||||
|
positiveText: '确认',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
da?.destroy()
|
||||||
|
debugger
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在删除小说数据。。。'
|
||||||
|
let res = await window.book.DeleteBookData(book.value.id)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
debugger
|
||||||
|
// 这边直接把数据删除了就行
|
||||||
|
reverseManageStore.bookData = reverseManageStore.bookData.filter(
|
||||||
|
(item) => item.id != book.value.id
|
||||||
|
)
|
||||||
|
message.success('删除小说数据成功')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -34,14 +34,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
|
import { ref, onMounted, defineComponent, h } from 'vue'
|
||||||
import { useMessage, NButton, useDialog } from 'naive-ui'
|
import { useMessage, NButton, useDialog } from 'naive-ui'
|
||||||
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
|
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
|
||||||
import { useSoftwareStore } from '../../../../../stores/software'
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
import { BookType, OperateBookType } from '../../../../../define/enum/bookEnum'
|
import { BookType, OperateBookType } from '../../../../../define/enum/bookEnum'
|
||||||
import AddBook from '../Components/AddBook.vue'
|
|
||||||
import { DEFINE_STRING } from '../../../../../define/define_string'
|
|
||||||
import { ResponseMessageType } from '../../../../../define/enum/softwareEnum'
|
|
||||||
import ManageBookTaskGenerateInformation from './ManageBookTaskGenerateInformation.vue'
|
import ManageBookTaskGenerateInformation from './ManageBookTaskGenerateInformation.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -51,9 +48,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
props: ['bookTask'],
|
props: ['bookTask'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
debugger
|
||||||
let message = useMessage()
|
let message = useMessage()
|
||||||
let dialog = useDialog()
|
let dialog = useDialog()
|
||||||
let bookTask = ref(props.bookTask)
|
let bookTask = ref(props.bookTask)
|
||||||
|
console.log('bookTask', bookTask.value)
|
||||||
let reverseManageStore = useReverseManageStore()
|
let reverseManageStore = useReverseManageStore()
|
||||||
let softwareStore = useSoftwareStore()
|
let softwareStore = useSoftwareStore()
|
||||||
|
|
||||||
@ -172,6 +171,7 @@ export default defineComponent({
|
|||||||
*/
|
*/
|
||||||
async function ClipDraft(e) {
|
async function ClipDraft(e) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
debugger
|
||||||
dialog.info({
|
dialog.info({
|
||||||
closeOnEsc: false,
|
closeOnEsc: false,
|
||||||
title: '生成草稿前检查',
|
title: '生成草稿前检查',
|
||||||
@ -186,7 +186,7 @@ export default defineComponent({
|
|||||||
*/
|
*/
|
||||||
async function GenerateVideo(e) {
|
async function GenerateVideo(e) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
alert('合成视频')
|
message.error('该功能暂不可用')
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -32,6 +32,7 @@ export default defineComponent({
|
|||||||
props: ['initData', 'index'],
|
props: ['initData', 'index'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
let data = ref(props.initData)
|
let data = ref(props.initData)
|
||||||
|
console.log('subValue', data.value)
|
||||||
onMounted(async () => {})
|
onMounted(async () => {})
|
||||||
let show = computed(() => {
|
let show = computed(() => {
|
||||||
debugger
|
debugger
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="position: absolute; top: 0">
|
<div>
|
||||||
<n-dropdown trigger="hover" :options="reverseOptions" @select="ReverseSelect">
|
<n-dropdown trigger="hover" :options="reverseOptions" @select="ReverseSelect">
|
||||||
<n-button size="tiny" :color="softwareStore.SoftColor.BROWN_YELLOW" @click="AddReversePrompt">
|
<n-button size="tiny" :color="softwareStore.SoftColor.BROWN_YELLOW" @click="AddReversePrompt">
|
||||||
单句反推
|
单句反推
|
||||||
@ -15,7 +15,6 @@
|
|||||||
英文 2 中文
|
英文 2 中文
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-dropdown>
|
</n-dropdown>
|
||||||
|
|
||||||
<n-button
|
<n-button
|
||||||
style="margin-left: 5px"
|
style="margin-left: 5px"
|
||||||
size="tiny"
|
size="tiny"
|
||||||
@ -35,6 +34,7 @@ import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
|||||||
import { TranslateType } from '../../../../../define/enum/translate'
|
import { TranslateType } from '../../../../../define/enum/translate'
|
||||||
import { ContainsChineseOrPunctuation } from '../../../../../define/Tools/common'
|
import { ContainsChineseOrPunctuation } from '../../../../../define/Tools/common'
|
||||||
import ReSelectReversePrompt from '../MJReverse/ReSelectReversePrompt.vue'
|
import ReSelectReversePrompt from '../MJReverse/ReSelectReversePrompt.vue'
|
||||||
|
import { OperateBookType } from '../../../../../define/enum/bookEnum'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -53,7 +53,11 @@ export default defineComponent({
|
|||||||
* 单句反推提示词
|
* 单句反推提示词
|
||||||
*/
|
*/
|
||||||
async function AddReversePrompt() {
|
async function AddReversePrompt() {
|
||||||
let res = await window.book.AddReversePrompt([data.value.id], null)
|
let res = await window.book.AddReversePrompt(
|
||||||
|
data.value.id,
|
||||||
|
OperateBookType.BOOKTASKDETAIL,
|
||||||
|
null
|
||||||
|
)
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
message.error(res.message)
|
message.error(res.message)
|
||||||
} else {
|
} else {
|
||||||
@ -63,7 +67,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
async function AddNextReversePrompt() {
|
async function AddNextReversePrompt() {
|
||||||
let res = await window.book.AddReversePrompt(
|
let res = await window.book.AddReversePrompt(
|
||||||
[data.value.id],
|
data.value.id,
|
||||||
|
OperateBookType.UNDERBOOKTASK,
|
||||||
reverseManageStore.selectBook.type
|
reverseManageStore.selectBook.type
|
||||||
)
|
)
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
@ -84,6 +89,7 @@ export default defineComponent({
|
|||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
message.error(res.message)
|
message.error(res.message)
|
||||||
} else {
|
} else {
|
||||||
|
reverseManageStore.selectBookTaskDetail[props.index].gptPrompt = undefined
|
||||||
reverseManageStore.selectBookTaskDetail[props.index].reversePrompt = undefined
|
reverseManageStore.selectBookTaskDetail[props.index].reversePrompt = undefined
|
||||||
message.success('删除反推数据成功')
|
message.success('删除反推数据成功')
|
||||||
}
|
}
|
||||||
@ -110,16 +116,16 @@ export default defineComponent({
|
|||||||
// 处理翻译英文的数据
|
// 处理翻译英文的数据
|
||||||
function TranslateOneParams(from, to) {
|
function TranslateOneParams(from, to) {
|
||||||
let translateData = []
|
let translateData = []
|
||||||
// if (!isEmpty(data.value.prompt)) {
|
if (!isEmpty(data.value.gptPrompt)) {
|
||||||
// translateData.push({
|
translateData.push({
|
||||||
// text: item.prompt,
|
text: data.value.gptPrompt,
|
||||||
// from: from,
|
from: from,
|
||||||
// to: to,
|
to: to,
|
||||||
// type: TranslateType.PROMPT_TRANSLATE,
|
type: TranslateType.GPT_PROMPT_TRANSLATE,
|
||||||
// isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
|
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
|
||||||
// bookTaskDetailId: data.value.id
|
bookTaskDetailId: data.value.id
|
||||||
// })
|
})
|
||||||
// } else {
|
} else {
|
||||||
let reversePrompt = data.value.reversePrompt
|
let reversePrompt = data.value.reversePrompt
|
||||||
if (reversePrompt) {
|
if (reversePrompt) {
|
||||||
reversePrompt.forEach((item) => {
|
reversePrompt.forEach((item) => {
|
||||||
@ -143,7 +149,7 @@ export default defineComponent({
|
|||||||
translateData.push(temp_obj)
|
translateData.push(temp_obj)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
return translateData
|
return translateData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,27 +158,39 @@ export default defineComponent({
|
|||||||
let translateData = []
|
let translateData = []
|
||||||
for (let i = index.value; i < reverseManageStore.selectBookTaskDetail.length; i++) {
|
for (let i = index.value; i < reverseManageStore.selectBookTaskDetail.length; i++) {
|
||||||
const element = reverseManageStore.selectBookTaskDetail[i]
|
const element = reverseManageStore.selectBookTaskDetail[i]
|
||||||
let reversePrompt = element.reversePrompt
|
// 这边判断GPT提示词是不是存在,存在的话翻译GPT提示词
|
||||||
if (reversePrompt) {
|
if (!isEmpty(data.value.gptPrompt)) {
|
||||||
reversePrompt.forEach((item) => {
|
translateData.push({
|
||||||
if (from == 'zh' && to == 'en') {
|
text: element.gptPrompt,
|
||||||
// 判断是不是有中文
|
from: from,
|
||||||
if (!ContainsChineseOrPunctuation(item.promptCN ? item.promptCN : item.prompt)) {
|
to: to,
|
||||||
return
|
type: TranslateType.GPT_PROMPT_TRANSLATE,
|
||||||
}
|
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
|
||||||
}
|
bookTaskDetailId: element.id
|
||||||
|
|
||||||
let temp_obj = {
|
|
||||||
text: item.prompt,
|
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
type: TranslateType.REVERSE_PROMPT_TRANSLATE,
|
|
||||||
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
|
|
||||||
bookTaskDetailId: element.id,
|
|
||||||
reversePromptId: item.id
|
|
||||||
}
|
|
||||||
translateData.push(temp_obj)
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
let reversePrompt = element.reversePrompt
|
||||||
|
if (reversePrompt) {
|
||||||
|
reversePrompt.forEach((item) => {
|
||||||
|
if (from == 'zh' && to == 'en') {
|
||||||
|
// 判断是不是有中文
|
||||||
|
if (!ContainsChineseOrPunctuation(item.promptCN ? item.promptCN : item.prompt)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let temp_obj = {
|
||||||
|
text: item.prompt,
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
type: TranslateType.REVERSE_PROMPT_TRANSLATE,
|
||||||
|
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
|
||||||
|
bookTaskDetailId: element.id,
|
||||||
|
reversePromptId: item.id
|
||||||
|
}
|
||||||
|
translateData.push(temp_obj)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return translateData
|
return translateData
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import { useSoftwareStore } from '../../../../../stores/software'
|
|||||||
import DynamicTagsSelect from '../../Components/DynamicTagsSelect.vue'
|
import DynamicTagsSelect from '../../Components/DynamicTagsSelect.vue'
|
||||||
import { usePromptStore } from '../../../../../stores/prompt'
|
import { usePromptStore } from '../../../../../stores/prompt'
|
||||||
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
import { BookImageCategory, BookType, MergeType } from '../../../../../define/enum/bookEnum'
|
import { BookImageCategory, OperateBookType } from '../../../../../define/enum/bookEnum'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { NDropdown, NPopover, NIcon, NButton, Construct },
|
components: { NDropdown, NPopover, NIcon, NButton, Construct },
|
||||||
@ -110,20 +110,15 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 开始进行合并,调用不同的合并模式
|
// 开始进行合并,调用不同的合并模式
|
||||||
let res = undefined
|
|
||||||
// 合并之前,要确认保存
|
// 合并之前,要确认保存
|
||||||
softwareStore.spin.spinning = true
|
softwareStore.spin.spinning = true
|
||||||
softwareStore.spin.tip = '合并命令中。。。'
|
softwareStore.spin.tip = '合并命令中。。。'
|
||||||
|
|
||||||
if (type == 'mj_merge') {
|
let res = await window.book.MergePrompt(
|
||||||
res = await window.mj.MergePrompt(reverseManageStore.selectBookTask.id, MergeType.BOOKTASK)
|
reverseManageStore.selectBookTask.id,
|
||||||
} else if (type == 'sd_merge') {
|
type,
|
||||||
res = await window.sd.MergePrompt(reverseManageStore.selectBookTask.id, MergeType.BOOKTASK)
|
OperateBookType.BOOKTASK
|
||||||
} else {
|
)
|
||||||
message.error('未知的合并模式')
|
|
||||||
softwareStore.spin.spinning = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这边对返回的数据进行处理
|
// 这边对返回的数据进行处理
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="position: absolute; top: 0">
|
<div>
|
||||||
<n-dropdown trigger="hover" :options="mergeOptions" @select="MergePrompt">
|
<n-dropdown trigger="hover" :options="mergeOptions" @select="MergePrompt">
|
||||||
<n-button
|
<n-button
|
||||||
size="tiny"
|
size="tiny"
|
||||||
@ -37,7 +37,6 @@
|
|||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<n-input
|
<n-input
|
||||||
style="margin-top: 5px"
|
|
||||||
type="textarea"
|
type="textarea"
|
||||||
size="tiny"
|
size="tiny"
|
||||||
@input="InputDebounced"
|
@input="InputDebounced"
|
||||||
@ -51,7 +50,7 @@ import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'v
|
|||||||
import { useMessage, useDialog, NInput, NButton, NDropdown } from 'naive-ui'
|
import { useMessage, useDialog, NInput, NButton, NDropdown } from 'naive-ui'
|
||||||
import { useSoftwareStore } from '../../../../../stores/software'
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
import { MergeType, OperateBookType } from '../../../../../define/enum/bookEnum'
|
import { OperateBookType } from '../../../../../define/enum/bookEnum'
|
||||||
import { BookImageCategory } from '../../../../../define/enum/bookEnum'
|
import { BookImageCategory } from '../../../../../define/enum/bookEnum'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import InputDialogContent from '../../Original/Components/InputDialogContent.vue'
|
import InputDialogContent from '../../Original/Components/InputDialogContent.vue'
|
||||||
@ -81,25 +80,14 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 开始进行合并,调用不同的合并模式
|
// 开始进行合并,调用不同的合并模式
|
||||||
let res = undefined
|
|
||||||
// 合并之前,要确认保存
|
// 合并之前,要确认保存
|
||||||
softwareStore.spin.spinning = true
|
softwareStore.spin.spinning = true
|
||||||
softwareStore.spin.tip = '合并命令中。。。'
|
softwareStore.spin.tip = '合并命令中。。。'
|
||||||
|
let res = await window.book.MergePrompt(data.value.id, type, OperateBookType.BOOKTASKDETAIL)
|
||||||
if (type == 'mj_merge') {
|
softwareStore.spin.spinning = false
|
||||||
res = await window.mj.MergePrompt(data.value.id, MergeType.BOOKTASKDETAIL)
|
|
||||||
} else if (type == 'sd_merge') {
|
|
||||||
res = await window.sd.MergePrompt(data.value.id, MergeType.BOOKTASKDETAIL)
|
|
||||||
} else {
|
|
||||||
message.error('未知的合并模式')
|
|
||||||
softwareStore.spin.spinning = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这边对返回的数据进行处理
|
// 这边对返回的数据进行处理
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
message.error(res.message)
|
message.error(res.message)
|
||||||
softwareStore.spin.spinning = false
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for (let i = 0; i < res.data.length; i++) {
|
for (let i = 0; i < res.data.length; i++) {
|
||||||
@ -110,7 +98,6 @@ export default defineComponent({
|
|||||||
reverseManageStore.selectBookTaskDetail[selectBookDetailIndex].prompt = element.prompt
|
reverseManageStore.selectBookTaskDetail[selectBookDetailIndex].prompt = element.prompt
|
||||||
}
|
}
|
||||||
message.success(res.message)
|
message.success(res.message)
|
||||||
softwareStore.spin.spinning = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单个出图
|
// 单个出图
|
||||||
@ -169,7 +156,7 @@ export default defineComponent({
|
|||||||
// 处理数据。获取当前的所有的数据
|
// 处理数据。获取当前的所有的数据
|
||||||
let dialogWidth = 400
|
let dialogWidth = 400
|
||||||
let dialogHeight = 150
|
let dialogHeight = 150
|
||||||
dialog.create({
|
let da = dialog.create({
|
||||||
title: '添加图片链接/本地地址',
|
title: '添加图片链接/本地地址',
|
||||||
showIcon: false,
|
showIcon: false,
|
||||||
closeOnEsc: false,
|
closeOnEsc: false,
|
||||||
@ -182,9 +169,12 @@ export default defineComponent({
|
|||||||
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
||||||
maskClosable: false,
|
maskClosable: false,
|
||||||
onClose: async () => {
|
onClose: async () => {
|
||||||
|
da?.destroy()
|
||||||
let row_image_url = image_url_ref.value.data
|
let row_image_url = image_url_ref.value.data
|
||||||
alert(row_image_url)
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在下载图片/分割图片中。。。'
|
||||||
let res = await window.book.DownloadImageUrlAndSplit(data.value.id, row_image_url)
|
let res = await window.book.DownloadImageUrlAndSplit(data.value.id, row_image_url)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
message.error(res.message)
|
message.error(res.message)
|
||||||
return
|
return
|
||||||
@ -192,24 +182,6 @@ export default defineComponent({
|
|||||||
data.value.outImagePath = res.data.outImagePath
|
data.value.outImagePath = res.data.outImagePath
|
||||||
data.value.subImagePath = res.data.subImagePath
|
data.value.subImagePath = res.data.subImagePath
|
||||||
message.success(res.message)
|
message.success(res.message)
|
||||||
|
|
||||||
// 下载指定的图片地址并且分割
|
|
||||||
// await window.mj.DownloadImageUrlAndSplit(
|
|
||||||
// JSON.stringify([toRaw(row.value), row_image_url]),
|
|
||||||
// (value) => {
|
|
||||||
// if (value.code == 0) {
|
|
||||||
// message.error(value.message)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// // 更新当前的数据
|
|
||||||
// row.value.outImagePath = value.data.outImagePath
|
|
||||||
// row.value.subImagePath = value.data.subImagePath
|
|
||||||
// row.value.mj_message = value.data.mj_message ? value.data.mj_message : {}
|
|
||||||
// row.value.mj_message.image_click = value.data.image_click
|
|
||||||
// row.value.mj_message.image_path = value.data.image_path
|
|
||||||
// row.value.mj_message.progress = 100
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div class="artplayer-app" style="height: 100%">
|
||||||
|
<Artplayer ref="art" id="art-player" @get-instance="getInstance" :option="option" :style="palyarStyle" />
|
||||||
|
<div style="margin-top: 20px; display: flex; justify-content: center">
|
||||||
|
<n-button :loading="loading" type="info" @click="ReplaceFrame"> 替换为当前帧 </n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useMessage, useDialog, NButton } from 'naive-ui'
|
||||||
|
import Artplayer from '../../Components/Artplayer.vue'
|
||||||
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
|
let message = useMessage()
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
|
||||||
|
let props = defineProps({
|
||||||
|
videoPath: undefined,
|
||||||
|
type: undefined,
|
||||||
|
id: undefined
|
||||||
|
})
|
||||||
|
let videoPath = ref(props.videoPath)
|
||||||
|
let id = ref(props.id)
|
||||||
|
let art = ref(null)
|
||||||
|
let loading = ref(false)
|
||||||
|
|
||||||
|
function getInstance(art) {}
|
||||||
|
|
||||||
|
async function ReplaceFrame() {
|
||||||
|
let artInstance = art.value.instance
|
||||||
|
message.success(artInstance.currentTime)
|
||||||
|
|
||||||
|
let currentTime = artInstance.currentTime
|
||||||
|
loading.value = true
|
||||||
|
let res = await window.book.ReplaceVideoCurrentFrame(id.value, currentTime * 1000)
|
||||||
|
loading.value = false
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
// 将返回的数据写回
|
||||||
|
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == id.value)
|
||||||
|
if (index < 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reverseManageStore.selectBookTaskDetail[index].oldImage = res.data
|
||||||
|
message.success('替换视频帧成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {}
|
||||||
|
let palyarStyle = {
|
||||||
|
width: '600px',
|
||||||
|
height: '600px',
|
||||||
|
margin: '0 auto'
|
||||||
|
}
|
||||||
|
let option = {
|
||||||
|
container: '.artplayer-app',
|
||||||
|
id: id.value,
|
||||||
|
url: videoPath.value,
|
||||||
|
playbackRate: true,
|
||||||
|
aspectRatio: true,
|
||||||
|
mutex: true,
|
||||||
|
setting: true,
|
||||||
|
hotkey: true,
|
||||||
|
autoSize: true,
|
||||||
|
fullscreen: true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -134,10 +134,12 @@ export default defineComponent({
|
|||||||
code.value = code.value + '\n' + value.data
|
code.value = code.value + '\n' + value.data
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 修改进度
|
||||||
|
softwareStore.spin.tip = `正在提取文案,当前进度 ${value.data.progress.current} / ${value.data.progress.total} 。。。`
|
||||||
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == value.id)
|
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == value.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
reverseManageStore.selectBookTaskDetail[index].word = value.data
|
reverseManageStore.selectBookTaskDetail[index].word = value.data.content
|
||||||
reverseManageStore.selectBookTaskDetail[index].afterGpt = value.data
|
reverseManageStore.selectBookTaskDetail[index].afterGpt = value.data.content
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -251,18 +253,39 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let copywriting_res = await window.book.GetCopywriting(reverseManageStore.selectBook.id)
|
let subtitleSettingRes = await window.write.GetSubtitleSetting()
|
||||||
if (copywriting_res.code == 0) {
|
if (subtitleSettingRes.code == 0) {
|
||||||
message.error(copywriting_res.message)
|
message.error(subtitleSettingRes.message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message.success('获取文案成功')
|
|
||||||
|
let da = dialog.warning({
|
||||||
|
title: '开始提取文案提示',
|
||||||
|
content: `即将进行文案提取,当前的文案提取模式为 ${subtitleSettingRes.data.selectModel} ,是否继续?`,
|
||||||
|
positiveText: '继续',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
da?.destroy()
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = `正在使用 ${subtitleSettingRes.data.selectModel} 提取文案,正在准备中。。。`
|
||||||
|
let copywriting_res = await window.book.GetCopywriting(
|
||||||
|
reverseManageStore.selectBook.id,
|
||||||
|
reverseManageStore.selectBookTask.id,
|
||||||
|
OperateBookType.BOOKTASK
|
||||||
|
)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (copywriting_res.code == 0) {
|
||||||
|
message.error(copywriting_res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// dialog.success({})
|
||||||
|
message.success('获取全部文案成功')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始去除水印
|
// 开始去除水印
|
||||||
async function RemoveWatermark() {
|
async function RemoveWatermark() {
|
||||||
// softwareStore.spin.spinning = true
|
|
||||||
// softwareStore.spin.tip = '正在去除水印中'
|
|
||||||
if (isEmpty(reverseManageStore.selectBookTask.id)) {
|
if (isEmpty(reverseManageStore.selectBookTask.id)) {
|
||||||
window.api.showGlobalMessageDialog({
|
window.api.showGlobalMessageDialog({
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -270,12 +293,23 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let res_frame = await window.book.RemoveWatermark(
|
let da = dialog.warning({
|
||||||
reverseManageStore.selectBookTask.id,
|
title: '去除水印提示',
|
||||||
OperateBookType.BOOKTASK
|
content: '即将去除全部水印,是否继续?',
|
||||||
)
|
positiveText: '继续',
|
||||||
softwareStore.spin.spinning = false
|
negativeText: '取消',
|
||||||
window.api.showGlobalMessageDialog(res_frame)
|
onPositiveClick: async () => {
|
||||||
|
da?.destroy()
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在去除水印中。。。'
|
||||||
|
let res_frame = await window.book.RemoveWatermark(
|
||||||
|
reverseManageStore.selectBookTask.id,
|
||||||
|
OperateBookType.BOOKTASK
|
||||||
|
)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
window.api.showGlobalMessageDialog(res_frame)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文案信息设置
|
// 获取文案信息设置
|
||||||
@ -297,6 +331,28 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出文案
|
||||||
|
async function ExportCopywriting() {
|
||||||
|
debugger
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '正在导出文案中...'
|
||||||
|
let res = await window.book.ExportCopywriting(reverseManageStore.selectBookTask.id)
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
dialog.success({
|
||||||
|
title: '导出文案成功',
|
||||||
|
content: '导出文案成功,是否打开导出的字幕文件',
|
||||||
|
positiveText: '打开',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
window.system.OpenFile(res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取水印位置
|
* 获取水印位置
|
||||||
*/
|
*/
|
||||||
@ -329,6 +385,9 @@ export default defineComponent({
|
|||||||
case 'recognizing_setting': // 文案位置设置
|
case 'recognizing_setting': // 文案位置设置
|
||||||
await GetCopywritingSetting()
|
await GetCopywritingSetting()
|
||||||
break
|
break
|
||||||
|
case 'export_recognizing': // 导出文案
|
||||||
|
await ExportCopywriting()
|
||||||
|
break
|
||||||
case 'watermark_position': // 水印位置设置
|
case 'watermark_position': // 水印位置设置
|
||||||
await GetWatermarkPosition()
|
await GetWatermarkPosition()
|
||||||
break
|
break
|
||||||
@ -376,7 +435,6 @@ export default defineComponent({
|
|||||||
* @param type 反推类型
|
* @param type 反推类型
|
||||||
*/
|
*/
|
||||||
async function ImageReversePrompt(type = undefined) {
|
async function ImageReversePrompt(type = undefined) {
|
||||||
debugger
|
|
||||||
if (isEmpty(reverseManageStore.selectBookTask.id)) {
|
if (isEmpty(reverseManageStore.selectBookTask.id)) {
|
||||||
window.api.showGlobalMessageDialog({
|
window.api.showGlobalMessageDialog({
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -384,32 +442,36 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
dialog.warning({
|
||||||
|
title: '反推提示',
|
||||||
|
content: `即将进行反推操作,反推方式为 ${
|
||||||
|
type ? type : reverseManageStore.selectBook.type
|
||||||
|
} ,是否继续?`,
|
||||||
|
positiveText: '继续',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
if (!type) {
|
||||||
|
let bookType = reverseManageStore.selectBook.type
|
||||||
|
type = bookType
|
||||||
|
}
|
||||||
|
|
||||||
if (!type) {
|
if (type != BookType.MJ_REVERSE && type != BookType.SD_REVERSE) {
|
||||||
let bookType = reverseManageStore.selectBook.type
|
message.error(`该类型 ${bookType} 的小说不支持反推`)
|
||||||
type = bookType
|
return
|
||||||
}
|
}
|
||||||
|
// 开始添加
|
||||||
if (type != BookType.MJ_REVERSE && type != BookType.SD_REVERSE) {
|
let res = await window.book.AddReversePrompt(
|
||||||
message.error(`该类型 ${bookType} 的小说不支持反推`)
|
reverseManageStore.selectBookTask.id,
|
||||||
return
|
OperateBookType.BOOKTASK,
|
||||||
}
|
type
|
||||||
let reverseIds = []
|
)
|
||||||
// 开始获取需要反推的数据
|
if (res.code == 0) {
|
||||||
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
|
message.error(res.message)
|
||||||
const element = reverseManageStore.selectBookTaskDetail[i]
|
} else {
|
||||||
if (!element.reversePrompt || element.reversePrompt.length <= 0) {
|
message.success('添加所有反推任务成功')
|
||||||
reverseIds.push(element.id)
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
// 开始添加
|
|
||||||
let res = await window.book.AddReversePrompt(reverseIds, type)
|
|
||||||
if (res.code == 0) {
|
|
||||||
message.error(res.message)
|
|
||||||
} else {
|
|
||||||
message.success('添加所有反推任务成功')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -417,13 +479,16 @@ export default defineComponent({
|
|||||||
*/
|
*/
|
||||||
async function RemoveReverseData(id) {
|
async function RemoveReverseData(id) {
|
||||||
let deleteIds = []
|
let deleteIds = []
|
||||||
|
if (id == undefined) {
|
||||||
// 删除全部的
|
// 删除全部的
|
||||||
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
|
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
|
||||||
const element = reverseManageStore.selectBookTaskDetail[i]
|
const element = reverseManageStore.selectBookTaskDetail[i]
|
||||||
if (element.reversePrompt && element.reversePrompt.length > 0) {
|
if (element.reversePrompt && element.reversePrompt.length > 0) {
|
||||||
deleteIds.push(element.id)
|
deleteIds.push(element.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
deleteIds.push(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await window.book.RemoveReverseData(deleteIds)
|
let res = await window.book.RemoveReverseData(deleteIds)
|
||||||
@ -643,6 +708,10 @@ export default defineComponent({
|
|||||||
label: '提取文案位置',
|
label: '提取文案位置',
|
||||||
key: 'recognizing_setting'
|
key: 'recognizing_setting'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '导出文案',
|
||||||
|
key: 'export_recognizing'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '停止提取',
|
label: '停止提取',
|
||||||
key: 'stop_recognizing'
|
key: 'stop_recognizing'
|
||||||
@ -665,7 +734,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SD反推',
|
label: 'SD反推',
|
||||||
key: 'sd_reverse'
|
key: 'sd_reverse',
|
||||||
|
disabled: reverseManageStore.selectBook.type != BookType.SD_REVERSE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '清除反推数据',
|
label: '清除反推数据',
|
||||||
|
|||||||
@ -1,28 +1,107 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="position: absolute; top: 0">
|
<div style="margin-bottom: 2px">
|
||||||
<!-- <n-button size="tiny">123</n-button> -->
|
<n-button :color="softwareStore.SoftColor.BROWN_YELLOW" size="tiny" @click="OpenGetVideoFrame"
|
||||||
|
>抽帧</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
style="margin-left: 2px"
|
||||||
|
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||||
|
size="tiny"
|
||||||
|
@click="GetVideoSubtitle"
|
||||||
|
>文案</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
style="margin-left: 2px"
|
||||||
|
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||||
|
size="tiny"
|
||||||
|
@click="RemoveImageWatermark"
|
||||||
|
>水印</n-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<n-image v-if="data.oldImage" width="110" :src="data.oldImage"> </n-image>
|
<n-image v-if="data.oldImage" width="112" :src="data.oldImage"> </n-image>
|
||||||
<video v-else-if="data.data.videoPath" width="110" controls>
|
<video v-else-if="data.videoPath" width="110" controls>
|
||||||
<source :src="data.videoPath" type="video/mp4" />
|
<source :src="data.videoPath" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
|
import { ref, onMounted, h } from 'vue'
|
||||||
import { useMessage, NImage, NButton } from 'naive-ui'
|
import { useMessage, useDialog, NImage, NButton } from 'naive-ui'
|
||||||
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
|
import { OperateBookType } from '../../../../../define/enum/bookEnum'
|
||||||
|
import GetVideoFrame from './GetVideoFrame.vue'
|
||||||
|
let message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
|
||||||
export default defineComponent({
|
let props = defineProps({
|
||||||
components: { NImage, NButton },
|
initData: undefined,
|
||||||
props: ['initData', 'index'],
|
index: undefined
|
||||||
setup(props) {
|
|
||||||
let message = useMessage()
|
|
||||||
let data = ref(props.initData)
|
|
||||||
onMounted(async () => {})
|
|
||||||
|
|
||||||
return {
|
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
let data = ref(props.initData)
|
||||||
|
let index = ref(props.index)
|
||||||
|
onMounted(async () => {})
|
||||||
|
|
||||||
|
// 重新对当前视频进行抽帧
|
||||||
|
async function OpenGetVideoFrame() {
|
||||||
|
// 判断的分镜中的视频是否存在
|
||||||
|
if (!data.value.videoPath) {
|
||||||
|
message.error('当前分镜没有视频')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dialog.create({
|
||||||
|
title: '获取视频的帧',
|
||||||
|
style: 'width : 800px;',
|
||||||
|
content: () =>
|
||||||
|
h(GetVideoFrame, {
|
||||||
|
videoPath: data.value.videoPath,
|
||||||
|
id: data.value.id,
|
||||||
|
type: OperateBookType.BOOKTASKDETAIL
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前视频的片段的文案
|
||||||
|
async function GetVideoSubtitle() {
|
||||||
|
// alert(data.value.id)
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = `获取分镜 ${data.value.name} 文案中。。。`
|
||||||
|
let res = await window.book.GetCopywriting(
|
||||||
|
reverseManageStore.selectBook.id,
|
||||||
|
data.value.id,
|
||||||
|
OperateBookType.BOOKTASKDETAIL
|
||||||
|
)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
// 修改指定的数据
|
||||||
|
reverseManageStore.selectBookTaskDetail[index.value].afterGpt = res.data
|
||||||
|
reverseManageStore.selectBookTaskDetail[index.value].word = res.data
|
||||||
|
message.success('获取视频文案成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去除当前分镜文案的水印
|
||||||
|
async function RemoveImageWatermark() {
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = `去除分镜 ${data.value.name} 水印中。。。`
|
||||||
|
let res = await window.book.RemoveWatermark(data.value.id, OperateBookType.BOOKTASKDETAIL)
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
// 修改指定的数据
|
||||||
|
let index = reverseManageStore.selectBookTaskDetail.findIndex(
|
||||||
|
(item) => item.id == data.value.id
|
||||||
|
)
|
||||||
|
if (index < 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reverseManageStore.selectBookTaskDetail[index].oldImage = res.data
|
||||||
|
message.success(`${data.value.name} 去除水印成功`)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item path="backgroundMusic">
|
<n-form-item path="backgroundMusic">
|
||||||
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask">{{
|
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask">{{
|
||||||
type == 'bookTsk' ? '应用主小说相关数据' : '当前就是用的主小说的数据'
|
type == bookTask ? '应用主小说相关数据' : '当前就是用的主小说的数据'
|
||||||
}}</n-button>
|
}}</n-button>
|
||||||
<n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button>
|
<n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@ -73,6 +73,7 @@ export default defineComponent({
|
|||||||
props: ['bookTask', 'type'],
|
props: ['bookTask', 'type'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
let bookTask = ref(props.bookTask)
|
let bookTask = ref(props.bookTask)
|
||||||
|
debugger
|
||||||
let type = ref(props.type)
|
let type = ref(props.type)
|
||||||
let backgroundMusicOptions = ref([])
|
let backgroundMusicOptions = ref([])
|
||||||
let message = useMessage()
|
let message = useMessage()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin-bottom: 7px">
|
<div>
|
||||||
<DatatableGptPromptButton :initData="data" :index="index" />
|
<DatatableGptPromptButton :initData="data" :index="index" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data.gptPrompt">
|
<div v-if="data.gptPrompt">
|
||||||
@ -15,11 +15,22 @@
|
|||||||
>
|
>
|
||||||
</n-input>
|
</n-input>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="show-gpt-prompt">
|
<div v-else-if="data.reversePrompt && data.reversePrompt.length > 0" class="show-gpt-prompt">
|
||||||
<div v-for="(item, index) in showReversePrompt" :key="index" style="margin-bottom: 5px">
|
<div v-for="(item, index) in showReversePrompt" :key="index" style="margin-bottom: 5px">
|
||||||
<n-input v-model:value="item.prompt" type="text" size="tiny"> </n-input>
|
<n-input v-model:value="item.prompt" type="text" size="tiny"> </n-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<n-input
|
||||||
|
v-else
|
||||||
|
type="textarea"
|
||||||
|
size="tiny"
|
||||||
|
v-model:value="data.gptPrompt"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 6,
|
||||||
|
maxRows: 6
|
||||||
|
}"
|
||||||
|
@input="InputDebounced"
|
||||||
|
></n-input>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -42,7 +53,7 @@ export default defineComponent({
|
|||||||
let showReversePrompt = computed(() => {
|
let showReversePrompt = computed(() => {
|
||||||
debugger
|
debugger
|
||||||
let res = []
|
let res = []
|
||||||
for (let i = 0; i < data.value.reversePrompt.length; i++) {
|
for (let i = 0; i < data.value.reversePrompt?.length; i++) {
|
||||||
let item = data.value.reversePrompt[i]
|
let item = data.value.reversePrompt[i]
|
||||||
let res_obj = {
|
let res_obj = {
|
||||||
...item
|
...item
|
||||||
|
|||||||
@ -106,6 +106,7 @@ export default defineComponent({
|
|||||||
return h(DatatableHeaderImage)
|
return h(DatatableHeaderImage)
|
||||||
},
|
},
|
||||||
width: 300,
|
width: 300,
|
||||||
|
className: 'space-row',
|
||||||
render(row, index) {
|
render(row, index) {
|
||||||
return h(DataTableShowGenerateImage, {
|
return h(DataTableShowGenerateImage, {
|
||||||
image_generate_category: 'mj',
|
image_generate_category: 'mj',
|
||||||
@ -126,7 +127,6 @@ export default defineComponent({
|
|||||||
let div = document.getElementsByClassName('space-row')
|
let div = document.getElementsByClassName('space-row')
|
||||||
for (let i = 0; i < div.length; i++) {
|
for (let i = 0; i < div.length; i++) {
|
||||||
div[i].style.padding = '0px 5px'
|
div[i].style.padding = '0px 5px'
|
||||||
div[i].style.position = 'relative'
|
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<n-data-table
|
<n-data-table
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:size="softwareStore.softWare.reverse_data_table_size"
|
:size="softwareStore.softWare.reverse_data_table_size"
|
||||||
:data="data"
|
:data="reverseManageStore.bookData"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:remote="true"
|
:remote="true"
|
||||||
@ -39,7 +39,6 @@ export default defineComponent({
|
|||||||
let message = useMessage()
|
let message = useMessage()
|
||||||
let softwareStore = useSoftwareStore()
|
let softwareStore = useSoftwareStore()
|
||||||
let reverseManageStore = useReverseManageStore()
|
let reverseManageStore = useReverseManageStore()
|
||||||
let data = computed(() => reverseManageStore.GetBookData())
|
|
||||||
let maxHeight = ref(0)
|
let maxHeight = ref(0)
|
||||||
// 分页设置
|
// 分页设置
|
||||||
const paginationReactive = (() => {
|
const paginationReactive = (() => {
|
||||||
@ -161,7 +160,7 @@ export default defineComponent({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: 310,
|
width: 240,
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render: (row) => {
|
render: (row) => {
|
||||||
return h(BookListAction, { book: row })
|
return h(BookListAction, { book: row })
|
||||||
@ -185,7 +184,6 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
softwareStore,
|
softwareStore,
|
||||||
reverseManageStore,
|
reverseManageStore,
|
||||||
data,
|
|
||||||
pagination,
|
pagination,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
columns: createColumns(),
|
columns: createColumns(),
|
||||||
|
|||||||
@ -66,11 +66,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 执行对应的方法,修改数据
|
// 执行对应的方法,修改数据
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case ResponseMessageType.MJ_REVERSE:
|
case ResponseMessageType.MJ_REVERSE: // MJ反推的数据返回处理
|
||||||
MJReverseResponse(value)
|
MJReverseResponse(value)
|
||||||
break
|
break
|
||||||
case ResponseMessageType.PROMPT_TRANSLATE:
|
case ResponseMessageType.REVERSE_PROMPT_TRANSLATE: // 翻译反推提示词的数据处理
|
||||||
PromptTranslateResponse(value)
|
ReversePromptTranslateResponse(value)
|
||||||
|
break
|
||||||
|
case ResponseMessageType.GPT_PROMPT_TRANSLATE: // GPT提示词翻译返回
|
||||||
|
GptPromptTranslateResponse(value)
|
||||||
break
|
break
|
||||||
case ResponseMessageType.MJ_IMAGE:
|
case ResponseMessageType.MJ_IMAGE:
|
||||||
MJImageResponse(value)
|
MJImageResponse(value)
|
||||||
@ -111,7 +114,7 @@ export default defineComponent({
|
|||||||
* prompt: string // 英文数据
|
* prompt: string // 英文数据
|
||||||
* promptCN: string // 中文翻译数据(但是也可以存储英文)
|
* promptCN: string // 中文翻译数据(但是也可以存储英文)
|
||||||
*/
|
*/
|
||||||
function PromptTranslateResponse(value) {
|
function ReversePromptTranslateResponse(value) {
|
||||||
if (!value.data) {
|
if (!value.data) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -143,15 +146,32 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GptPromptTranslateResponse(value) {
|
||||||
|
console.log('GptPromptTranslateResponse', value)
|
||||||
|
if (!value.data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let index = reverseManageStore.selectBookTaskDetail.findIndex(
|
||||||
|
(item) => item.id == value.data.bookTaskDetailId
|
||||||
|
)
|
||||||
|
if (index < 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reverseManageStore.selectBookTaskDetail[index].gptPrompt = value.data.prompt
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MJ反推返回数据
|
* MJ反推返回数据
|
||||||
*/
|
*/
|
||||||
function MJReverseResponse(value) {
|
function MJReverseResponse(value) {
|
||||||
|
console.log('MJReverseResponse', value)
|
||||||
if (value.data && value.data.progress == 100) {
|
if (value.data && value.data.progress == 100) {
|
||||||
|
debugger
|
||||||
let dataIndex = reverseManageStore.selectBookTaskDetail.findIndex(
|
let dataIndex = reverseManageStore.selectBookTaskDetail.findIndex(
|
||||||
(item) => item.id == value.data.id
|
(item) => item.id == value.data.id
|
||||||
)
|
)
|
||||||
if (dataIndex >= 0) {
|
if (dataIndex >= 0) {
|
||||||
|
reverseManageStore.selectBookTaskDetail[dataIndex].gptPrompt = undefined
|
||||||
reverseManageStore.selectBookTaskDetail[dataIndex].reversePrompt = JSON.parse(
|
reverseManageStore.selectBookTaskDetail[dataIndex].reversePrompt = JSON.parse(
|
||||||
value.data.prompt
|
value.data.prompt
|
||||||
)
|
)
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
|
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
|
||||||
import { useMessage, useDialog, NButton, NDataTable, NIcon } from 'naive-ui'
|
import { useMessage, useDialog, NButton, NDataTable, NIcon, NWatermark } from 'naive-ui'
|
||||||
import { useReverseManageStore } from '../../../../stores/reverseManage'
|
import { useReverseManageStore } from '../../../../stores/reverseManage'
|
||||||
import { useSoftwareStore } from '../../../../stores/software'
|
import { useSoftwareStore } from '../../../../stores/software'
|
||||||
import { AddSharp } from '@vicons/ionicons5'
|
import { AddSharp } from '@vicons/ionicons5'
|
||||||
@ -46,7 +46,8 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
NButton,
|
NButton,
|
||||||
NDataTable,
|
NDataTable,
|
||||||
BookTaskListAction
|
BookTaskListAction,
|
||||||
|
NWatermark
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
@ -103,6 +104,7 @@ export default defineComponent({
|
|||||||
width: 215,
|
width: 215,
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render(row, index) {
|
render(row, index) {
|
||||||
|
debugger
|
||||||
return h(BookTaskListAction, {
|
return h(BookTaskListAction, {
|
||||||
bookTask: row
|
bookTask: row
|
||||||
})
|
})
|
||||||
|
|||||||
@ -89,7 +89,11 @@ export default defineComponent({
|
|||||||
let message = useMessage()
|
let message = useMessage()
|
||||||
let type = ref(props.type)
|
let type = ref(props.type)
|
||||||
let row = ref(props.row)
|
let row = ref(props.row)
|
||||||
let translate_options = ref([{ label: '翻译中文', key: 'chinese' }])
|
let translate_options = ref([
|
||||||
|
{ label: '翻译中文', key: 'chinese' },
|
||||||
|
{ label: '下翻译 英文 2 中文', key: 'down_english_chinese' },
|
||||||
|
{ label: '下翻译 中文 2 英文', key: 'down_chinese_english' }
|
||||||
|
])
|
||||||
|
|
||||||
// 监听数据变化
|
// 监听数据变化
|
||||||
watch(
|
watch(
|
||||||
@ -142,7 +146,6 @@ export default defineComponent({
|
|||||||
message.error('当前翻译的数据里面没有中文')
|
message.error('当前翻译的数据里面没有中文')
|
||||||
}
|
}
|
||||||
} else if (key == 'chinese') {
|
} else if (key == 'chinese') {
|
||||||
|
|
||||||
let t = [[toRaw(row.value)], 'en', 'zh', false, false]
|
let t = [[toRaw(row.value)], 'en', 'zh', false, false]
|
||||||
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
|
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
|
||||||
if (value.code == 0) {
|
if (value.code == 0) {
|
||||||
@ -151,6 +154,14 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
message.success('添加翻译任务成功')
|
message.success('添加翻译任务成功')
|
||||||
})
|
})
|
||||||
|
} else if (key == 'down_english_chinese') {
|
||||||
|
// 下翻译 英文 到 中文
|
||||||
|
props.func.translateAll(key, props.index)
|
||||||
|
} else if (key == 'down_chinese_english') {
|
||||||
|
// 下翻译 中文 到 英文
|
||||||
|
props.func.translateAll(key, props.index)
|
||||||
|
} else {
|
||||||
|
message.error('未知的翻译类型')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -81,8 +81,8 @@
|
|||||||
class="g-image-class generate-image-show"
|
class="g-image-class generate-image-show"
|
||||||
:src="outImagePath ? outImagePath : space_image"
|
:src="outImagePath ? outImagePath : space_image"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
width="120"
|
:width="120"
|
||||||
height="120"
|
:height="120"
|
||||||
lazy
|
lazy
|
||||||
/>
|
/>
|
||||||
<n-button
|
<n-button
|
||||||
@ -107,7 +107,7 @@
|
|||||||
subImage="true"
|
subImage="true"
|
||||||
class="g-image-class"
|
class="g-image-class"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
:width="width"
|
:width="56"
|
||||||
style="margin: 1px"
|
style="margin: 1px"
|
||||||
v-for="(image, index) in images"
|
v-for="(image, index) in images"
|
||||||
:key="image.id"
|
:key="image.id"
|
||||||
@ -330,7 +330,7 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let lock = !data.value.imageLock
|
let lock = !data.value.imageLock
|
||||||
|
|
||||||
if (
|
if (
|
||||||
reverseManageStore.selectBookTaskDetail &&
|
reverseManageStore.selectBookTaskDetail &&
|
||||||
reverseManageStore.selectBookTaskDetail.length > 0
|
reverseManageStore.selectBookTaskDetail.length > 0
|
||||||
|
|||||||
@ -250,6 +250,7 @@ export default defineComponent({
|
|||||||
row: row,
|
row: row,
|
||||||
index: index,
|
index: index,
|
||||||
func: {
|
func: {
|
||||||
|
translateAll: TranslateAll,
|
||||||
nextGptPrompt: NextGptPrompt,
|
nextGptPrompt: NextGptPrompt,
|
||||||
singlePrompt: SinglePrompt
|
singlePrompt: SinglePrompt
|
||||||
}
|
}
|
||||||
@ -848,8 +849,9 @@ export default defineComponent({
|
|||||||
* 翻译传入的数据
|
* 翻译传入的数据
|
||||||
* @param {*} key 翻译的类型
|
* @param {*} key 翻译的类型
|
||||||
*/
|
*/
|
||||||
async function TranslateAll(key) {
|
async function TranslateAll(key, index = -1) {
|
||||||
// 将中文翻译成英文
|
// 将中文翻译成英文
|
||||||
|
debugger
|
||||||
if (key == 'english') {
|
if (key == 'english') {
|
||||||
let tmp_d = []
|
let tmp_d = []
|
||||||
for (let i = 0; i < data.value.length; i++) {
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
@ -877,6 +879,45 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
message.success('添加翻译任务成功')
|
message.success('添加翻译任务成功')
|
||||||
})
|
})
|
||||||
|
} else if (key == 'down_english_chinese') {
|
||||||
|
// 下翻译 英文 到 中文
|
||||||
|
// 获取当前下面的所有的数据,
|
||||||
|
let tempData = []
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
const element = cloneDeep(data.value[i])
|
||||||
|
if (index <= i) {
|
||||||
|
tempData.push(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = [tempData, 'en', 'zh', false, false]
|
||||||
|
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('添加翻译任务成功')
|
||||||
|
})
|
||||||
|
} else if (key == 'down_chinese_english') {
|
||||||
|
// 下翻译 中文 到 英文
|
||||||
|
// 获取当前下面的所有的数据
|
||||||
|
let tempData = []
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
const element = cloneDeep(data.value[i])
|
||||||
|
if (index <= i) {
|
||||||
|
tempData.push(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let t = [tempData, 'zh', 'en', false, false]
|
||||||
|
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('添加翻译任务成功')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
message.error('未知的翻译类型')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,6 @@ export default defineComponent({
|
|||||||
for (let i = 0; i < data.value.length; i++) {
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
const item = data.value[i]
|
const item = data.value[i]
|
||||||
await window.api.GetPromptJson(item.name, (value) => {
|
await window.api.GetPromptJson(item.name, (value) => {
|
||||||
console.log(value)
|
|
||||||
if (value.code == 0 && promptError) {
|
if (value.code == 0 && promptError) {
|
||||||
message.error(value.message)
|
message.error(value.message)
|
||||||
promptError = false
|
promptError = false
|
||||||
|
|||||||
@ -35,8 +35,8 @@
|
|||||||
v-model:value="mjSetting.imageScale"
|
v-model:value="mjSetting.imageScale"
|
||||||
></n-select>
|
></n-select>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="image_suffix">
|
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="imageSuffix">
|
||||||
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
|
<n-input v-model:value="mjSetting.imageSuffix" placeholder="请输入后缀命令"></n-input>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="生图任务量" style="width: 100px; margin-left: 10px" path="taskCount">
|
<n-form-item label="生图任务量" style="width: 100px; margin-left: 10px" path="taskCount">
|
||||||
<n-input-number
|
<n-input-number
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<n-input
|
<n-input
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="请输入密钥"
|
placeholder="请输入密钥"
|
||||||
show-password-on="mousedown"
|
show-password-on="mousedown"
|
||||||
v-model:value="mjSetting.apiSetting.apiKey"
|
v-model:value="mjSetting.apiSetting.apiKey"
|
||||||
></n-input>
|
></n-input>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@ -272,7 +272,7 @@ export default defineComponent({
|
|||||||
let request_model_options = ref([])
|
let request_model_options = ref([])
|
||||||
let mj_api_options = ref([])
|
let mj_api_options = ref([])
|
||||||
|
|
||||||
let image_suffix = computed(() => {
|
let computedSuffix = () => {
|
||||||
let text = image_model_options.value.findIndex((item) => {
|
let text = image_model_options.value.findIndex((item) => {
|
||||||
return item.value == mjSetting.value.imageModel
|
return item.value == mjSetting.value.imageModel
|
||||||
})
|
})
|
||||||
@ -285,7 +285,7 @@ export default defineComponent({
|
|||||||
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
|
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
|
||||||
mjSetting.value.imageSuffix = dd
|
mjSetting.value.imageSuffix = dd
|
||||||
return dd
|
return dd
|
||||||
})
|
}
|
||||||
|
|
||||||
// 初始化现在设置的数据
|
// 初始化现在设置的数据
|
||||||
async function InitData() {
|
async function InitData() {
|
||||||
@ -419,7 +419,7 @@ export default defineComponent({
|
|||||||
message.error('请检查必填字段')
|
message.error('请检查必填字段')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mjSetting.value.imageSuffix = image_suffix.value
|
// mjSetting.value.imageSuffix = image_suffix.value
|
||||||
|
|
||||||
// 通过选择的请求模式判断哪些是要校验的
|
// 通过选择的请求模式判断哪些是要校验的
|
||||||
let request_model = mjSetting.value.requestModel
|
let request_model = mjSetting.value.requestModel
|
||||||
@ -500,6 +500,9 @@ export default defineComponent({
|
|||||||
mjSetting.value.imageModel =
|
mjSetting.value.imageModel =
|
||||||
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
|
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新命令后缀
|
||||||
|
mjSetting.value.imageSuffix = computedSuffix()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -546,7 +549,6 @@ export default defineComponent({
|
|||||||
image_scale_options,
|
image_scale_options,
|
||||||
image_model_options,
|
image_model_options,
|
||||||
UpdateSelectRobot,
|
UpdateSelectRobot,
|
||||||
image_suffix,
|
|
||||||
request_model_options,
|
request_model_options,
|
||||||
mj_api_options,
|
mj_api_options,
|
||||||
mj_speed_options,
|
mj_speed_options,
|
||||||
|
|||||||
@ -1,18 +1,182 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>识别文案设置</div>
|
<div style="display: flex; align-items: center; margin-bottom: 10px; margin-top: 10px">
|
||||||
|
<div>选择识别字幕的方式</div>
|
||||||
|
<n-select
|
||||||
|
style="margin-left: 10px; width: 200px"
|
||||||
|
:options="subtitleOptions"
|
||||||
|
v-model:value="subtitleSetting.selectModel"
|
||||||
|
placeholder="选择识别文案方式"
|
||||||
|
/>
|
||||||
|
<n-button style="margin-left: 10px" :type="urlDisabled ? 'warning' : 'info'" @click="UnBlock">{{
|
||||||
|
urlDisabled ? '解锁' : '上锁'
|
||||||
|
}}</n-button>
|
||||||
|
<n-button style="margin-left: 10px" type="info" @click="ResetSubtitleSetting"
|
||||||
|
>重置数据</n-button
|
||||||
|
>
|
||||||
|
<n-button style="margin-left: 10px" type="info" @click="SaveSubtitleSetting">保存</n-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<n-card title="本地OCR | 本地Whisper">
|
||||||
|
<span class="url_class" @click="OpenTeach('local_ocr')" style="margin-left: 5px"
|
||||||
|
>本地OCR安装教程</span
|
||||||
|
>
|
||||||
|
<span class="url_class" @click="OpenTeach('local_whisper')" style="margin-left: 25px"
|
||||||
|
>本地Whisper安装教程</span
|
||||||
|
>
|
||||||
|
</n-card>
|
||||||
|
<n-card title="LAI Whisper" style="margin-top: 5px">
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
label-placement="left"
|
||||||
|
inline
|
||||||
|
:label-width="auto"
|
||||||
|
:model="formValue"
|
||||||
|
:rules="rules"
|
||||||
|
:size="size"
|
||||||
|
>
|
||||||
|
<n-form-item label="API URL" path="subtitleSetting.laiWhisper.url">
|
||||||
|
<n-input
|
||||||
|
:disabled="urlDisabled"
|
||||||
|
style="width: 220px"
|
||||||
|
v-model:value="subtitleSetting.laiWhisper.url"
|
||||||
|
></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="API KEY" path="subtitleSetting.laiWhisper.apiKey">
|
||||||
|
<n-input
|
||||||
|
type="password"
|
||||||
|
style="width: 220px"
|
||||||
|
show-password-on="mousedown"
|
||||||
|
v-model:value="subtitleSetting.laiWhisper.apiKey"
|
||||||
|
></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="prompt" path="subtitleSetting.laiWhisper.prompt">
|
||||||
|
<n-input
|
||||||
|
type="text"
|
||||||
|
style="width: 220px"
|
||||||
|
placeholder="请输入识别文案的提示"
|
||||||
|
v-model:value="subtitleSetting.laiWhisper.prompt"
|
||||||
|
></n-input>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item path="subtitleSetting.laiWhisper.syncGPTAPIKey">
|
||||||
|
<n-button type="info" @click="SyncGptSetting">同步GPT设置</n-button>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
|
import { onMounted, ref, toRaw } from 'vue'
|
||||||
import { useMessage } from 'naive-ui'
|
import { useMessage, useDialog, NCard, NSelect, NForm, NFormItem, NInput, NButton } from 'naive-ui'
|
||||||
|
import { GetSubtitleType } from '../../../../define/enum/waterMarkAndSubtitle'
|
||||||
export default defineComponent({
|
import { SyncGptKeyType } from '../../../../define/enum/softwareEnum'
|
||||||
components: {},
|
let message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
setup() {
|
let urlDisabled = ref(true)
|
||||||
onMounted(async () => {})
|
let subtitleSetting = ref({
|
||||||
|
selectModel: GetSubtitleType.LAI_WHISPER,
|
||||||
return {}
|
laiWhisper: {
|
||||||
|
url: 'https://api.laitool.cc/',
|
||||||
|
apiKey: '你的LAI API KEY',
|
||||||
|
syncGPTAPIKey: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
let res = await window.write.GetSubtitleSetting()
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
subtitleSetting.value = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 同步GPT设置中的API KEY
|
||||||
|
async function SyncGptSetting() {
|
||||||
|
dialog.warning({
|
||||||
|
title: '同步提示',
|
||||||
|
content:
|
||||||
|
'该功能会将通用设置中的GPT Key直接复制到这边,请确定在GPT中用的是LAI API,不然后续对应的操作可能会出现报错,是否继续操作?',
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
// 确定同步
|
||||||
|
let res = await window.gpt.SyncGptKey(SyncGptKeyType.SUBTITLE_SETTING)
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
subtitleSetting.value.laiWhisper.apiKey = res.data
|
||||||
|
message.success('获取全局GPT Key成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解锁和上锁
|
||||||
|
function UnBlock() {
|
||||||
|
urlDisabled.value = !urlDisabled.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置识别文案设置
|
||||||
|
async function ResetSubtitleSetting() {
|
||||||
|
dialog.warning({
|
||||||
|
title: '重置识别文案设置',
|
||||||
|
content: '注意,该操作不可逆,是否重置识别文案设置?',
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
let res = await window.write.ResetSubtitleSetting()
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
subtitleSetting.value = res.data
|
||||||
|
message.success('重置字幕设置成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存识别文案设置
|
||||||
|
async function SaveSubtitleSetting() {
|
||||||
|
// 这边要检查是不是存在对应的环境,在后进行保存
|
||||||
|
let res = await window.write.SaveSubtitleSetting(toRaw(subtitleSetting.value))
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
message.success('保存提取文案设置成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开对应的教程文档
|
||||||
|
function OpenTeach(type) {
|
||||||
|
switch (type) {
|
||||||
|
case 'local_ocr':
|
||||||
|
window.api.OpenUrl(
|
||||||
|
'https://rvgyir5wk1c.feishu.cn/docx/RSj1dIJvpooKCGxHxhgcDhsqnSh?from=from_copylink'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
case 'local_whisper':
|
||||||
|
window.api.OpenUrl(
|
||||||
|
'https://pvwu1oahp5m.feishu.cn/docx/VrBVd2KUDosmNfxat3OceWuInjd?from=from_copylink'
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let subtitleOptions = ref([
|
||||||
|
{ label: '本地OCR', value: GetSubtitleType.LOCAL_OCR },
|
||||||
|
{ label: '本地Whisper', value: GetSubtitleType.LOCAL_WHISPER },
|
||||||
|
{ label: 'LAI Whisper', value: GetSubtitleType.LAI_WHISPER }
|
||||||
|
])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.url_class {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.url_class:hover {
|
||||||
|
color: brown;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -39,8 +39,14 @@
|
|||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="APP ID/应用ID:">
|
<n-form-item label="APP ID/应用ID:">
|
||||||
<n-input
|
<n-input
|
||||||
:type="item.name == 'laitool' ? 'text' : 'password'"
|
v-if="item.name == 'laitool'"
|
||||||
:show-password-on="mousedown"
|
type="text"
|
||||||
|
v-model:value="item.translation_app_id"
|
||||||
|
/>
|
||||||
|
<n-input
|
||||||
|
v-else
|
||||||
|
type="password"
|
||||||
|
show-password-on="mousedown"
|
||||||
v-model:value="item.translation_app_id"
|
v-model:value="item.translation_app_id"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
@ -93,6 +99,7 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
translateSetting.value = translateSettingRes.data
|
translateSetting.value = translateSettingRes.data
|
||||||
|
console.log(translateSetting.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
function GetTranslationName(name) {
|
function GetTranslationName(name) {
|
||||||
|
|||||||
@ -448,7 +448,7 @@ export default defineComponent({
|
|||||||
async function SaveMask() {
|
async function SaveMask() {
|
||||||
debugger
|
debugger
|
||||||
// 判断当前是不是又蒙板
|
// 判断当前是不是又蒙板
|
||||||
if (canvasHistory.length <= 1) {
|
if (canvasHistory.length <= 0) {
|
||||||
message.error('请先选择去水印的区域')
|
message.error('请先选择去水印的区域')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,6 +81,8 @@ export const useReverseManageStore = defineStore('reverseManage', {
|
|||||||
// 获取小说任务数据
|
// 获取小说任务数据
|
||||||
async GetBookTaskDataFromDB(condition) {
|
async GetBookTaskDataFromDB(condition) {
|
||||||
try {
|
try {
|
||||||
|
debugger
|
||||||
|
this.bookTaskData = []
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
let res = await window.book.GetBookTaskData(condition)
|
let res = await window.book.GetBookTaskData(condition)
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
@ -90,7 +92,6 @@ export const useReverseManageStore = defineStore('reverseManage', {
|
|||||||
this.bookTaskData = res.data.bookTasks
|
this.bookTaskData = res.data.bookTasks
|
||||||
this.selectBookTask = res.data.bookTasks[0]
|
this.selectBookTask = res.data.bookTasks[0]
|
||||||
} else {
|
} else {
|
||||||
this.bookTaskData = []
|
|
||||||
this.selectBookTask = {
|
this.selectBookTask = {
|
||||||
no: null,
|
no: null,
|
||||||
id: null,
|
id: null,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user