LaiTool V3.1.1.
This commit is contained in:
parent
5dc75f018a
commit
918d06e990
6
package-lock.json
generated
6
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.4",
|
"version": "3.1.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.4",
|
"version": "3.1.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alicloud/alimt20181012": "^1.2.0",
|
"@alicloud/alimt20181012": "^1.2.0",
|
||||||
@ -12283,4 +12283,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.4",
|
"version": "3.1.1",
|
||||||
"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",
|
||||||
|
|||||||
BIN
resources/image/c_s/1236e3d6-c07f-4093-9bb1-a8d73401889a.png
Normal file
BIN
resources/image/c_s/1236e3d6-c07f-4093-9bb1-a8d73401889a.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/image/c_s/6d4245d0-18b8-4cc3-8827-af93d7de6c72.png
Normal file
BIN
resources/image/c_s/6d4245d0-18b8-4cc3-8827-af93d7de6c72.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/image/c_s/a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png
Normal file
BIN
resources/image/c_s/a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/image/c_s/a899bc65-317d-496d-a359-cbd3fb747c50.png
Normal file
BIN
resources/image/c_s/a899bc65-317d-496d-a359-cbd3fb747c50.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/image/c_s/f2e95c70-2267-4f7f-a93a-b095f7846604.png
Normal file
BIN
resources/image/c_s/f2e95c70-2267-4f7f-a93a-b095f7846604.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -37,3 +37,33 @@ export async function RetryWithBackoff<T>(fn: () => Promise<T>, retries: number
|
|||||||
}
|
}
|
||||||
throw new Error('所有重试失败'); // 理论上不会到达这里
|
throw new Error('所有重试失败'); // 理论上不会到达这里
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 并发执行任务(控制同时执行的任务数)
|
||||||
|
* @param tasks 总的任务列表
|
||||||
|
* @param concurrentCount 同时执行的数量
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function ExecuteConcurrently(tasks: Array<() => Promise<any>>, concurrentCount: number): Promise<any[]> {
|
||||||
|
let activeTasks: Array<Promise<any>> = [];
|
||||||
|
let results: Array<Promise<any>> = [];
|
||||||
|
|
||||||
|
while (tasks.length > 0) {
|
||||||
|
if (activeTasks.length < concurrentCount) {
|
||||||
|
let task = tasks.shift();
|
||||||
|
let promise = task().then(result => {
|
||||||
|
activeTasks = activeTasks.filter(t => t !== promise);
|
||||||
|
return result;
|
||||||
|
}).catch(error => {
|
||||||
|
// 抛出任务,停止所有的任务
|
||||||
|
tasks.length = 0;
|
||||||
|
throw error
|
||||||
|
});
|
||||||
|
activeTasks.push(promise);
|
||||||
|
results.push(promise);
|
||||||
|
} else {
|
||||||
|
await Promise.race(activeTasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.all(results);
|
||||||
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import util from 'util'
|
||||||
|
import { exec } from 'child_process'
|
||||||
|
const execAsync = util.promisify(exec)
|
||||||
const fspromises = fs.promises
|
const fspromises = fs.promises
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,3 +256,21 @@ export async function GetSubdirectories(folderPath: string): Promise<string[]> {
|
|||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除目标图片,然后将原图片的exif信息删除,然后将原图片复制到目标图片地址
|
||||||
|
* @param {*} exiftoolPath exiftool的地址
|
||||||
|
* @param {*} source 原图片地址
|
||||||
|
* @param {*} target 目标图片地址
|
||||||
|
*/
|
||||||
|
export async function DeleteFileExifData(exiftoolPath: string, source: string, target: string) {
|
||||||
|
try {
|
||||||
|
if (await CheckFileOrDirExist(target)) {
|
||||||
|
await fspromises.unlink(target)
|
||||||
|
}
|
||||||
|
let script = `"${exiftoolPath}" -all= -overwrite_original "${source}" -o "${target}"`
|
||||||
|
const output = await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' })
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import sharp from 'sharp'
|
import sharp from 'sharp'
|
||||||
import { CheckFileOrDirExist } from './file'
|
import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from './file'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ export async function Base64ToFile(base64: string, outFilePath: string): Promise
|
|||||||
let base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
let base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
|
||||||
let dataBuffer = Buffer.from(base64Data, 'base64')
|
let dataBuffer = Buffer.from(base64Data, 'base64')
|
||||||
let out_folder = path.dirname(outFilePath)
|
let out_folder = path.dirname(outFilePath)
|
||||||
await this.tools.checkFolderExistsOrCreate(out_folder)
|
await CheckFolderExistsOrCreate(out_folder)
|
||||||
await fs.promises.writeFile(outFilePath, dataBuffer)
|
await fs.promises.writeFile(outFilePath, dataBuffer)
|
||||||
// await this.tools.writeArrayToFile(dataBuffer, out_file);
|
// await this.tools.writeArrayToFile(dataBuffer, out_file);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
|
|||||||
updateTime: Date
|
updateTime: Date
|
||||||
startTime: number
|
startTime: number
|
||||||
endTime: number
|
endTime: number
|
||||||
|
messageName?: string
|
||||||
|
|
||||||
static schema: ObjectSchema = {
|
static schema: ObjectSchema = {
|
||||||
name: 'BookBackTaskList',
|
name: 'BookBackTaskList',
|
||||||
@ -31,7 +32,8 @@ export class BookBackTaskList extends Realm.Object<BookBackTaskList> {
|
|||||||
createTime: 'date',
|
createTime: 'date',
|
||||||
updateTime: 'date',
|
updateTime: 'date',
|
||||||
startTime: 'int',
|
startTime: 'int',
|
||||||
endTime: 'int'
|
endTime: 'int',
|
||||||
|
messageName: 'string?'
|
||||||
},
|
},
|
||||||
primaryKey: 'id'
|
primaryKey: 'id'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,7 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
|
|||||||
timeLimit: string | null // 事件实现(0 -- 3000)
|
timeLimit: string | null // 事件实现(0 -- 3000)
|
||||||
subValue: string | null // 包含的字幕数据
|
subValue: string | null // 包含的字幕数据
|
||||||
characterTags: string[] | null // 角色标签
|
characterTags: string[] | null // 角色标签
|
||||||
|
sceneTags: string[] | null // 场景标签
|
||||||
gptPrompt: string | null // GPT提示词
|
gptPrompt: string | null // GPT提示词
|
||||||
mjMessage: MJMessage | null // MJ消息
|
mjMessage: MJMessage | null // MJ消息
|
||||||
outImagePath: string | null // 输出图片地址
|
outImagePath: string | null // 输出图片地址
|
||||||
@ -174,6 +175,7 @@ export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
|
|||||||
subValue: 'string?',
|
subValue: 'string?',
|
||||||
reversePrompt: { type: 'list', objectType: 'ReversePrompt' },
|
reversePrompt: { type: 'list', objectType: 'ReversePrompt' },
|
||||||
characterTags: { type: 'list', objectType: 'string' },
|
characterTags: { type: 'list', objectType: 'string' },
|
||||||
|
sceneTags: 'string[]',
|
||||||
gptPrompt: 'string?',
|
gptPrompt: 'string?',
|
||||||
mjMessage: 'MJMessage?',
|
mjMessage: 'MJMessage?',
|
||||||
outImagePath: 'string?',
|
outImagePath: 'string?',
|
||||||
|
|||||||
36
src/define/db/model/SoftWare/preset.ts
Normal file
36
src/define/db/model/SoftWare/preset.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import Realm, { ObjectSchema } from 'realm'
|
||||||
|
|
||||||
|
export class PresetModel extends Realm.Object<PresetModel> {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
type: string
|
||||||
|
showImage?: string
|
||||||
|
prompt: string
|
||||||
|
chinesePrompt?: string
|
||||||
|
imageUrl?: string
|
||||||
|
srefSw?: number
|
||||||
|
crefCw?: number
|
||||||
|
lora?: string
|
||||||
|
loraWeight?: number
|
||||||
|
isShow: boolean
|
||||||
|
children?: string
|
||||||
|
static schema: ObjectSchema = {
|
||||||
|
name: 'PresetModel',
|
||||||
|
properties: {
|
||||||
|
id: 'string',
|
||||||
|
label: 'string',
|
||||||
|
type: 'string',
|
||||||
|
showImage: 'string?',
|
||||||
|
imageUrl: 'string?',
|
||||||
|
prompt: 'string',
|
||||||
|
chinesePrompt: 'string?',
|
||||||
|
srefSw: 'int?',
|
||||||
|
crefCw: 'int?',
|
||||||
|
lora: 'string?',
|
||||||
|
loraWeight: 'int?',
|
||||||
|
isShow: 'bool',
|
||||||
|
children: 'string?'
|
||||||
|
},
|
||||||
|
primaryKey: 'id'
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -140,7 +140,8 @@ export class BookBackTaskListService extends BaseRealmService {
|
|||||||
taskType: BookBackTaskType,
|
taskType: BookBackTaskType,
|
||||||
executeType = TaskExecuteType.AUTO,
|
executeType = TaskExecuteType.AUTO,
|
||||||
bookTaskId = null,
|
bookTaskId = null,
|
||||||
bookTaskDetailId = null
|
bookTaskDetailId = null,
|
||||||
|
responseMessageName: string = null
|
||||||
): GeneralResponse.SuccessItem | GeneralResponse.ErrorItem {
|
): GeneralResponse.SuccessItem | GeneralResponse.ErrorItem {
|
||||||
try {
|
try {
|
||||||
// 通过bookid获取book信息
|
// 通过bookid获取book信息
|
||||||
@ -181,6 +182,7 @@ export class BookBackTaskListService extends BaseRealmService {
|
|||||||
status: BookBackTaskStatus.WAIT,
|
status: BookBackTaskStatus.WAIT,
|
||||||
createTime: new Date(),
|
createTime: new Date(),
|
||||||
updateTime: new Date(),
|
updateTime: new Date(),
|
||||||
|
messageName: responseMessageName,
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
endTime: 0
|
endTime: 0
|
||||||
} as TaskModal.Task
|
} as TaskModal.Task
|
||||||
|
|||||||
@ -162,6 +162,20 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
|
|||||||
newBookTask[i].watermarkPosition = '[]'
|
newBookTask[i].watermarkPosition = '[]'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (oldRealm.schemaVersion < 23) {
|
||||||
|
const oldBookTask = oldRealm.objects('BookTaskDetail')
|
||||||
|
const newBookTask = newRealm.objects('BookTaskDetail')
|
||||||
|
for (let i = 0; i < oldBookTask.length; i++) {
|
||||||
|
newBookTask[i].subImagePath = '[]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldRealm.schemaVersion < 24) {
|
||||||
|
const oldBookTask = oldRealm.objects('BookBackTaskList')
|
||||||
|
const newBookTask = newRealm.objects('BookBackTaskList')
|
||||||
|
for (let i = 0; i < oldBookTask.length; i++) {
|
||||||
|
newBookTask[i].messageName = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseRealmService extends BaseService {
|
export class BaseRealmService extends BaseService {
|
||||||
@ -203,7 +217,7 @@ export class BaseRealmService extends BaseService {
|
|||||||
BookTaskDetailModel
|
BookTaskDetailModel
|
||||||
],
|
],
|
||||||
path: this.dbpath,
|
path: this.dbpath,
|
||||||
schemaVersion: 22,
|
schemaVersion: 24,
|
||||||
migration: migration
|
migration: migration
|
||||||
}
|
}
|
||||||
this.realm = await Realm.open(config)
|
this.realm = await Realm.open(config)
|
||||||
|
|||||||
@ -195,6 +195,9 @@ export class BookService extends BaseRealmService {
|
|||||||
await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹
|
await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹
|
||||||
// 修改数据
|
// 修改数据
|
||||||
book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
|
book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
|
||||||
|
if (book.type == BookType.ORIGINAL) {
|
||||||
|
book.oldVideoPath = null
|
||||||
|
}
|
||||||
|
|
||||||
let imageCategory = BookImageCategory.MJ
|
let imageCategory = BookImageCategory.MJ
|
||||||
if (book.type == BookType.SD_REVERSE) {
|
if (book.type == BookType.SD_REVERSE) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Realm from 'realm'
|
import Realm from 'realm'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { define } from '../../../define.js'
|
import { define } from '../../../define'
|
||||||
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
||||||
import { successMessage } from '../../../../main/Public/generalTools'
|
import { successMessage } from '../../../../main/Public/generalTools'
|
||||||
import { BaseRealmService } from './bookBasic'
|
import { BaseRealmService } from './bookBasic'
|
||||||
@ -72,6 +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,
|
||||||
|
sceneTags: item.sceneTags ? item.sceneTags.map((tag) => tag) : null,
|
||||||
subValue: isEmpty(item.subValue) ? null : JSON.parse(item.subValue),
|
subValue: isEmpty(item.subValue) ? null : JSON.parse(item.subValue),
|
||||||
reversePrompt: item.reversePrompt.map((reversePrompt) => {
|
reversePrompt: item.reversePrompt.map((reversePrompt) => {
|
||||||
return {
|
return {
|
||||||
@ -116,7 +117,7 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
* 添加一条小说任务对应的详细数据
|
* 添加一条小说任务对应的详细数据
|
||||||
* @param BookTaskDetail
|
* @param BookTaskDetail
|
||||||
*/
|
*/
|
||||||
public AddBookTaskDetail(bookTaskDetail) {
|
public AddBookTaskDetail(bookTaskDetail: Book.SelectBookTaskDetail) {
|
||||||
try {
|
try {
|
||||||
// 判断是不是又小说ID
|
// 判断是不是又小说ID
|
||||||
if (isEmpty(bookTaskDetail.bookId) || isEmpty(bookTaskDetail.bookTaskId)) {
|
if (isEmpty(bookTaskDetail.bookId) || isEmpty(bookTaskDetail.bookTaskId)) {
|
||||||
@ -191,7 +192,6 @@ export class BookTaskDetailService extends BaseRealmService {
|
|||||||
*/
|
*/
|
||||||
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)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Realm from 'realm'
|
import Realm from 'realm'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { define } from '../../../define.js'
|
import { define } from '../../../define'
|
||||||
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
||||||
import { BookBackTaskStatus, BookImageCategory, BookTaskStatus } from '../../../enum/bookEnum.js'
|
import { BookBackTaskStatus, BookImageCategory, BookTaskStatus } from '../../../enum/bookEnum.js'
|
||||||
import { successMessage } from '../../../../main/Public/generalTools'
|
import { successMessage } from '../../../../main/Public/generalTools'
|
||||||
|
|||||||
26
src/define/db/service/SoftWare/imageStyleService.ts
Normal file
26
src/define/db/service/SoftWare/imageStyleService.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Realm, { UpdateMode } from 'realm'
|
||||||
|
import path from 'path'
|
||||||
|
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
|
||||||
|
import { BaseSoftWareService } from './softwareBasic.js'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
|
||||||
|
export class ImageStyleService extends BaseSoftWareService {
|
||||||
|
static instance: ImageStyleService | null = null
|
||||||
|
realm: Realm
|
||||||
|
private constructor() {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前实例对象,为空则创建一个新的
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async getInstance() {
|
||||||
|
if (ImageStyleService.instance === null) {
|
||||||
|
ImageStyleService.instance = new ImageStyleService()
|
||||||
|
await super.getInstance()
|
||||||
|
}
|
||||||
|
return ImageStyleService.instance
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import Realm, { UpdateMode } from 'realm'
|
import Realm, { UpdateMode } from 'realm'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { BaseService } from '../baseService'
|
import { BaseService } from '../baseService'
|
||||||
import { define } from '../../../define.js'
|
import { define } from '../../../define'
|
||||||
import { SoftwareModel } from '../../model/SoftWare/software'
|
import { SoftwareModel } from '../../model/SoftWare/software'
|
||||||
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
|
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
|
||||||
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
|
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import {
|
|||||||
RemoteMJModel
|
RemoteMJModel
|
||||||
} from '../../model/SoftWare/mjSetting'
|
} from '../../model/SoftWare/mjSetting'
|
||||||
import { MJImageType, MJRobotType } from '../../../enum/mjEnum'
|
import { MJImageType, MJRobotType } from '../../../enum/mjEnum'
|
||||||
|
import { PresetModel } from '../../model/SoftWare/preset'
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
|
||||||
let dbPath = path.resolve(define.db_path, 'software.realm')
|
let dbPath = path.resolve(define.db_path, 'software.realm')
|
||||||
@ -155,6 +156,9 @@ const migration = (oldRealm: Realm, newRealm: Realm) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (oldRealm.schemaVersion < 22) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseSoftWareService extends BaseService {
|
export class BaseSoftWareService extends BaseService {
|
||||||
@ -190,10 +194,11 @@ export class BaseSoftWareService extends BaseService {
|
|||||||
BrowserMJModel,
|
BrowserMJModel,
|
||||||
RemoteMJModel,
|
RemoteMJModel,
|
||||||
APIMjModel,
|
APIMjModel,
|
||||||
MjSettingModel
|
MjSettingModel,
|
||||||
|
PresetModel
|
||||||
],
|
],
|
||||||
path: dbPath,
|
path: dbPath,
|
||||||
schemaVersion: 21, // 当前版本号
|
schemaVersion: 23, // 当前版本号
|
||||||
migration: migration
|
migration: migration
|
||||||
}
|
}
|
||||||
// 判断当前全局是不是又当前这个
|
// 判断当前全局是不是又当前这个
|
||||||
|
|||||||
@ -25,15 +25,25 @@ export class SoftwareService extends BaseSoftWareService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改数据库中行中的某个属性数据
|
// 修改数据库中行中的某个属性数据
|
||||||
UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): GeneralResponse.SuccessItem {
|
UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting) {
|
||||||
try {
|
if (software.id) {
|
||||||
this.realm.write(() => {
|
this.realm.write(() => {
|
||||||
this.realm.create('Software', software, UpdateMode.Modified)
|
this.realm.create('Software', software, UpdateMode.Modified)
|
||||||
})
|
})
|
||||||
// 返回成功信息
|
} else {
|
||||||
return successMessage(null, '修改软件配置信息成功', 'SoftwareService_UpdateSoftware')
|
// 没有ID,就修改指定属性
|
||||||
} catch (error) {
|
let softwareData = this.realm.objects('Software')
|
||||||
throw error
|
if (softwareData.length <= 0) {
|
||||||
|
throw new Error('数据库中没有软件配置信息')
|
||||||
|
}
|
||||||
|
let _software = softwareData[0]
|
||||||
|
this.realm.write(() => {
|
||||||
|
for (let key in software) {
|
||||||
|
if (software[key] != undefined) {
|
||||||
|
_software[key] = software[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export const DEFINE_STRING = {
|
export const DEFINE_STRING = {
|
||||||
|
SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE",
|
||||||
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
|
SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION',
|
||||||
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
|
OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD',
|
||||||
OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS',
|
OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS',
|
||||||
@ -7,7 +8,7 @@ export const DEFINE_STRING = {
|
|||||||
GET_DEFINE_CONFIG_JSON_BY_PROPERTY: 'GET_DEFINE_CONFIG_JSON_BY_PROPERTY',
|
GET_DEFINE_CONFIG_JSON_BY_PROPERTY: 'GET_DEFINE_CONFIG_JSON_BY_PROPERTY',
|
||||||
GET_IMAGE_GENERATE_CATEGORY: 'GET_IMAGE_GENERATE_CATEGORY',
|
GET_IMAGE_GENERATE_CATEGORY: 'GET_IMAGE_GENERATE_CATEGORY',
|
||||||
SHOW_MAIN_NOTIFICATION: 'SHOW_MAIN_NOTIFICATION',
|
SHOW_MAIN_NOTIFICATION: 'SHOW_MAIN_NOTIFICATION',
|
||||||
SHOW_GLOABAL_MESSAGE: 'SHOW_GLOABAL_MESSAGE',
|
SHOW_MAIN_MESSAGE: "SHOW_MAIN_MESSAGE",
|
||||||
CHECK_MACHINE_ID: 'CHECK_MACHINE_ID',
|
CHECK_MACHINE_ID: 'CHECK_MACHINE_ID',
|
||||||
GET_CUSTOMIZE_GPT_PROMPT: 'GET_CUSTOMIZE_GPT_PROMPT',
|
GET_CUSTOMIZE_GPT_PROMPT: 'GET_CUSTOMIZE_GPT_PROMPT',
|
||||||
GENERATE_GPT_EXAMPLE_OUT: 'GENERATE_GPT_EXAMPLE_OUT',
|
GENERATE_GPT_EXAMPLE_OUT: 'GENERATE_GPT_EXAMPLE_OUT',
|
||||||
@ -149,11 +150,19 @@ export const DEFINE_STRING = {
|
|||||||
TRANSLATE_NOW_RETURN: 'TRANSLATE_NOW_RETURN',
|
TRANSLATE_NOW_RETURN: 'TRANSLATE_NOW_RETURN',
|
||||||
GET_TRANSLATE_SETTING: 'GET_TRANSLATE_SETTING',
|
GET_TRANSLATE_SETTING: 'GET_TRANSLATE_SETTING',
|
||||||
RESET_TRANSLATE_SETTING: 'RESET_TRANSLATE_SETTING',
|
RESET_TRANSLATE_SETTING: 'RESET_TRANSLATE_SETTING',
|
||||||
SAVE_TRANSLATE_SETTING: 'SAVE_TRANSLATE_SETTING'
|
SAVE_TRANSLATE_SETTING: 'SAVE_TRANSLATE_SETTING',
|
||||||
|
/**
|
||||||
|
* GPT 反推提示词翻译返回数据
|
||||||
|
*/
|
||||||
|
GPT_PROMPT_TRANSLATE_RETRUN: "GPT_PROMPT_TRANSLATE_RETRUN"
|
||||||
},
|
},
|
||||||
SD: {
|
SD: {
|
||||||
LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
|
LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA',
|
||||||
TXT2IMG: 'TXT2IMG',
|
TXT2IMG: 'TXT2IMG',
|
||||||
|
|
||||||
|
//#region SD生成图片相关
|
||||||
|
|
||||||
|
//#endregion
|
||||||
},
|
},
|
||||||
MJ: {
|
MJ: {
|
||||||
SAVE_WORD_SRT: 'SAVE_WORD_SRT',
|
SAVE_WORD_SRT: 'SAVE_WORD_SRT',
|
||||||
@ -206,7 +215,6 @@ 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',
|
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',
|
||||||
@ -243,6 +251,41 @@ export const DEFINE_STRING = {
|
|||||||
REMOVE_GENERATE_IMAGE: 'REMOVE_GENERATE_IMAGE',
|
REMOVE_GENERATE_IMAGE: 'REMOVE_GENERATE_IMAGE',
|
||||||
ADD_NEW_BOOK_TASK: "ADD_NEW_BOOK_TASK",
|
ADD_NEW_BOOK_TASK: "ADD_NEW_BOOK_TASK",
|
||||||
REPLACE_BOOK_DATA: "REPLACE_BOOK_DATA",
|
REPLACE_BOOK_DATA: "REPLACE_BOOK_DATA",
|
||||||
|
SAVE_COPYWRITING: 'SAVE_COPYWRITING',
|
||||||
|
|
||||||
|
//#region 原创推理提示词
|
||||||
|
ORIGINAL_GPT_PROMPT: "ORIGINAL_GPT_PROMPT",
|
||||||
|
ORIGINAL_GPT_PROMPT_RETURN: "ORIGINAL_GPT_PROMPT_RETURN",
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 生图返回相关
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MJ生图返回信息
|
||||||
|
*/
|
||||||
|
MJ_IMAGE_GENERATE_RETURN: 'MJ_IMAGE_GENERATE_RETURN',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SD生图返回信息
|
||||||
|
*/
|
||||||
|
SD_IMAGE_GENERATE_RETURN: 'SD_IMAGE_GENERATE_RETURN',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* D3 出图返回信息
|
||||||
|
*/
|
||||||
|
D3_IMAGE_GENERATE_RETURN: 'D3_IMAGE_GENERATE_RETURN',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flux forge 生图返回信息
|
||||||
|
*/
|
||||||
|
FLUX_FORGE_IMAGE_GENERATE_RETURN: "FLUX_FORGE_IMAGE_GENERATE_RETURN",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flux api 生图返回信息
|
||||||
|
*/
|
||||||
|
FLUX_API_IMAGE_GENERATE_RETURN: "FLUX_API_IMAGE_GENERATE_RETURN",
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',
|
COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD',
|
||||||
|
|
||||||
@ -290,6 +333,19 @@ export const DEFINE_STRING = {
|
|||||||
GET_PROMPT_SORT_DATA: 'GET_PROMPT_SORT_DATA',
|
GET_PROMPT_SORT_DATA: 'GET_PROMPT_SORT_DATA',
|
||||||
OPEN_PROMPT_FILE_TXT: 'OPEN_PROMPT_FILE_TXT'
|
OPEN_PROMPT_FILE_TXT: 'OPEN_PROMPT_FILE_TXT'
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* IPC事件传递,预设相关
|
||||||
|
*/
|
||||||
|
PRESET: {
|
||||||
|
/**
|
||||||
|
* 获取任务的预设(只获取 label 和 id)
|
||||||
|
*/
|
||||||
|
GET_CHARACTER_PRESET: 'GET_CHARACTER_PRESET',
|
||||||
|
/**
|
||||||
|
* 获取场景的预设(只获取 label 和 id)
|
||||||
|
*/
|
||||||
|
GET_SCENE_PRESET: "GET_SCENE_PRESET"
|
||||||
|
},
|
||||||
TTS: {
|
TTS: {
|
||||||
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
|
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
|
||||||
GENERATE_AUDIO: 'GENERATE_AUDIO',
|
GENERATE_AUDIO: 'GENERATE_AUDIO',
|
||||||
@ -309,6 +365,21 @@ export const DEFINE_STRING = {
|
|||||||
DB: {
|
DB: {
|
||||||
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
|
UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA",
|
||||||
UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA",
|
UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA",
|
||||||
UPDATE_BOOK_DATA: "UPDATE_BOOK_DATA"
|
UPDATE_BOOK_DATA: "UPDATE_BOOK_DATA",
|
||||||
|
UPDATE_SOFTWARE_SETTING: "UPDATE_SOFTWARE_SETTING"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 后台任务相关
|
||||||
|
*/
|
||||||
|
TASK: {
|
||||||
|
/**
|
||||||
|
* 添加单个后台任务
|
||||||
|
*/
|
||||||
|
ADD_BOOK_BACK_TASK: "ADD_BOOK_BACK_TASK",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加多个后台任务
|
||||||
|
*/
|
||||||
|
ADD_MULTI_BOOK_BACK_TASK: 'ADD_MULTI_BOOK_BACK_TASK'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
export enum BookType {
|
export enum BookType {
|
||||||
// 原创
|
// 原创
|
||||||
ORIGINAL = 'original',
|
ORIGINAL = 'original',
|
||||||
|
// 区分老版本的原创
|
||||||
|
NEW_ORIGINAL = 'new_original',
|
||||||
// 反推
|
// 反推
|
||||||
SD_REVERSE = 'sd_reverse',
|
SD_REVERSE = 'sd_reverse',
|
||||||
// MJ 反推
|
// MJ 反推
|
||||||
@ -14,7 +16,11 @@ export enum BookImageCategory {
|
|||||||
// SD
|
// SD
|
||||||
SD = 'sd',
|
SD = 'sd',
|
||||||
// D3
|
// D3
|
||||||
D3 = 'd3'
|
D3 = 'd3',
|
||||||
|
// FLUX API
|
||||||
|
FLUX_API = 'flux-api',
|
||||||
|
// FLUX FORGE
|
||||||
|
FLUX_FORGE = 'flux-forge'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AddBookTaskCopyData {
|
export enum AddBookTaskCopyData {
|
||||||
@ -67,6 +73,10 @@ export enum BookBackTaskType {
|
|||||||
MJ_IMAGE = 'mj_image',
|
MJ_IMAGE = 'mj_image',
|
||||||
// SD 生成图片
|
// SD 生成图片
|
||||||
SD_IMAGE = 'sd_image',
|
SD_IMAGE = 'sd_image',
|
||||||
|
// flux forge 生成图片
|
||||||
|
FLUX_FORGE_IMAGE = 'flux_forge_image',
|
||||||
|
// flux api 生成图片
|
||||||
|
FLUX_API_IMAGE = 'flux_api_image',
|
||||||
// D3 生成图片
|
// D3 生成图片
|
||||||
D3_IMAGE = 'd3_image',
|
D3_IMAGE = 'd3_image',
|
||||||
// 高清
|
// 高清
|
||||||
@ -256,3 +266,13 @@ export enum BookRepalceDataType {
|
|||||||
// 提示词
|
// 提示词
|
||||||
PROMPT = 'prompt',
|
PROMPT = 'prompt',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小说选择标签的方式类型,可以是下拉和标签
|
||||||
|
*/
|
||||||
|
export enum BookTagSelectType {
|
||||||
|
// 下拉
|
||||||
|
DROP = 'drop',
|
||||||
|
// 标签
|
||||||
|
TAG = 'tag'
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Flux 调用API时候的 生图模型
|
||||||
|
*/
|
||||||
|
export enum FLxuAPIImageType {
|
||||||
|
FLUX = "flux",
|
||||||
|
FLUX_PRO = "flux-pro",
|
||||||
|
FLUX_DEV = "flux-dev",
|
||||||
|
FLUX_SCHNELL = "flux-schnell",
|
||||||
|
FLUX_PRO_MAX = "flux-pro-max"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum PresetType {
|
||||||
|
// 角色
|
||||||
|
CHARACTER = 'character',
|
||||||
|
|
||||||
|
// 本地风格
|
||||||
|
LOCAL_STYLE = 'localStyle',
|
||||||
|
|
||||||
|
// 自定义风格
|
||||||
|
CUSTOM_STYLE = 'customStyle',
|
||||||
|
|
||||||
|
// laitool预设风格
|
||||||
|
LAITOOL_STYLE = 'laitoolStyle',
|
||||||
|
}
|
||||||
@ -9,7 +9,16 @@ export enum MJImageType {
|
|||||||
BROWSER_MJ = 'browser_mj',
|
BROWSER_MJ = 'browser_mj',
|
||||||
|
|
||||||
// API模式
|
// API模式
|
||||||
API_MJ = 'api_mj'
|
API_MJ = 'api_mj',
|
||||||
|
|
||||||
|
// 本地 SD
|
||||||
|
LOCAL_SD = 'local_sd',
|
||||||
|
|
||||||
|
// flux-api
|
||||||
|
FLUX_API = 'flux-api',
|
||||||
|
|
||||||
|
// flxu-forge
|
||||||
|
FLUX_FORGE = 'flux-forge'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MJRobotType {
|
export enum MJRobotType {
|
||||||
|
|||||||
16
src/define/enum/preset.ts
Normal file
16
src/define/enum/preset.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 标签库预设的图片样式类型
|
||||||
|
*/
|
||||||
|
export enum PresetType {
|
||||||
|
// 角色
|
||||||
|
CHARACTER = 'character',
|
||||||
|
|
||||||
|
// 本地风格
|
||||||
|
LOCAL_STYLE = 'localStyle',
|
||||||
|
|
||||||
|
// 自定义风格
|
||||||
|
CUSTOM_STYLE = 'customStyle',
|
||||||
|
|
||||||
|
// laitool预设风格
|
||||||
|
LAITOOL_STYLE = 'laitoolStyle',
|
||||||
|
}
|
||||||
@ -1,245 +1,275 @@
|
|||||||
import { Tools } from "../../main/tools";
|
import { Tools } from '../../main/tools'
|
||||||
import { define } from "../define";
|
import { define } from '../define'
|
||||||
import path from "path";
|
import path from 'path'
|
||||||
import { DEFINE_STRING } from "../define_string";
|
import { DEFINE_STRING } from '../define_string'
|
||||||
import { get, has } from "lodash";
|
import { get, has } from 'lodash'
|
||||||
let tools = new Tools();
|
let tools = new Tools()
|
||||||
const { v4: uuidv4 } = require('uuid'); // 引入UUID库来生成唯一标识符
|
const { v4: uuidv4 } = require('uuid') // 引入UUID库来生成唯一标识符
|
||||||
|
|
||||||
export const ImageSetting = {
|
export const ImageSetting = {
|
||||||
|
/**
|
||||||
/**
|
* 获取自动保存图片的方式
|
||||||
* 获取自动保存图片的方式
|
* @returns
|
||||||
* @returns
|
*/
|
||||||
*/
|
async GetAutoSaveImageClassifyOptions() {
|
||||||
async GetAutoSaveImageClassifyOptions() {
|
return {
|
||||||
return {
|
code: 1,
|
||||||
code: 1,
|
data: [
|
||||||
data: [{
|
{
|
||||||
label: "不分类",
|
label: '不分类',
|
||||||
value: "one"
|
value: 'one'
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// label: "按模型",
|
// label: "按模型",
|
||||||
// value: "model"
|
// value: "model"
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
label: "按风格",
|
label: '按风格',
|
||||||
value: "style"
|
value: 'style'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "风格+模型",
|
label: '风格+模型',
|
||||||
value: "theme"
|
value: 'theme'
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取自动保存图片的方式(sd,mj,d3 等)
|
* 获取自动保存图片的方式(sd,mj,d3 等)
|
||||||
*/
|
*/
|
||||||
async GetImageGenerateCategory() {
|
async GetImageGenerateCategory() {
|
||||||
return {
|
return {
|
||||||
code: 1,
|
code: 1,
|
||||||
data: [{
|
data: [
|
||||||
label: "SD",
|
{
|
||||||
value: "sd"
|
label: 'SD',
|
||||||
|
value: 'sd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'MJ',
|
||||||
|
value: 'mj'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'D3',
|
||||||
|
value: 'd3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Flux-Forge',
|
||||||
|
value: 'flux-forge'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Flux-API',
|
||||||
|
value: 'flux-api'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存自动保存图片的设置
|
||||||
|
*/
|
||||||
|
async SaveImageAutoSaveSetting(value) {
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value)
|
||||||
|
await tools.writeJsonFilePropertyValue(define.img_base, 'auto_save_image', value)
|
||||||
|
return {
|
||||||
|
code: 1
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: error.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存自动保存图片的设置
|
||||||
|
*/
|
||||||
|
async GetImageAutoSaveSetting() {
|
||||||
|
try {
|
||||||
|
let res = await tools.getJsonFilePropertyValue(define.img_base, 'auto_save_image', {}, false)
|
||||||
|
return {
|
||||||
|
code: 1,
|
||||||
|
data: res
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: error.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存图片到指定文件夹,只是将任务添加到队列中
|
||||||
|
*/
|
||||||
|
async SaveImageToOtherFolder(output = [], value) {
|
||||||
|
try {
|
||||||
|
let show = false
|
||||||
|
if (value) {
|
||||||
|
value = JSON.parse(value)
|
||||||
|
show = false
|
||||||
|
} else {
|
||||||
|
let auto_save_image = await tools.getJsonFilePropertyValue(
|
||||||
|
define.img_base,
|
||||||
|
'auto_save_image',
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
value = {
|
||||||
|
save_match_count: auto_save_image.save_match_count,
|
||||||
|
save_folder: auto_save_image.main_save_folder
|
||||||
|
}
|
||||||
|
if (!auto_save_image.auto_save) {
|
||||||
|
return {
|
||||||
|
code: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let batch = DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER
|
||||||
|
// 获取当前的所有的output文件夹
|
||||||
|
if (output.length == 0) {
|
||||||
|
output = await tools.getSubFolderList(
|
||||||
|
path.join(global.config.project_path, 'tmp/bak/'),
|
||||||
|
'start',
|
||||||
|
'output_crop_'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (let i = 0; i < output.length; i++) {
|
||||||
|
const element = path.join(global.config.project_path, 'tmp/bak/' + output[i])
|
||||||
|
// 获取指定的文件夹里面的文件
|
||||||
|
let png_files = await tools.getFilesWithExtensions(element, '.png')
|
||||||
|
console.log(png_files)
|
||||||
|
// 判断当前的png_files中的数据是不是大于value.save_match_count,大于的话,删除数组里面的数据
|
||||||
|
if (value.save_match_count && png_files.length > value.save_match_count) {
|
||||||
|
// 删除数组
|
||||||
|
png_files.splice(value.save_match_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < png_files.length; j++) {
|
||||||
|
const item = png_files[j]
|
||||||
|
global.fileQueue.enqueue(
|
||||||
|
async () => {
|
||||||
|
// 复制文件到指定的文件夹
|
||||||
|
let dst = path.join(
|
||||||
|
value.save_folder,
|
||||||
|
`${Date.now().toString()}_${uuidv4().split('-')[0]}.png`
|
||||||
|
)
|
||||||
|
|
||||||
|
await tools.copyFileOrDirectory(item, dst)
|
||||||
},
|
},
|
||||||
{
|
`${batch}_${item}`,
|
||||||
label: "MJ",
|
batch
|
||||||
value: "mj"
|
)
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "D3",
|
|
||||||
value: "d3"
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
global.fileQueue.setBatchCompletionCallback(batch, (failedTasks) => {
|
||||||
/**
|
if (failedTasks.length > 0) {
|
||||||
* 保存自动保存图片的设置
|
let message = `
|
||||||
*/
|
|
||||||
async SaveImageAutoSaveSetting(value) {
|
|
||||||
try {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
await tools.writeJsonFilePropertyValue(define.img_base, "auto_save_image", value);
|
|
||||||
return {
|
|
||||||
code: 1,
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
message: error.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存自动保存图片的设置
|
|
||||||
*/
|
|
||||||
async GetImageAutoSaveSetting() {
|
|
||||||
try {
|
|
||||||
let res = await tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false);
|
|
||||||
return {
|
|
||||||
code: 1,
|
|
||||||
data: res
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
message: error.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存图片到指定文件夹,只是将任务添加到队列中
|
|
||||||
*/
|
|
||||||
async SaveImageToOtherFolder(output = [], value) {
|
|
||||||
try {
|
|
||||||
let show = false;
|
|
||||||
if (value) {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
show = false;
|
|
||||||
} else {
|
|
||||||
let auto_save_image = await tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false);
|
|
||||||
value = {
|
|
||||||
save_match_count: auto_save_image.save_match_count,
|
|
||||||
save_folder: auto_save_image.main_save_folder
|
|
||||||
}
|
|
||||||
if (!auto_save_image.auto_save) {
|
|
||||||
return {
|
|
||||||
code: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let batch = DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER;
|
|
||||||
// 获取当前的所有的output文件夹
|
|
||||||
if (output.length == 0) {
|
|
||||||
output = await tools.getSubFolderList(path.join(global.config.project_path, "tmp/bak/"), "start", "output_crop_");
|
|
||||||
}
|
|
||||||
for (let i = 0; i < output.length; i++) {
|
|
||||||
const element = path.join(global.config.project_path, 'tmp/bak/' + output[i]);
|
|
||||||
// 获取指定的文件夹里面的文件
|
|
||||||
let png_files = await tools.getFilesWithExtensions(element, ".png");
|
|
||||||
console.log(png_files);
|
|
||||||
// 判断当前的png_files中的数据是不是大于value.save_match_count,大于的话,删除数组里面的数据
|
|
||||||
if (value.save_match_count && png_files.length > value.save_match_count) {
|
|
||||||
// 删除数组
|
|
||||||
png_files.splice(value.save_match_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0; j < png_files.length; j++) {
|
|
||||||
const item = png_files[j];
|
|
||||||
global.fileQueue.enqueue(async () => {
|
|
||||||
// 复制文件到指定的文件夹
|
|
||||||
let dst = path.join(value.save_folder, `${Date.now().toString()}_${uuidv4().split('-')[0]}.png`);
|
|
||||||
|
|
||||||
await tools.copyFileOrDirectory(item, dst);
|
|
||||||
}, `${batch}_${item}`, batch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
global.fileQueue.setBatchCompletionCallback(batch, (failedTasks) => {
|
|
||||||
if (failedTasks.length > 0) {
|
|
||||||
let message = `
|
|
||||||
转存任务都已完成。
|
转存任务都已完成。
|
||||||
但是以下任务执行失败:
|
但是以下任务执行失败:
|
||||||
`
|
`
|
||||||
failedTasks.forEach(({ taskId, error }) => {
|
failedTasks.forEach(({ taskId, error }) => {
|
||||||
message += `${taskId}-, \n 错误信息: ${error}` + '\n';
|
message += `${taskId}-, \n 错误信息: ${error}` + '\n'
|
||||||
});
|
})
|
||||||
|
|
||||||
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
||||||
code: 0,
|
code: 0,
|
||||||
message: message
|
message: message
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (show) {
|
if (show) {
|
||||||
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
||||||
code: 1,
|
code: 1,
|
||||||
message: "所有图片转存完成"
|
message: '所有图片转存完成'
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
return {
|
|
||||||
code: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
message: error.toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
|
|
||||||
/**
|
return {
|
||||||
* 获取指定的配置文件里面指定的属性的数据
|
code: 1
|
||||||
* @param {*} value 执行方法必要的信息
|
}
|
||||||
* 0 define中的指定属性(指定的配置文件)
|
} catch (error) {
|
||||||
* 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据
|
return {
|
||||||
* 2 是不是要校验属性不存在
|
code: 0,
|
||||||
* 3 属性没有找到的默认值
|
message: error.toString()
|
||||||
* @returns
|
}
|
||||||
*/
|
|
||||||
async GetDefineConfigJsonByProperty(value) {
|
|
||||||
try {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
let defin_property = value[0];
|
|
||||||
let property = value[1];
|
|
||||||
let need_check = value[2];
|
|
||||||
let default_data = value[3];
|
|
||||||
// 判断define中的属性是不是存在
|
|
||||||
let hasProperty = has(define, defin_property);
|
|
||||||
if (!hasProperty) {
|
|
||||||
throw new Error(`${defin_property} 属性不存在。`);
|
|
||||||
}
|
|
||||||
let data = await tools.getJsonFilePropertyValue(define[defin_property], property, default_data, need_check);
|
|
||||||
return {
|
|
||||||
code: 1,
|
|
||||||
data: data
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
message: "获取配置信息失败,错误信息入下 : " + error.message.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存指定的配置文件里面指定的属性的数据
|
|
||||||
* @param {*} value
|
|
||||||
* 0 define中的指定属性(指定的配置文件)
|
|
||||||
* 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据
|
|
||||||
* 2 要写入的值
|
|
||||||
* 3 是不是要校验属性不存在
|
|
||||||
*/
|
|
||||||
async SaveDefineConfigJsonByProperty(value) {
|
|
||||||
try {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
let defin_property = value[0];
|
|
||||||
let property = value[1];
|
|
||||||
let data = value[2];
|
|
||||||
let need_check = value[3] ? value[3] : false;
|
|
||||||
// 判断define中的属性是不是存在
|
|
||||||
let hasProperty = has(define, defin_property);
|
|
||||||
if (!hasProperty) {
|
|
||||||
throw new Error(`${defin_property} 属性不存在。`);
|
|
||||||
}
|
|
||||||
await tools.writeJsonFilePropertyValue(define[defin_property], property, data, need_check);
|
|
||||||
return {
|
|
||||||
code: 1,
|
|
||||||
message: "保存指定的配置成功"
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
message: "保存配置信息失败,错误信息入下 : " + error.message.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 获取指定的配置文件里面指定的属性的数据
|
||||||
|
* @param {*} value 执行方法必要的信息
|
||||||
|
* 0 define中的指定属性(指定的配置文件)
|
||||||
|
* 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据
|
||||||
|
* 2 是不是要校验属性不存在
|
||||||
|
* 3 属性没有找到的默认值
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetDefineConfigJsonByProperty(value) {
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value)
|
||||||
|
let defin_property = value[0]
|
||||||
|
let property = value[1]
|
||||||
|
let need_check = value[2]
|
||||||
|
let default_data = value[3]
|
||||||
|
// 判断define中的属性是不是存在
|
||||||
|
let hasProperty = has(define, defin_property)
|
||||||
|
if (!hasProperty) {
|
||||||
|
throw new Error(`${defin_property} 属性不存在。`)
|
||||||
|
}
|
||||||
|
let data = await tools.getJsonFilePropertyValue(
|
||||||
|
define[defin_property],
|
||||||
|
property,
|
||||||
|
default_data,
|
||||||
|
need_check
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
code: 1,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: '获取配置信息失败,错误信息入下 : ' + error.message.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存指定的配置文件里面指定的属性的数据
|
||||||
|
* @param {*} value
|
||||||
|
* 0 define中的指定属性(指定的配置文件)
|
||||||
|
* 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据
|
||||||
|
* 2 要写入的值
|
||||||
|
* 3 是不是要校验属性不存在
|
||||||
|
*/
|
||||||
|
async SaveDefineConfigJsonByProperty(value) {
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value)
|
||||||
|
let defin_property = value[0]
|
||||||
|
let property = value[1]
|
||||||
|
let data = value[2]
|
||||||
|
let need_check = value[3] ? value[3] : false
|
||||||
|
// 判断define中的属性是不是存在
|
||||||
|
let hasProperty = has(define, defin_property)
|
||||||
|
if (!hasProperty) {
|
||||||
|
throw new Error(`${defin_property} 属性不存在。`)
|
||||||
|
}
|
||||||
|
await tools.writeJsonFilePropertyValue(define[defin_property], property, data, need_check)
|
||||||
|
return {
|
||||||
|
code: 1,
|
||||||
|
message: '保存指定的配置成功'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: '保存配置信息失败,错误信息入下 : ' + error.message.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { SubtitleService } from '../Service/Subtitle/subtitleService'
|
|||||||
import { BookFrame } from '../Service/Book/bookFrame'
|
import { BookFrame } from '../Service/Book/bookFrame'
|
||||||
import { BookPrompt } from '../Service/Book/bookPrompt'
|
import { BookPrompt } from '../Service/Book/bookPrompt'
|
||||||
import { BookGeneral } from '../Service/Book/bookGeneral'
|
import { BookGeneral } from '../Service/Book/bookGeneral'
|
||||||
|
import { OperateBookType } from '../../define/enum/bookEnum'
|
||||||
let reverseBook = new ReverseBook()
|
let reverseBook = new ReverseBook()
|
||||||
let basicReverse = new BasicReverse()
|
let basicReverse = new BasicReverse()
|
||||||
let subtitle = new Subtitle()
|
let subtitle = new Subtitle()
|
||||||
@ -141,16 +142,30 @@ export function BookIpc() {
|
|||||||
async (event, id, operateBookType) => await bookPrompt.RemoveMergePromptData(id, operateBookType)
|
async (event, id, operateBookType) => await bookPrompt.RemoveMergePromptData(id, operateBookType)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 原创推理提示词
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT,
|
||||||
|
async (event, id: string, operateBookType: OperateBookType, coverData: boolean) =>
|
||||||
|
await bookPrompt.OriginalGetPrompt(id, operateBookType, coverData)
|
||||||
|
)
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 文案相关
|
//#region 文案相关
|
||||||
|
|
||||||
// 开始执行获取小说文案的方法
|
// 开始执行反推获取小说文案的方法
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
||||||
async (event, bookId, bookTaskId, operateBookType, coverData) => await subtitleService.GetCopywriting(bookId, bookTaskId, operateBookType, coverData)
|
async (event, bookId, bookTaskId, operateBookType, coverData) => await subtitleService.GetCopywriting(bookId, bookTaskId, operateBookType, coverData)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 导入文案和字幕对齐数据的方法,保存到数据库中
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.BOOK.SAVE_COPYWRITING,
|
||||||
|
async (event, bookTaskId, copywritingData, operateBookType) => await subtitleService.SaveCopywriting(bookTaskId, copywritingData, operateBookType)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
// 获取小说的文案数据,然后保存到对应的文件中
|
// 获取小说的文案数据,然后保存到对应的文件中
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.BOOK.EXPORT_COPYWRITING,
|
DEFINE_STRING.BOOK.EXPORT_COPYWRITING,
|
||||||
|
|||||||
@ -5,12 +5,14 @@ import { Book } from '../../model/book'
|
|||||||
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 { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic'
|
||||||
|
|
||||||
|
|
||||||
async function DBIpc() {
|
async function DBIpc() {
|
||||||
let bookTaskService = await BookTaskService.getInstance()
|
let bookTaskService = await BookTaskService.getInstance()
|
||||||
let bookTaskDetailService = await BookTaskDetailService.getInstance()
|
let bookTaskDetailService = await BookTaskDetailService.getInstance()
|
||||||
let bookService = await BookService.getInstance()
|
let bookService = await BookService.getInstance()
|
||||||
|
let softWareServiceBasic = new SoftWareServiceBasic()
|
||||||
//#region 小说相关的修改
|
//#region 小说相关的修改
|
||||||
|
|
||||||
// 修改小说任务的数据
|
// 修改小说任务的数据
|
||||||
@ -47,5 +49,18 @@ async function DBIpc() {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//#region 软件设置的修改
|
||||||
|
|
||||||
|
// 修改软件设置
|
||||||
|
ipcMain.handle(DEFINE_STRING.DB.UPDATE_SOFTWARE_SETTING, async (event, software: SoftwareSettingModel.SoftwareSetting) => {
|
||||||
|
try {
|
||||||
|
await softWareServiceBasic.UpdateSoftware(software)
|
||||||
|
return successMessage(null, "修改软件配置信息成功", "DBIpc_UpdateSoftwareSetting")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("修改软件配置信息失败", "DBIpc_UpdateSoftwareSetting")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
export { DBIpc }
|
export { DBIpc }
|
||||||
|
|||||||
@ -46,6 +46,11 @@ function GlobalIpc() {
|
|||||||
ipcMain.on(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, (event, value) => {
|
ipcMain.on(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, (event, value) => {
|
||||||
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MAIN_NOTIFICATION, value)
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MAIN_NOTIFICATION, value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听打开message事件
|
||||||
|
ipcMain.on(DEFINE_STRING.SHOW_GLOBAL_MESSAGE, (event, value) => {
|
||||||
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MAIN_MESSAGE, value)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { GlobalIpc }
|
export { GlobalIpc }
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import { SystemIpc } from './systemIpc.js'
|
|||||||
import { BookIpc } from './bookIpc'
|
import { BookIpc } from './bookIpc'
|
||||||
import { TTSIpc } from './ttsIpc.js'
|
import { TTSIpc } from './ttsIpc.js'
|
||||||
import { DBIpc } from './dbIpc'
|
import { DBIpc } from './dbIpc'
|
||||||
|
import { PresetIpc } from './presetIpc'
|
||||||
|
import { TaskIpc } from './taskIpc'
|
||||||
|
|
||||||
export async function RegisterIpc(createWindow) {
|
export async function RegisterIpc(createWindow) {
|
||||||
PromptIpc()
|
PromptIpc()
|
||||||
@ -26,6 +28,8 @@ export async function RegisterIpc(createWindow) {
|
|||||||
GptIpc()
|
GptIpc()
|
||||||
SdIpc()
|
SdIpc()
|
||||||
await DBIpc()
|
await DBIpc()
|
||||||
|
PresetIpc()
|
||||||
|
TaskIpc()
|
||||||
MjIpc()
|
MjIpc()
|
||||||
MainIpc(createWindow)
|
MainIpc(createWindow)
|
||||||
OriginalImageGenerateIpc()
|
OriginalImageGenerateIpc()
|
||||||
|
|||||||
@ -141,7 +141,8 @@ function MjIpc() {
|
|||||||
// 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,
|
||||||
async (event, id, operateBookType) => await mjOpt.AddMJGenerateImageTask(id, operateBookType)
|
async (event, id, operateBookType, responseMessageName, coverData) =>
|
||||||
|
await mjOpt.AddMJGenerateImageTask(id, operateBookType, responseMessageName, coverData)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
src/main/IPCEvent/presetIpc.ts
Normal file
19
src/main/IPCEvent/presetIpc.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { ipcMain } from 'electron'
|
||||||
|
import { DEFINE_STRING } from '../../define/define_string'
|
||||||
|
import { PresetService } from '../Service/presetService'
|
||||||
|
let presetService = new PresetService()
|
||||||
|
function PresetIpc() {
|
||||||
|
|
||||||
|
// 获取人物的预设(只获取 lable 和 id)
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.PRESET.GET_CHARACTER_PRESET,
|
||||||
|
async (event) => await presetService.GetCharacterPreset()
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取场景的预设(只获取 lable 和 id)
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.PRESET.GET_SCENE_PRESET,
|
||||||
|
async (event) => await presetService.GetScenePreset()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export { PresetIpc }
|
||||||
@ -151,14 +151,14 @@ async function SettingIpc() {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 基础设置
|
//#region 基础设置(数据库)
|
||||||
// 获取软件的基础设置(初始的时候执行一次)
|
// 获取软件的基础设置(初始的时候执行一次)
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING,
|
DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING,
|
||||||
async (event) => await basicSetting.GetSoftwareSetting()
|
async (event) => await basicSetting.GetSoftwareSetting()
|
||||||
)
|
)
|
||||||
|
|
||||||
// 保存软件的基础设置
|
// 保存软件的通用设置
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING,
|
DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING,
|
||||||
async (event, value) => await basicSetting.SaveSoftWareSetting(value)
|
async (event, value) => await basicSetting.SaveSoftWareSetting(value)
|
||||||
|
|||||||
39
src/main/IPCEvent/taskIpc.ts
Normal file
39
src/main/IPCEvent/taskIpc.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { ipcMain } from "electron"
|
||||||
|
import { BookServiceBasic } from "../Service/ServiceBasic/bookServiceBasic"
|
||||||
|
import { DEFINE_STRING } from "../../define/define_string";
|
||||||
|
import { errorMessage, successMessage } from "../Public/generalTools";
|
||||||
|
import { BookBackTaskType, TaskExecuteType } from "../../define/enum/bookEnum";
|
||||||
|
|
||||||
|
let bookServiceBasic = new BookServiceBasic();
|
||||||
|
|
||||||
|
function TaskIpc() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加后台任务,单个
|
||||||
|
*/
|
||||||
|
ipcMain.handle(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, async (event, bookId: string, taskType: BookBackTaskType, executeType: TaskExecuteType, bookTaskId: string, bookTaskDetailId: string, responseMessageName: string) => {
|
||||||
|
try {
|
||||||
|
let res = await bookServiceBasic.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName)
|
||||||
|
return successMessage(res, `添加 ${taskType} 任务成功`, 'TaskIpc_AddBookBackTask');
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage(`添加 ${taskType} 任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddBookBackTask')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加多个后台任务
|
||||||
|
*/
|
||||||
|
ipcMain.handle(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, async (event, tasks: TaskModal.Task[]) => {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < tasks.length; i++) {
|
||||||
|
const element = tasks[i];
|
||||||
|
let res = await bookServiceBasic.AddBookBackTask(element.bookId, element.type, element.executeType, element.bookTaskId, element.bookTaskDetailId, element.messageName)
|
||||||
|
}
|
||||||
|
return successMessage(null, `添加多个任务成功`, 'TaskIpc_AddMultiBookBackTask');
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage(`添加多个任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddMultiBookBackTask')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export { TaskIpc }
|
||||||
@ -92,10 +92,9 @@ export class MJOriginalImageGenerate {
|
|||||||
LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER
|
LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
let result = []
|
||||||
for (let i = 0; i < value.length; i++) {
|
for (let i = 0; i < value.length; i++) {
|
||||||
const element = value[i]
|
const element = value[i]
|
||||||
|
|
||||||
let res_data = {
|
let res_data = {
|
||||||
code: 1,
|
code: 1,
|
||||||
id: element.id, // 当前 data 的ID
|
id: element.id, // 当前 data 的ID
|
||||||
@ -104,13 +103,12 @@ export class MJOriginalImageGenerate {
|
|||||||
|
|
||||||
// 获取当前的字幕数据
|
// 获取当前的字幕数据
|
||||||
let temp_sub = []
|
let temp_sub = []
|
||||||
for (let j = 0; element.suValue && j < element.suValue.length; j++) {
|
for (let j = 0; element.subValue && j < element.subValue.length; j++) {
|
||||||
const element = array[j]
|
temp_sub.push(element.subValue[j].srt_value)
|
||||||
temp_sub.push(element.srt_value)
|
|
||||||
}
|
}
|
||||||
let word = ''
|
let word = ''
|
||||||
if (temp_sub.length == 0) {
|
if (temp_sub.length == 0) {
|
||||||
word = element.after_gpt
|
word = element.after_gpt ? element.after_gpt : element.afterGpt
|
||||||
} else {
|
} else {
|
||||||
word = temp_sub.join(',')
|
word = temp_sub.join(',')
|
||||||
}
|
}
|
||||||
@ -144,11 +142,11 @@ export class MJOriginalImageGenerate {
|
|||||||
res_data.match_character.push(temp_item_data)
|
res_data.match_character.push(temp_item_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result.push(res_data)
|
||||||
// 开始往前端传递数据
|
// 开始往前端传递数据
|
||||||
this.sendChangeMessage(res_data, DEFINE_STRING.MJ.MACTH_USER_RETURN)
|
this.sendChangeMessage(res_data, DEFINE_STRING.MJ.MACTH_USER_RETURN)
|
||||||
}
|
}
|
||||||
return successMessage(null, '人物标签自动匹配完成', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER)
|
return successMessage(result, '人物标签自动匹配完成', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(
|
return errorMessage(
|
||||||
'通过文本自动匹配数据错误,错误信息如下:' + error.message,
|
'通过文本自动匹配数据错误,错误信息如下:' + error.message,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { DEFINE_STRING } from '../../define/define_string'
|
||||||
import { GeneralResponse } from '../../model/generalResponse'
|
import { GeneralResponse } from '../../model/generalResponse'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,11 +105,21 @@ function errorMessage(message: string, service?: string): GeneralResponse.ErrorI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动发送消息到前端,用作数据返回
|
||||||
|
* @param data 要返回的数据
|
||||||
|
* @param message_name 消息名称
|
||||||
|
*/
|
||||||
|
function SendReturnMessage(data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.GET_COPYWRITING_RETURN) {
|
||||||
|
global.newWindow[0].win.webContents.send(message_name, data)
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
checkStringValueAddSuffix,
|
checkStringValueAddSuffix,
|
||||||
checkStringValueAddPrefix,
|
checkStringValueAddPrefix,
|
||||||
checkStringValueDeletePrefix,
|
checkStringValueDeletePrefix,
|
||||||
checkStringValueDeleteSuffix,
|
checkStringValueDeleteSuffix,
|
||||||
successMessage,
|
successMessage,
|
||||||
errorMessage
|
errorMessage,
|
||||||
|
SendReturnMessage
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,10 +138,13 @@ export class BookBasic {
|
|||||||
watermarkPosition: undefined,
|
watermarkPosition: undefined,
|
||||||
})
|
})
|
||||||
// 文件重置,获取data下面的所有的子文件夹,删除所有的文件夹
|
// 文件重置,获取data下面的所有的子文件夹,删除所有的文件夹
|
||||||
let dirs = await GetSubdirectories(path.join(book.bookFolderPath, 'data'))
|
let bookData = path.join(book.bookFolderPath, 'data');
|
||||||
for (let i = 0; i < dirs.length; i++) {
|
if (await CheckFileOrDirExist(bookData)) {
|
||||||
const element = dirs[i];
|
let dirs = await GetSubdirectories(bookData)
|
||||||
await DeleteFolderAllFile(element, true)
|
for (let i = 0; i < dirs.length; i++) {
|
||||||
|
const element = dirs[i];
|
||||||
|
await DeleteFolderAllFile(element, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let scriptPath = path.join(book.bookFolderPath, 'script')
|
let scriptPath = path.join(book.bookFolderPath, 'script')
|
||||||
if (await CheckFileOrDirExist(scriptPath)) {
|
if (await CheckFileOrDirExist(scriptPath)) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { successMessage, errorMessage } from '../../Public/generalTools'
|
|||||||
import { BookBasic } from './BooKBasic'
|
import { BookBasic } from './BooKBasic'
|
||||||
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 { BookTaskService } from '../../../define/db/service/Book/bookTaskService'
|
||||||
import { define } from '../../../define/define.js'
|
import { define } from '../../../define/define'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { DEFINE_STRING } from "../../../define/define_string";
|
import { DEFINE_STRING } from "../../../define/define_string";
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
@ -299,6 +299,7 @@ export class ReverseBook {
|
|||||||
|
|
||||||
// TODO SD反推,待重写
|
// TODO SD反推,待重写
|
||||||
async SDReversePrompt(task: TaskModal.Task): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async SDReversePrompt(task: TaskModal.Task): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
console.log("SDReversePrompt", '')
|
||||||
return successMessage(null, "", "ReverseBook_SDReversePrompt")
|
return successMessage(null, "", "ReverseBook_SDReversePrompt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { isEmpty } from "lodash";
|
|||||||
import { DEFINE_STRING } from "../../../define/define_string";
|
import { DEFINE_STRING } from "../../../define/define_string";
|
||||||
import { ResponseMessageType } from "../../../define/enum/softwareEnum";
|
import { ResponseMessageType } from "../../../define/enum/softwareEnum";
|
||||||
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import fs from 'fs'
|
||||||
import util from 'util'
|
import util from 'util'
|
||||||
import { exec } from 'child_process'
|
import { exec } from 'child_process'
|
||||||
const execAsync = util.promisify(exec);
|
const execAsync = util.promisify(exec);
|
||||||
@ -44,7 +45,7 @@ export class BookImage {
|
|||||||
* @param id
|
* @param id
|
||||||
* @param operateBookType
|
* @param operateBookType
|
||||||
*/
|
*/
|
||||||
async ResetGenerateImage(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
async ResetGenerateImage(id: string, operateBookType: OperateBookType, coverData: boolean): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
try {
|
try {
|
||||||
let bookTaskDetails = undefined as Book.SelectBookTaskDetail[]
|
let bookTaskDetails = undefined as Book.SelectBookTaskDetail[]
|
||||||
let bookTask = undefined as Book.SelectBookTask
|
let bookTask = undefined as Book.SelectBookTask
|
||||||
@ -56,11 +57,15 @@ export class BookImage {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error('不支持的操作类型,请检查')
|
throw new Error('不支持的操作类型,请检查')
|
||||||
}
|
}
|
||||||
|
//这边过滤被锁定的数据
|
||||||
|
if (!coverData) {
|
||||||
|
bookTaskDetails = bookTaskDetails.filter(item => !item.imageLock)
|
||||||
|
}
|
||||||
|
|
||||||
if (bookTaskDetails.length <= 0) {
|
if (bookTaskDetails.length <= 0) {
|
||||||
throw new Error('没有要删除的分镜数据,请检查')
|
throw new Error('没有要删除的分镜数据,请检查')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 开始删除数据,要删除图片数据和出图的信息
|
// 开始删除数据,要删除图片数据和出图的信息
|
||||||
for (let i = 0; i < bookTaskDetails.length; i++) {
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
const element = bookTaskDetails[i];
|
const element = bookTaskDetails[i];
|
||||||
@ -69,12 +74,18 @@ export class BookImage {
|
|||||||
} else if (bookTask.imageCategory == BookImageCategory.D3) {
|
} else if (bookTask.imageCategory == BookImageCategory.D3) {
|
||||||
throw new Error('暂时不支持D3生成的图片删除')
|
throw new Error('暂时不支持D3生成的图片删除')
|
||||||
} else if (bookTask.imageCategory == BookImageCategory.SD) {
|
} else if (bookTask.imageCategory == BookImageCategory.SD) {
|
||||||
throw new Error('暂时不支持SD生成的图片删除')
|
await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('未知的小说类型,请检查')
|
throw new Error('未知的小说类型,请检查')
|
||||||
}
|
}
|
||||||
|
// 上面的信息重置完毕之后,开始删除文件信息
|
||||||
|
let outImage = element.outImagePath;
|
||||||
|
if (await CheckFileOrDirExist(outImage)) {
|
||||||
|
await fs.promises.unlink(outImage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return successMessage(bookTask.imageCategory, "删除所有的生图数据成功", "BookImage_ResetGenerateImage")
|
|
||||||
|
return successMessage(bookTaskDetails, "删除所有的生图数据成功", "BookImage_ResetGenerateImage")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("删除所有的图片数据失败,失败信息如下:" + error.toString(), "BookImage_ResetGenerateImage")
|
return errorMessage("删除所有的图片数据失败,失败信息如下:" + error.toString(), "BookImage_ResetGenerateImage")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,21 @@ import { isEmpty } from "lodash";
|
|||||||
import { BookType, OperateBookType } from "../../../define/enum/bookEnum";
|
import { BookType, OperateBookType } 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 { errorMessage, successMessage } from "../../Public/generalTools";
|
import { errorMessage, SendReturnMessage, successMessage } from "../../Public/generalTools";
|
||||||
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { GptService } from "../GPT/gpt";
|
||||||
|
import { ExecuteConcurrently } from "../../../define/Tools/common";
|
||||||
|
import { DEFINE_STRING } from "../../../define/define_string";
|
||||||
|
|
||||||
export class BookPrompt {
|
export class BookPrompt {
|
||||||
bookServiceBasic: BookServiceBasic
|
bookServiceBasic: BookServiceBasic
|
||||||
|
gptService: GptService
|
||||||
constructor() {
|
constructor() {
|
||||||
this.bookServiceBasic = new BookServiceBasic()
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
|
this.gptService = new GptService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region 反推的提示词相关
|
||||||
/**
|
/**
|
||||||
* 将MJ反推出来的数据,选择指定的写入到GPT提示词中
|
* 将MJ反推出来的数据,选择指定的写入到GPT提示词中
|
||||||
* @param bookId 小说的ID
|
* @param bookId 小说的ID
|
||||||
@ -39,7 +45,7 @@ export class BookPrompt {
|
|||||||
emptyName.push(element.name)
|
emptyName.push(element.name)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let reversePrompt = reversePrompts[index - 1]
|
let reversePrompt = reversePrompts[index - 1]
|
||||||
let gptPrompt = undefined
|
let gptPrompt = undefined
|
||||||
if (!isEmpty(reversePrompt.promptCN) && reversePrompt.promptCN != "") {
|
if (!isEmpty(reversePrompt.promptCN) && reversePrompt.promptCN != "") {
|
||||||
gptPrompt = reversePrompt.promptCN
|
gptPrompt = reversePrompt.promptCN
|
||||||
@ -102,7 +108,16 @@ export class BookPrompt {
|
|||||||
await this.bookServiceBasic.DeleteBookTaskDetailReversePromptById(element.id);
|
await this.bookServiceBasic.DeleteBookTaskDetailReversePromptById(element.id);
|
||||||
}
|
}
|
||||||
} else if (type == BookType.ORIGINAL) {
|
} else if (type == BookType.ORIGINAL) {
|
||||||
throw new Error("原创小说删除还不支持")
|
// 原创删除所有的反推提示词数据
|
||||||
|
this.bookServiceBasic.transaction(async (realm) => {
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const element = bookTaskDetails[i];
|
||||||
|
let btd = realm.objectForPrimaryKey('BookTaskDetail', element.id)
|
||||||
|
if (btd) {
|
||||||
|
btd.gptPrompt = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
} else if (type == BookType.SD_REVERSE) { }
|
} else if (type == BookType.SD_REVERSE) { }
|
||||||
else {
|
else {
|
||||||
throw new Error("SD反推删除还不支持")
|
throw new Error("SD反推删除还不支持")
|
||||||
@ -149,5 +164,98 @@ export class BookPrompt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 原创的提示词相关
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原创推理提示词
|
||||||
|
* @param id 要推理的ID
|
||||||
|
* @param operateBookType 操作的类型
|
||||||
|
* @param coverData 是不是要覆盖数据(用于推理空白提示词)
|
||||||
|
*/
|
||||||
|
async OriginalGetPrompt(id: string, operateBookType: OperateBookType, coverData: boolean): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let bookTask = undefined as Book.SelectBookTask
|
||||||
|
let bookTaskDetails = undefined as Book.SelectBookTaskDetail[]
|
||||||
|
let allBookTaskDetails = undefined as Book.SelectBookTaskDetail[]
|
||||||
|
|
||||||
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(id)
|
||||||
|
allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: id
|
||||||
|
})
|
||||||
|
if (!coverData) { // 不覆盖数据,只推理空白提示词
|
||||||
|
bookTaskDetails = allBookTaskDetails.filter(item => isEmpty(item.gptPrompt))
|
||||||
|
} else { // 不覆盖,就是全部
|
||||||
|
bookTaskDetails = allBookTaskDetails;
|
||||||
|
}
|
||||||
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
|
let singleBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id)
|
||||||
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(singleBookTaskDetail.bookTaskId)
|
||||||
|
bookTaskDetails = [singleBookTaskDetail]
|
||||||
|
} else if (operateBookType == OperateBookType.UNDERBOOKTASK) {
|
||||||
|
let singleBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id)
|
||||||
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(singleBookTaskDetail.bookTaskId)
|
||||||
|
// 开始计算上下文数据
|
||||||
|
allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: bookTask.id
|
||||||
|
})
|
||||||
|
for (let i = 0; i < allBookTaskDetails.length; i++) {
|
||||||
|
const element = allBookTaskDetails[i];
|
||||||
|
if (!bookTaskDetails) {
|
||||||
|
bookTaskDetails = []
|
||||||
|
}
|
||||||
|
if (i + 1 >= singleBookTaskDetail.no) {
|
||||||
|
bookTaskDetails.push(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('未知的操作类型');
|
||||||
|
}
|
||||||
|
if (!allBookTaskDetails) {
|
||||||
|
allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: bookTask.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bookTaskDetails.length <= 0) {
|
||||||
|
throw new Error('没有找到要推理的分镜数据')
|
||||||
|
}
|
||||||
|
|
||||||
|
let tasks = [] as Array<() => Promise<any>>
|
||||||
|
// 添加异步任务
|
||||||
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
||||||
|
const element = bookTaskDetails[i];
|
||||||
|
tasks.push(async () => {
|
||||||
|
let content = await this.gptService.OriginalInferencePrompt(element, allBookTaskDetails, global.config.gpt_count, bookTask.autoAnalyzeCharacter)
|
||||||
|
// 修改推理出来的数据
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(element.id, {
|
||||||
|
gptPrompt: content
|
||||||
|
})
|
||||||
|
// 每次完成,都要向前端返回信息
|
||||||
|
SendReturnMessage({
|
||||||
|
code: 1,
|
||||||
|
id: element.id,
|
||||||
|
data: {
|
||||||
|
content: content,
|
||||||
|
progress: {
|
||||||
|
current: i,
|
||||||
|
total: bookTaskDetails.length
|
||||||
|
} as GeneralResponse.ProgressResponse
|
||||||
|
}
|
||||||
|
}, DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT_RETURN);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 分批次执行异步任务
|
||||||
|
let res = await ExecuteConcurrently(tasks, global.config.task_number)
|
||||||
|
// 执行完毕
|
||||||
|
return successMessage(null, "推理所有数据完成", 'BookPrompt_OriginalGetPrompt')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("原创推理提示词失败,错误信息: " + error.toString(), 'BookPrompt_OriginalGetPrompt')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
341
src/main/Service/Flux/flux.ts
Normal file
341
src/main/Service/Flux/flux.ts
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
import { define } from '../../../define/define'
|
||||||
|
import fs from "fs";
|
||||||
|
import { ImageStyle } from "../Book/imageStyle";
|
||||||
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import axios from 'axios';
|
||||||
|
const fspromise = fs.promises
|
||||||
|
import path from 'path'
|
||||||
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFileExifData } from '../../../define/Tools/file';
|
||||||
|
import { Base64ToFile, GetImageBase64 } from '../../../define/Tools/image';
|
||||||
|
import { BookBackTaskStatus } from '../../../define/enum/bookEnum';
|
||||||
|
import { MJAction, MJImageType } from '../../../define/enum/mjEnum';
|
||||||
|
import { GptService } from '../GPT/gpt';
|
||||||
|
|
||||||
|
export class FluxOpt {
|
||||||
|
gptService: GptService
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
constructor() {
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
|
this.gptService = new GptService()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO 这边的设置应该改为数据库
|
||||||
|
/**
|
||||||
|
* 获取SD的设置,之后要删掉,改为数据库
|
||||||
|
*/
|
||||||
|
private async GetSDSetting() {
|
||||||
|
let sdSetting = JSON.parse(await fspromise.readFile(define.sd_setting, 'utf-8'))
|
||||||
|
return sdSetting
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region flux forge 生图
|
||||||
|
/**
|
||||||
|
* 使用flux forge生图
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async FluxForgeImage(task: TaskModal.Task): Promise<void> {
|
||||||
|
let sdSetting = undefined
|
||||||
|
try {
|
||||||
|
// 开始生图
|
||||||
|
sdSetting = await this.GetSDSetting()
|
||||||
|
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId);
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
|
||||||
|
let prompt = bookTaskDetail.prompt;
|
||||||
|
let url = sdSetting.setting.webui_api_url
|
||||||
|
if (url.endsWith('/')) {
|
||||||
|
url = url + "sdapi/v1/txt2img"
|
||||||
|
} else {
|
||||||
|
url = url + "/sdapi/v1/txt2img"
|
||||||
|
}
|
||||||
|
if (!isEmpty(sdSetting.webui.prompt)) {
|
||||||
|
prompt = sdSetting.webui.prompt + ', ' + prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前是不是有开修脸修手
|
||||||
|
let ADetailer = {
|
||||||
|
args: sdSetting.adetailer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 种子默认 -1,随机
|
||||||
|
let seed = -1;
|
||||||
|
let body = {
|
||||||
|
scheduler: 'Simple',
|
||||||
|
prompt: prompt,
|
||||||
|
seed: seed,
|
||||||
|
sampler_name: sdSetting.webui.sampler_name,
|
||||||
|
// 提示词相关性
|
||||||
|
cfg_scale: sdSetting.webui.cfg_scale,
|
||||||
|
distilled_cfg_scale: 3.5,
|
||||||
|
width: sdSetting.webui.width,
|
||||||
|
height: sdSetting.webui.height,
|
||||||
|
batch_size: sdSetting.setting.batch_size,
|
||||||
|
steps: sdSetting.webui.steps,
|
||||||
|
save_images: false,
|
||||||
|
tiling: false,
|
||||||
|
override_settings_restore_afterwards: true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bookTaskDetail.adetailer) {
|
||||||
|
body['alwayson_scripts'] = {
|
||||||
|
"ADetailer": ADetailer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post(url, body)
|
||||||
|
// TODO 对SD图片种子的一些处理,待定
|
||||||
|
// let info = JSON.parse(res.data.info)
|
||||||
|
// if (seed == -1) {
|
||||||
|
// seed = info.seed
|
||||||
|
// }
|
||||||
|
let images = response.data.images
|
||||||
|
let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage');
|
||||||
|
await CheckFolderExistsOrCreate(SdOriginalImage);
|
||||||
|
let outputFolder = bookTask.imageFolder;
|
||||||
|
await CheckFolderExistsOrCreate(outputFolder);
|
||||||
|
let inputFolder = path.join(book.bookFolderPath, 'tmp/input')
|
||||||
|
await CheckFolderExistsOrCreate(inputFolder);
|
||||||
|
|
||||||
|
let subImagePath = []
|
||||||
|
let outImagePath = ''
|
||||||
|
// 开始写出图片
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
const element = images[i];
|
||||||
|
// 包含info信息的图片地址
|
||||||
|
let infoImgPath = path.join(SdOriginalImage, `info_${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
// 不包含info信息的图片地址
|
||||||
|
let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
await Base64ToFile(element, infoImgPath)
|
||||||
|
// 这边去图片信息
|
||||||
|
await DeleteFileExifData(path.join(define.package_path, 'exittool/exiftool.exe'), infoImgPath, imgPath);
|
||||||
|
// 写出去
|
||||||
|
if (bookTask.name == 'output_00001') {
|
||||||
|
// 复制一个到input
|
||||||
|
let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, inputImgPath)
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
// 复制到对应的文件夹里面
|
||||||
|
let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, outPath)
|
||||||
|
outImagePath = outPath
|
||||||
|
}
|
||||||
|
subImagePath.push(imgPath)
|
||||||
|
}
|
||||||
|
// 修改数据库
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
outImagePath: path.relative(define.project_path, outImagePath),
|
||||||
|
subImagePath: subImagePath.map((item) => path.relative(define.project_path, item))
|
||||||
|
})
|
||||||
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
|
id: task.id,
|
||||||
|
status: BookBackTaskStatus.DONE
|
||||||
|
});
|
||||||
|
let resp = {
|
||||||
|
mjApiUrl: url,
|
||||||
|
progress: 100,
|
||||||
|
category: MJImageType.FLUX_FORGE,
|
||||||
|
imageClick: subImagePath.join(','),
|
||||||
|
imageShow: subImagePath.join(','),
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "success",
|
||||||
|
subImagePath: subImagePath,
|
||||||
|
outImagePath: outImagePath,
|
||||||
|
message: "FLUX FORGE 生成图片成功"
|
||||||
|
}
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp)
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 1,
|
||||||
|
message: "FLUX FORGE 生成图片成功",
|
||||||
|
data: {
|
||||||
|
...resp,
|
||||||
|
id: bookTaskDetail.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
let errorMsg = "FLUX FORGE 生成图片失败,错误信息如下:" + error.toString()
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
|
mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "",
|
||||||
|
progress: 0,
|
||||||
|
category: MJImageType.FLUX_FORGE,
|
||||||
|
imageClick: "",
|
||||||
|
imageShow: "",
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "error",
|
||||||
|
message: errorMsg
|
||||||
|
})
|
||||||
|
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 0,
|
||||||
|
message: errorMsg,
|
||||||
|
data: {
|
||||||
|
status: 'error',
|
||||||
|
message: errorMsg,
|
||||||
|
id: task.bookTaskDetailId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//#region flux api
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 FLUX API 请求
|
||||||
|
* @param url 请求的地址
|
||||||
|
* @param key 请求的key
|
||||||
|
* @param body 请求的请求体
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async FluxAPIImageRequest(url: string, key: string, body: { model: string; prompt: string; size: string; }): Promise<string> {
|
||||||
|
let response = await axios.post(url, { ...body, n: 1 }, {
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer ' + key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.data && response.data.data && response.data.data.length > 0) {
|
||||||
|
return response.data.data[0].url
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 FLUX API 生成图片
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async FluxAPIImage(task: TaskModal.Task): Promise<void> {
|
||||||
|
let sdSetting = undefined
|
||||||
|
try {
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId);
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
sdSetting = await this.GetSDSetting()
|
||||||
|
await this.gptService.RefreshGptSetting();
|
||||||
|
|
||||||
|
let prompt = bookTaskDetail.prompt;
|
||||||
|
let requestUrl = this.gptService.gptUrl
|
||||||
|
let uil = new URL(requestUrl);
|
||||||
|
let url = `${uil.protocol}//${uil.hostname}` + "/v1/images/generations"
|
||||||
|
|
||||||
|
if (!isEmpty(sdSetting.webui.prompt)) {
|
||||||
|
prompt = sdSetting.webui.prompt + ', ' + prompt
|
||||||
|
}
|
||||||
|
let size = `${sdSetting.webui.width}x${sdSetting.webui.height}`
|
||||||
|
let model = sdSetting.flux.model
|
||||||
|
// 一次请求生成一张 多个请求
|
||||||
|
|
||||||
|
let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage');
|
||||||
|
await CheckFolderExistsOrCreate(SdOriginalImage);
|
||||||
|
let outputFolder = bookTask.imageFolder;
|
||||||
|
await CheckFolderExistsOrCreate(outputFolder);
|
||||||
|
let inputFolder = path.join(book.bookFolderPath, 'tmp/input')
|
||||||
|
await CheckFolderExistsOrCreate(inputFolder);
|
||||||
|
|
||||||
|
let outImagePath = ''
|
||||||
|
let subImagePath = []
|
||||||
|
|
||||||
|
let batchSize = sdSetting.setting.batch_size;
|
||||||
|
for (let i = 0; i < batchSize; i++) {
|
||||||
|
const element = batchSize;
|
||||||
|
let imageUrl = await this.FluxAPIImageRequest(url, this.gptService.gptApiKey, {
|
||||||
|
model: model,
|
||||||
|
prompt: prompt,
|
||||||
|
size: size
|
||||||
|
})
|
||||||
|
// 这边开始处理返回的数据
|
||||||
|
if (isEmpty(imageUrl)) {
|
||||||
|
throw new Error('FLUX 生图返回的图片地址为空')
|
||||||
|
}
|
||||||
|
// 下载指定的文件
|
||||||
|
let base64 = await GetImageBase64(imageUrl)
|
||||||
|
// 将base64 写出
|
||||||
|
let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
await Base64ToFile(base64, imgPath);
|
||||||
|
|
||||||
|
// 写出去
|
||||||
|
if (bookTask.name == 'output_00001') {
|
||||||
|
// 复制一个到input
|
||||||
|
let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, inputImgPath)
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
// 复制到对应的文件夹里面
|
||||||
|
let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, outPath)
|
||||||
|
outImagePath = outPath
|
||||||
|
}
|
||||||
|
subImagePath.push(imgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束 开始返回
|
||||||
|
// 修改数据库
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
outImagePath: path.relative(define.project_path, outImagePath),
|
||||||
|
subImagePath: subImagePath.map((item) => path.relative(define.project_path, item))
|
||||||
|
})
|
||||||
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
|
id: task.id,
|
||||||
|
status: BookBackTaskStatus.DONE
|
||||||
|
});
|
||||||
|
let resp = {
|
||||||
|
mjApiUrl: url,
|
||||||
|
progress: 100,
|
||||||
|
category: MJImageType.FLUX_API,
|
||||||
|
imageClick: subImagePath.join(','),
|
||||||
|
imageShow: subImagePath.join(','),
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "success",
|
||||||
|
subImagePath: subImagePath,
|
||||||
|
outImagePath: outImagePath,
|
||||||
|
message: "FLUX API 生成图片成功"
|
||||||
|
}
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp)
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 1,
|
||||||
|
message: "FLUX API 生成图片成功",
|
||||||
|
data: {
|
||||||
|
...resp,
|
||||||
|
id: bookTaskDetail.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
let errorMsg = "FLUX API 生成图片失败,错误信息如下:" + error.toString()
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
|
mjApiUrl: "",
|
||||||
|
progress: 0,
|
||||||
|
category: MJImageType.FLUX_API,
|
||||||
|
imageClick: "",
|
||||||
|
imageShow: "",
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "error",
|
||||||
|
message: errorMsg,
|
||||||
|
})
|
||||||
|
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 0,
|
||||||
|
message: errorMsg,
|
||||||
|
data: {
|
||||||
|
status: 'error',
|
||||||
|
message: errorMsg,
|
||||||
|
id: task.bookTaskDetailId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/main/Service/Flux/fluxService.ts
Normal file
0
src/main/Service/Flux/fluxService.ts
Normal file
@ -2,6 +2,7 @@ import { isEmpty } from "lodash";
|
|||||||
import { gptDefine } from "../../../define/gptDefine";
|
import { gptDefine } from "../../../define/gptDefine";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { RetryWithBackoff } from "../../../define/Tools/common";
|
import { RetryWithBackoff } from "../../../define/Tools/common";
|
||||||
|
import { Book } from "../../../model/book";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一些GPT相关的服务都在这边
|
* 一些GPT相关的服务都在这边
|
||||||
@ -103,6 +104,7 @@ export class GptService {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region GPT 通用请求
|
||||||
/**
|
/**
|
||||||
* 发送GPT请求
|
* 发送GPT请求
|
||||||
* @param {*} message 请求的信息
|
* @param {*} message 请求的信息
|
||||||
@ -138,9 +140,146 @@ export class GptService {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 繁体中文 -> 简体中文
|
//#region 原创推理
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前分镜的上下文数据
|
||||||
|
* @param currentBookTaskDetail 当前分镜数据
|
||||||
|
* @param bookTaskDetails 所有的小说分镜数据
|
||||||
|
* @param contextCount 上下文行数
|
||||||
|
*/
|
||||||
|
GetBookTaskDetailContextData(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number): string {
|
||||||
|
let prefix = "";
|
||||||
|
// 拼接一个word
|
||||||
|
let i = currentBookTaskDetail.no - 1
|
||||||
|
if (i <= contextCount) {
|
||||||
|
prefix = bookTaskDetails
|
||||||
|
.filter((item, index) => index < i)
|
||||||
|
.map((item) => item.afterGpt)
|
||||||
|
.join('\r\n')
|
||||||
|
} else if (i > contextCount) {
|
||||||
|
prefix = bookTaskDetails
|
||||||
|
.filter((item, index) => i - index <= contextCount && i - index > 0)
|
||||||
|
.map((item) => item.afterGpt)
|
||||||
|
.join('\r\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
let suffix = "";
|
||||||
|
let o_i = bookTaskDetails.length - i
|
||||||
|
if (o_i <= contextCount) {
|
||||||
|
suffix = bookTaskDetails
|
||||||
|
.filter((item, index) => index > i)
|
||||||
|
.map((item) => item.afterGpt)
|
||||||
|
.join('\r\n')
|
||||||
|
} else if (o_i > contextCount) {
|
||||||
|
suffix = bookTaskDetails
|
||||||
|
.filter((item, index) => index - i <= contextCount && index - i > 0)
|
||||||
|
.map((item) => item.afterGpt)
|
||||||
|
.join('\r\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${prefix}\r\n${currentBookTaskDetail.afterGpt}\r\n${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回当前推理数据的请求体中的message
|
||||||
|
* @param currentBookTaskDetail 当前推理的提示词数据
|
||||||
|
* @param contextData 上下文数据
|
||||||
|
* @param autoAnalyzeCharacter 自动分析的角色数据
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
GetGPTRequestMessage(currentBookTaskDetail: Book.SelectBookTaskDetail, contextData: string, autoAnalyzeCharacter: string): any[] {
|
||||||
|
let message = []
|
||||||
|
if (
|
||||||
|
['superSinglePrompt', 'onlyPromptMJ', 'superSinglePromptChinese'].includes(
|
||||||
|
global.config.gpt_auto_inference
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// 有返回案例的
|
||||||
|
message = gptDefine.GetExamplePromptMessage(global.config.gpt_auto_inference)
|
||||||
|
// 加当前提问的
|
||||||
|
message.push({
|
||||||
|
role: 'user',
|
||||||
|
content: currentBookTaskDetail.afterGpt
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 直接返回,没有案例的
|
||||||
|
message = [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: gptDefine.getSystemContentByType(global.config.gpt_auto_inference, {
|
||||||
|
textContent: contextData,
|
||||||
|
characterContent: autoAnalyzeCharacter
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: gptDefine.getUserContentByType(global.config.gpt_auto_inference, {
|
||||||
|
textContent: currentBookTaskDetail.afterGpt,
|
||||||
|
wordCount:
|
||||||
|
global.config.gpt_model && global.config.gpt_model.includes('gpt-4')
|
||||||
|
? '20'
|
||||||
|
: '40'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原创推理提示词数据
|
||||||
|
* @param currentBookTaskDetail 要推理的小说分镜任务
|
||||||
|
* @param bookTaskDetails 所有的小说分镜任务
|
||||||
|
* @param contextCount 上下文的数量
|
||||||
|
* @param autoAnalyzeCharacter 自动分析的角色数据字符串
|
||||||
|
*/
|
||||||
|
async OriginalInferencePrompt(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number, autoAnalyzeCharacter: string) {
|
||||||
|
let gptPromptType = global.config.gpt_auto_inference;
|
||||||
|
let message = []
|
||||||
|
if (gptPromptType == "customize") { //自定义模式
|
||||||
|
// 自定义模式
|
||||||
|
// 获取当前自定义的推理提示词
|
||||||
|
let customize_gpt_prompt = (
|
||||||
|
await gptDefine.getGptDataByTypeAndProperty('dynamic', 'customize_gpt_prompt', [])
|
||||||
|
).data
|
||||||
|
let index = customize_gpt_prompt.findIndex(
|
||||||
|
(item: any) => item.id == global.config.customize_gpt_prompt
|
||||||
|
)
|
||||||
|
if (global.config.customize_gpt_prompt && index < 0) {
|
||||||
|
throw new Error('自定义推理时要选择对应的自定义推理词')
|
||||||
|
}
|
||||||
|
message = gptDefine.CustomizeGptPrompt(customize_gpt_prompt[index], currentBookTaskDetail.afterGpt)
|
||||||
|
message.push({
|
||||||
|
role: 'user',
|
||||||
|
content: currentBookTaskDetail.afterGpt
|
||||||
|
})
|
||||||
|
} else { // 内置模式
|
||||||
|
let context = this.GetBookTaskDetailContextData(currentBookTaskDetail, bookTaskDetails, contextCount);
|
||||||
|
message = this.GetGPTRequestMessage(currentBookTaskDetail, context, autoAnalyzeCharacter);
|
||||||
|
}
|
||||||
|
// 开始请求
|
||||||
|
let res = await RetryWithBackoff(async () => {
|
||||||
|
return this.FetchGpt(message)
|
||||||
|
}, 5, 1000)
|
||||||
|
if (res) {
|
||||||
|
if (res) {
|
||||||
|
res = res
|
||||||
|
.replace(/\)\s*\(/g, ', ')
|
||||||
|
.replace(/^\(/, '')
|
||||||
|
.replace(/\)$/, '')
|
||||||
|
.replaceAll('*', '')
|
||||||
|
.replaceAll('--', ' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 中文 繁体转简体
|
||||||
/**
|
/**
|
||||||
* 将繁体中文转换为简体中文
|
* 将繁体中文转换为简体中文
|
||||||
* @param traditionalText 繁体中文文本
|
* @param traditionalText 繁体中文文本
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { isEmpty, join } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import { Book } from "../../../model/book";
|
import { Book } from "../../../model/book";
|
||||||
import { checkStringValueAddPrefix, checkStringValueAddSuffix, errorMessage, successMessage } from "../../Public/generalTools";
|
import { checkStringValueAddPrefix, checkStringValueAddSuffix, errorMessage, successMessage } from "../../Public/generalTools";
|
||||||
import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService";
|
|
||||||
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
|
||||||
import { CheckFolderExistsOrCreate, CopyFileOrFolder, JoinPath } from "../../../define/Tools/file";
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder, JoinPath } from "../../../define/Tools/file";
|
||||||
import { define } from "../../../define/define"
|
import { define } from "../../../define/define"
|
||||||
import { CompressImageToSize, GetImageBase64, ImageSplit } from "../../../define/Tools/image";
|
import { CompressImageToSize, GetImageBase64, ImageSplit } from "../../../define/Tools/image";
|
||||||
@ -14,14 +12,12 @@ import { MJRespoonseType } from "../../../define/enum/mjEnum";
|
|||||||
import { MJSetting } from "../../../model/Setting/mjSetting";
|
import { MJSetting } from "../../../model/Setting/mjSetting";
|
||||||
import { GeneralResponse } from "../../../model/generalResponse"
|
import { GeneralResponse } from "../../../model/generalResponse"
|
||||||
import { LoggerStatus, ResponseMessageType } from "../../../define/enum/softwareEnum";
|
import { LoggerStatus, ResponseMessageType } from "../../../define/enum/softwareEnum";
|
||||||
import { BookTaskService } from "../../../define/db/service/Book/bookTaskService";
|
|
||||||
import { ReverseBook } from "../Book/ReverseBook";
|
|
||||||
import { ImageStyle } from "../Book/imageStyle";
|
import { ImageStyle } from "../Book/imageStyle";
|
||||||
import { TaskScheduler } from "../taskScheduler";
|
import { TaskScheduler } from "../taskScheduler";
|
||||||
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 { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { PresetService } from "../presetService";
|
||||||
|
import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic";
|
||||||
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
@ -29,53 +25,42 @@ import fs from "fs"
|
|||||||
const fspromise = fs.promises
|
const fspromise = fs.promises
|
||||||
|
|
||||||
export class MJOpt {
|
export class MJOpt {
|
||||||
bookBackTaskList: BookBackTaskListService
|
|
||||||
bookTaskDetail: BookTaskDetailService
|
|
||||||
reverseBook: ReverseBook;
|
|
||||||
bookTaskService: BookTaskService
|
|
||||||
mjApi: MJApi;
|
mjApi: MJApi;
|
||||||
mjSetting: MJSetting.MjSetting
|
mjSetting: MJSetting.MjSetting
|
||||||
imageStyle: ImageStyle;
|
imageStyle: ImageStyle;
|
||||||
taskScheduler: TaskScheduler;
|
taskScheduler: TaskScheduler;
|
||||||
bookService: BookService
|
|
||||||
tools: Tools;
|
tools: Tools;
|
||||||
mjSettingService: MJSettingService;
|
|
||||||
bookServiceBasic: BookServiceBasic
|
bookServiceBasic: BookServiceBasic
|
||||||
|
presetService: PresetService
|
||||||
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
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();
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
|
this.presetService = new PresetService()
|
||||||
|
this.mjApi = new MJApi()
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic()
|
||||||
}
|
}
|
||||||
async InitService() {
|
|
||||||
if (!this.reverseBook) {
|
/**
|
||||||
this.reverseBook = new ReverseBook()
|
* 获取MJ设置
|
||||||
|
*/
|
||||||
|
async GetMJSetting() {
|
||||||
|
if (!this.mjSetting) {
|
||||||
|
this.mjSetting = await this.softWareServiceBasic.GetMjSetting()
|
||||||
}
|
}
|
||||||
if (!this.bookBackTaskList) {
|
|
||||||
this.bookBackTaskList = await BookBackTaskListService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.bookTaskDetail) {
|
|
||||||
this.bookTaskDetail = await BookTaskDetailService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.mjApi) {
|
|
||||||
this.mjApi = new MJApi()
|
|
||||||
}
|
|
||||||
if (!this.bookTaskService) {
|
|
||||||
this.bookTaskService = await BookTaskService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.bookService) {
|
|
||||||
this.bookService = await BookService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.mjSettingService) {
|
|
||||||
this.mjSettingService = await MJSettingService.getInstance()
|
|
||||||
}
|
|
||||||
this.mjSetting = await this.mjApi.InitMJSetting()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回MJ的数据到前端界面,前端界面做出相应的改变
|
* 返回MJ的数据到前端界面,前端界面做出相应的改变
|
||||||
* @param {*} data
|
* @param {*} data
|
||||||
*/
|
*/
|
||||||
sendChangeMessage(data: GeneralResponse.MessageResponse, message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN) {
|
sendChangeMessage(data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.MAIN_DATA_RETURN) {
|
||||||
|
if (!message_name) {
|
||||||
|
message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN
|
||||||
|
}
|
||||||
global.newWindow[0].win.webContents.send(message_name, data)
|
global.newWindow[0].win.webContents.send(message_name, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +73,8 @@ export class MJOpt {
|
|||||||
*/
|
*/
|
||||||
async SingleReverseToGptPrompt(bookTaskDetailId: string, index: number): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async SingleReverseToGptPrompt(bookTaskDetailId: string, index: number): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService();
|
await this.GetMJSetting()
|
||||||
let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(bookTaskDetailId)
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskDetailId)
|
||||||
if (bookTaskDetail == null) {
|
if (bookTaskDetail == null) {
|
||||||
throw new Error("没有找到对应的数据")
|
throw new Error("没有找到对应的数据")
|
||||||
}
|
}
|
||||||
@ -100,7 +85,7 @@ export class MJOpt {
|
|||||||
let reversePrompt = reversePrompts[index]
|
let reversePrompt = reversePrompts[index]
|
||||||
let gptPrompt = reversePrompt.promptCN ? reversePrompt.promptCN : reversePrompt.prompt
|
let gptPrompt = reversePrompt.promptCN ? reversePrompt.promptCN : reversePrompt.prompt
|
||||||
// 开始修改
|
// 开始修改
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetailId, {
|
||||||
gptPrompt: gptPrompt
|
gptPrompt: gptPrompt
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -125,14 +110,13 @@ export class MJOpt {
|
|||||||
try {
|
try {
|
||||||
// 执行你的操作
|
// 执行你的操作
|
||||||
let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id);
|
let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id);
|
||||||
|
|
||||||
// 判断他的状态是不是成功
|
// 判断他的状态是不是成功
|
||||||
if (task_res.code == 0) {
|
if (task_res.code == 0) {
|
||||||
// 反推失败
|
// 反推失败
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.REVERSE_FAIL
|
status: BookTaskStatus.REVERSE_FAIL
|
||||||
});
|
});
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.FAIL,
|
status: BookBackTaskStatus.FAIL,
|
||||||
errorMessage: task_res.message
|
errorMessage: task_res.message
|
||||||
@ -142,7 +126,7 @@ export class MJOpt {
|
|||||||
if (task_res.progress == 100) {
|
if (task_res.progress == 100) {
|
||||||
task_res.type == MJRespoonseType.FINISHED;
|
task_res.type == MJRespoonseType.FINISHED;
|
||||||
|
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.DONE
|
status: BookBackTaskStatus.DONE
|
||||||
});
|
});
|
||||||
@ -162,7 +146,7 @@ export class MJOpt {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.REVERSE_DONE,
|
status: BookTaskStatus.REVERSE_DONE,
|
||||||
reversePrompt: reversePrompt,
|
reversePrompt: reversePrompt,
|
||||||
gptPrompt: undefined
|
gptPrompt: undefined
|
||||||
@ -175,7 +159,7 @@ export class MJOpt {
|
|||||||
type: ResponseMessageType.MJ_REVERSE,
|
type: ResponseMessageType.MJ_REVERSE,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
data: task_res
|
data: task_res
|
||||||
});
|
}, task.messageName);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// 当获取的图片的进度小于100的时候,等待5秒继续监听
|
// 当获取的图片的进度小于100的时候,等待5秒继续监听
|
||||||
@ -189,7 +173,7 @@ export class MJOpt {
|
|||||||
type: ResponseMessageType.MJ_REVERSE,
|
type: ResponseMessageType.MJ_REVERSE,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
data: task_res
|
data: task_res
|
||||||
});
|
}, task.messageName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -205,9 +189,8 @@ export class MJOpt {
|
|||||||
if (isEmpty(task.bookTaskDetailId)) {
|
if (isEmpty(task.bookTaskDetailId)) {
|
||||||
throw new Error("MJ反推,没有找到对应的分镜信息")
|
throw new Error("MJ反推,没有找到对应的分镜信息")
|
||||||
}
|
}
|
||||||
await this.InitService()
|
await this.GetMJSetting()
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
|
||||||
|
|
||||||
let oldImagePath = bookTaskDetail.oldImage
|
let oldImagePath = bookTaskDetail.oldImage
|
||||||
if (isEmpty(oldImagePath)) {
|
if (isEmpty(oldImagePath)) {
|
||||||
@ -228,7 +211,7 @@ export class MJOpt {
|
|||||||
})
|
})
|
||||||
if (reqRes == '23') {
|
if (reqRes == '23') {
|
||||||
// 任务队列过多,重新提交排队
|
// 任务队列过多,重新提交排队
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.RECONNECT,
|
status: BookBackTaskStatus.RECONNECT,
|
||||||
})
|
})
|
||||||
@ -236,7 +219,7 @@ export class MJOpt {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.REVERSE
|
status: BookTaskStatus.REVERSE
|
||||||
})
|
})
|
||||||
this.sendChangeMessage({
|
this.sendChangeMessage({
|
||||||
@ -248,18 +231,18 @@ export class MJOpt {
|
|||||||
type: MJRespoonseType.UPDATED,
|
type: MJRespoonseType.UPDATED,
|
||||||
mjType: MJAction.DESCRIBE,
|
mjType: MJAction.DESCRIBE,
|
||||||
category: this.mjSetting.type,
|
category: this.mjSetting.type,
|
||||||
message_id: reqRes,
|
messageId: reqRes,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
status: "success"
|
status: "success"
|
||||||
} as MJ.MJResponseToFront
|
} as MJ.MJResponseToFront
|
||||||
})
|
}, task.messageName)
|
||||||
|
|
||||||
await this.fetchWithRetry(task, reqRes);
|
await this.fetchWithRetry(task, reqRes);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
let errorMsg = "MJ反推失败,失败信息如下:" + error.toString()
|
let errorMsg = "MJ反推失败,失败信息如下:" + error.toString()
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.FAIL,
|
status: BookBackTaskStatus.FAIL,
|
||||||
errorMessage: errorMsg
|
errorMessage: errorMsg
|
||||||
@ -275,13 +258,13 @@ export class MJOpt {
|
|||||||
type: MJRespoonseType.UPDATED,
|
type: MJRespoonseType.UPDATED,
|
||||||
mjType: MJAction.DESCRIBE,
|
mjType: MJAction.DESCRIBE,
|
||||||
category: this.mjSetting.type,
|
category: this.mjSetting.type,
|
||||||
message_id: undefined,
|
messageId: undefined,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
message: error.toString(),
|
message: error.toString(),
|
||||||
status: "failure"
|
status: "failure"
|
||||||
}
|
}
|
||||||
})
|
}, task.messageName)
|
||||||
return errorMessage(errorMsg, "MJReverse_MJImage2Text")
|
return errorMessage(errorMsg, "MJReverse_MJImage2Text")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,6 +272,59 @@ export class MJOpt {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 合并提示词相关
|
//#region 合并提示词相关
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取场景的提示词
|
||||||
|
* @param ids 需要获取的IDs
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetScenePresetStringByIds(ids: string[]): Promise<string> {
|
||||||
|
let sceneString = ''
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
const id = ids[i];
|
||||||
|
let scene = await this.presetService.GetScenePresetDetailById(id)
|
||||||
|
if (scene.code == 1) {
|
||||||
|
// 这边开始拼接
|
||||||
|
sceneString += scene.data.prompt + ', '
|
||||||
|
} else {
|
||||||
|
throw new Error(scene.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sceneString
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取人物提示词,包括垫图链接
|
||||||
|
* @param ids 需要获取的IDs
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetCharacterPresetStringByIds(ids: string[]): Promise<{ characterString: string, characterUrl: string }> {
|
||||||
|
let characterString = ''
|
||||||
|
let characterUrl = ''
|
||||||
|
let crefCw = undefined
|
||||||
|
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
const element = ids[i];
|
||||||
|
let character = await this.presetService.GetCharacterPresetDetailById(element)
|
||||||
|
if (character.code == 1) {
|
||||||
|
characterString += character.data.prompt + ', '
|
||||||
|
if (character.data.image_url && character.data.image_url != '' && character.data.cref_cw) {
|
||||||
|
characterUrl += ` ${character.data.image_url} `
|
||||||
|
crefCw = character.data.cref_cw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(character.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//这边坐下合并s
|
||||||
|
if (characterUrl != '') {
|
||||||
|
characterUrl = ` --cref ${characterUrl} --cw ${crefCw}`
|
||||||
|
}
|
||||||
|
return { characterString, characterUrl }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MJ 进行合并提示词,通过类型进行判断是单个还是全部合并
|
* MJ 进行合并提示词,通过类型进行判断是单个还是全部合并
|
||||||
* @param id 合并的ID
|
* @param id 合并的ID
|
||||||
@ -296,16 +332,14 @@ export class MJOpt {
|
|||||||
*/
|
*/
|
||||||
async MergePrompt(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async MergePrompt(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
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;
|
||||||
|
await this.GetMJSetting()
|
||||||
if (operateBookType == OperateBookType.BOOKTASK) {
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
bookTaskDetail = this.bookTaskDetail.GetBookTaskData({
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookTaskId: id
|
bookTaskId: id
|
||||||
}).data
|
})
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(id);
|
||||||
// 判断是不是有为空的
|
// 判断是不是有为空的
|
||||||
let emptyName = [] as string[]
|
let emptyName = [] as string[]
|
||||||
for (let i = 0; i < bookTaskDetail.length; i++) {
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
||||||
@ -323,11 +357,16 @@ export class MJOpt {
|
|||||||
throw new Error("当前分镜没有推理提示词,请先生成")
|
throw new Error("当前分镜没有推理提示词,请先生成")
|
||||||
}
|
}
|
||||||
bookTaskDetail = [tempBookTaskDetail]
|
bookTaskDetail = [tempBookTaskDetail]
|
||||||
bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("未知的合并类型")
|
throw new Error("未知的合并类型")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bookTaskDetail.length <= 0) {
|
||||||
|
throw new Error("没有找到对应的需要合并的分镜数据")
|
||||||
|
}
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
|
||||||
// 获取合并的排序
|
// 获取合并的排序
|
||||||
let imageBaseSetting = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')); // 没有就直接报错
|
let imageBaseSetting = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')); // 没有就直接报错
|
||||||
let promptSort = imageBaseSetting.prompt_sort; // 没有就直接报错
|
let promptSort = imageBaseSetting.prompt_sort; // 没有就直接报错
|
||||||
@ -336,11 +375,8 @@ export class MJOpt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// let suffixParam = imageBaseSetting.mj_config.image_suffix ; // 没有就直接报错
|
// let suffixParam = imageBaseSetting.mj_config.image_suffix ; // 没有就直接报错
|
||||||
let mjSettingDb = this.mjSettingService.GetMjSetting({}).data
|
let mjSettingDb = await this.softWareServiceBasic.GetMjSetting()
|
||||||
if (mjSettingDb.length <= 0) {
|
let suffixParam = mjSettingDb.imageSuffix
|
||||||
throw new Error("请先添加MJ配置")
|
|
||||||
}
|
|
||||||
let suffixParam = mjSettingDb[0].imageSuffix
|
|
||||||
|
|
||||||
// let styleString = '';
|
// let styleString = '';
|
||||||
// 拿到所有的风格
|
// 拿到所有的风格
|
||||||
@ -349,18 +385,33 @@ 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];
|
||||||
|
// 没有推理提示词,直接跳过
|
||||||
|
if (isEmpty(element.gptPrompt)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
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];
|
||||||
promptStr += `${'${' + element.value + '}'} `
|
promptStr += `${'${' + element.value + '}'} `
|
||||||
}
|
}
|
||||||
console.log(promptStr)
|
|
||||||
|
|
||||||
|
|
||||||
// TODO 后面需要完善人物和场景的提示词
|
// TODO 后面需要完善人物和场景的提示词
|
||||||
let characterString = '' // 人物
|
let characterString = '' // 人物
|
||||||
|
let characterUrl = ''
|
||||||
let sceneString = "" // 场景
|
let sceneString = "" // 场景
|
||||||
// 获取当前的自定义风格的垫图字符串
|
// 获取当前的自定义风格的垫图字符串
|
||||||
|
if (book.type == BookType.ORIGINAL) {
|
||||||
|
let sceneIds = element.sceneTags ? element.sceneTags : []
|
||||||
|
let characterIds = element.characterTags ? element.characterTags : []
|
||||||
|
if (sceneIds && sceneIds.length > 0) {
|
||||||
|
sceneString = await this.GetScenePresetStringByIds(sceneIds)
|
||||||
|
}
|
||||||
|
if (characterIds && characterIds.length > 0) {
|
||||||
|
let res = await this.GetCharacterPresetStringByIds(characterIds)
|
||||||
|
characterString = res.characterString
|
||||||
|
characterUrl = res.characterUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let styleString = ""
|
let styleString = ""
|
||||||
let style_url = ''
|
let style_url = ''
|
||||||
@ -404,9 +455,9 @@ export class MJOpt {
|
|||||||
promptStr = checkStringValueAddSuffix(promptStr, ',') + bookTask.suffixPrompt
|
promptStr = checkStringValueAddSuffix(promptStr, ',') + bookTask.suffixPrompt
|
||||||
}
|
}
|
||||||
promptStr = ' ' + promptStr;
|
promptStr = ' ' + promptStr;
|
||||||
promptStr += ` ${cref_url} ${style_url}${suffixParam}`
|
promptStr += ` ${characterUrl} ${style_url}${suffixParam}`
|
||||||
// 修改数据库数据
|
// 修改数据库数据
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(element.id, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(element.id, {
|
||||||
prompt: promptStr
|
prompt: promptStr
|
||||||
})
|
})
|
||||||
// 写回数据
|
// 写回数据
|
||||||
@ -416,7 +467,6 @@ export class MJOpt {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return successMessage(result, "MJ模式合并数据成功", "MJOpt_MergePrompt")
|
return successMessage(result, "MJ模式合并数据成功", "MJOpt_MergePrompt")
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("MJ合并提示词失败,错误信息如下:" + error.message, "MJOpt_MergePrompt")
|
return errorMessage("MJ合并提示词失败,错误信息如下:" + error.message, "MJOpt_MergePrompt")
|
||||||
}
|
}
|
||||||
@ -430,29 +480,32 @@ export class MJOpt {
|
|||||||
* @param id 要添加的ID
|
* @param id 要添加的ID
|
||||||
* @param operateBookType 操作的类型
|
* @param operateBookType 操作的类型
|
||||||
*/
|
*/
|
||||||
async AddMJGenerateImageTask(id: string, operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async AddMJGenerateImageTask(id: string, operateBookType: OperateBookType, responseMessageName: string = null, coverData: boolean = true): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
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 (operateBookType == OperateBookType.BOOKTASK) {
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
bookTaskDetail = this.bookTaskDetail.GetBookTaskData({
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookTaskId: id
|
bookTaskId: id
|
||||||
}).data
|
})
|
||||||
|
if (!coverData) {
|
||||||
|
// 过滤掉已经生成的数据
|
||||||
|
bookTaskDetail = bookTaskDetail.filter((item) => !item.mjMessage)
|
||||||
|
}
|
||||||
// bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
// bookTask = this.bookTaskService.GetBookTaskDataById(id);
|
||||||
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
} else if (operateBookType == OperateBookType.BOOKTASKDETAIL) {
|
||||||
bookTaskDetail = [this.bookTaskDetail.GetBookTaskDetailDataById(id)]
|
let bookTaskDetailRes = await this.bookServiceBasic.GetBookTaskDetailDataById(id)
|
||||||
|
bookTaskDetail = [bookTaskDetailRes]
|
||||||
// bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
// bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId);
|
||||||
} else if (operateBookType == OperateBookType.UNDERBOOKTASK) {
|
} else if (operateBookType == OperateBookType.UNDERBOOKTASK) {
|
||||||
let thisBookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(id);
|
let thisBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id);
|
||||||
if (thisBookTaskDetail == null) {
|
if (thisBookTaskDetail == null) {
|
||||||
throw new Error("没有找到对应的数据")
|
throw new Error("没有找到对应的数据")
|
||||||
}
|
}
|
||||||
// 获取批次的所有数据
|
// 获取批次的所有数据
|
||||||
bookTaskDetail = this.bookTaskDetail.GetBookTaskData({
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookTaskId: thisBookTaskDetail.bookTaskId
|
bookTaskId: thisBookTaskDetail.bookTaskId
|
||||||
}).data
|
})
|
||||||
// bookTask = this.bookTaskService.GetBookTaskDataById(thisBookTaskDetail.bookTaskId);
|
// bookTask = this.bookTaskService.GetBookTaskDataById(thisBookTaskDetail.bookTaskId);
|
||||||
bookTaskDetail = bookTaskDetail.filter((item) => item.no >= thisBookTaskDetail.no) // 需要包含自己
|
bookTaskDetail = bookTaskDetail.filter((item) => item.no >= thisBookTaskDetail.no) // 需要包含自己
|
||||||
}
|
}
|
||||||
@ -469,13 +522,10 @@ 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 taskRes = await this.bookBackTaskList.AddBookBackTask(element.bookId, BookBackTaskType.MJ_IMAGE, TaskExecuteType.AUTO, element.bookTaskId, element.id
|
let taskRes = await this.bookServiceBasic.AddBookBackTask(element.bookId, BookBackTaskType.MJ_IMAGE, TaskExecuteType.AUTO, element.bookTaskId, element.id, responseMessageName
|
||||||
);
|
);
|
||||||
if (taskRes.code == 0) {
|
|
||||||
throw new Error(taskRes.message)
|
|
||||||
}
|
|
||||||
// 添加返回日志
|
// 添加返回日志
|
||||||
await this.taskScheduler.AddLogToDB(element.bookId, BookBackTaskType.MJ_IMAGE, `添加 ${element.name} MJ生成视频任务成功`, element.bookTaskId, LoggerStatus.SUCCESS)
|
await this.taskScheduler.AddLogToDB(element.bookId, BookBackTaskType.MJ_IMAGE, `添加 ${element.name} MJ生成任务成功`, element.bookTaskId, LoggerStatus.SUCCESS)
|
||||||
}
|
}
|
||||||
// 全部完毕
|
// 全部完毕
|
||||||
return successMessage(null, "MJ添加生成图片任务成功", "MJOpt_AddGenerateImageTask")
|
return successMessage(null, "MJ添加生成图片任务成功", "MJOpt_AddGenerateImageTask")
|
||||||
@ -492,30 +542,32 @@ export class MJOpt {
|
|||||||
async FetchImageTask(task: TaskModal.Task, reqRes: string, book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetail: Book.SelectBookTaskDetail) {
|
async FetchImageTask(task: TaskModal.Task, reqRes: string, book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetail: Book.SelectBookTaskDetail) {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
|
await this.GetMJSetting()
|
||||||
// 执行你的操作
|
// 执行你的操作
|
||||||
let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id);
|
let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id);
|
||||||
task_res.id = task.bookTaskDetailId;
|
task_res.id = task.bookTaskDetailId;
|
||||||
// 判断他的状态是不是成功
|
// 判断他的状态是不是成功
|
||||||
if (task_res.code == 0) {
|
if (task_res.code == 0) {
|
||||||
// 生图失败
|
// 生图失败
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.IMAGE_FAIL,
|
status: BookTaskStatus.IMAGE_FAIL,
|
||||||
});
|
});
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
let errorMsg = `MJ生成图片失败,失败信息如下:${task_res.message}`
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
mjApiUrl: this.mjApi.imagineUrl,
|
mjApiUrl: this.mjApi.imagineUrl,
|
||||||
progress: 0,
|
progress: 100,
|
||||||
category: this.mjApi.mjSetting.type,
|
category: this.mjApi.mjSetting.type,
|
||||||
imageClick: task_res.image_click,
|
imageClick: task_res.imageClick,
|
||||||
imageShow: task_res.image_show,
|
imageShow: task_res.imageShow,
|
||||||
messageId: task_res.message_id,
|
messageId: task_res.messageId,
|
||||||
action: MJAction.IMAGINE,
|
action: MJAction.IMAGINE,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
message: task_res.message
|
message: errorMsg
|
||||||
})
|
})
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.FAIL,
|
status: BookBackTaskStatus.FAIL,
|
||||||
errorMessage: task_res.message
|
errorMessage: errorMsg
|
||||||
});
|
});
|
||||||
this.sendChangeMessage({
|
this.sendChangeMessage({
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -523,24 +575,25 @@ export class MJOpt {
|
|||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
data: {
|
data: {
|
||||||
...task_res,
|
...task_res,
|
||||||
status: "error"
|
status: "error",
|
||||||
|
message: errorMsg
|
||||||
},
|
},
|
||||||
message: task_res.message
|
message: errorMsg
|
||||||
});
|
}, task.messageName);
|
||||||
return;
|
return;
|
||||||
// throw new Error(`${task_res.message}`);
|
// throw new Error(`${task_res.message}`);
|
||||||
} else {
|
} else {
|
||||||
if (task_res.progress == 100) {
|
if (task_res.progress == 100) {
|
||||||
task_res.type == MJRespoonseType.FINISHED;
|
task_res.type == MJRespoonseType.FINISHED;
|
||||||
console.log(task.id, "22222")
|
console.log(task.id, "22222")
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.DONE
|
status: BookBackTaskStatus.DONE
|
||||||
});
|
});
|
||||||
// 下载图片
|
// 下载图片
|
||||||
let imagePath = path.join(book.bookFolderPath, `data\\MJOriginalImage\\${task_res.message_id}.png`);
|
let imagePath = path.join(book.bookFolderPath, `data\\MJOriginalImage\\${task_res.messageId}.png`);
|
||||||
await CheckFolderExistsOrCreate(path.dirname(imagePath))
|
await CheckFolderExistsOrCreate(path.dirname(imagePath))
|
||||||
await this.tools.downloadFileUrl(task_res.image_click, imagePath)
|
await this.tools.downloadFileUrl(task_res.imageClick, imagePath)
|
||||||
|
|
||||||
// 进行图片裁剪
|
// 进行图片裁剪
|
||||||
let imageRes = await ImageSplit(imagePath, bookTaskDetail.name, path.join(book.bookFolderPath, 'data\\MJOriginalImage'));
|
let imageRes = await ImageSplit(imagePath, bookTaskDetail.name, path.join(book.bookFolderPath, 'data\\MJOriginalImage'));
|
||||||
@ -560,17 +613,17 @@ export class MJOpt {
|
|||||||
|
|
||||||
task_res.id = task.bookTaskDetailId;
|
task_res.id = task.bookTaskDetailId;
|
||||||
// 修改分镜的数据
|
// 修改分镜的数据
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
outImagePath: path.relative(define.project_path, out_file),
|
outImagePath: path.relative(define.project_path, out_file),
|
||||||
subImagePath: imageRes.map((item) => path.relative(define.project_path, item))
|
subImagePath: imageRes.map((item) => path.relative(define.project_path, item))
|
||||||
})
|
})
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
mjApiUrl: this.mjApi.imagineUrl,
|
mjApiUrl: this.mjApi.imagineUrl,
|
||||||
progress: 100,
|
progress: 100,
|
||||||
category: this.mjApi.mjSetting.type,
|
category: this.mjApi.mjSetting.type,
|
||||||
imageClick: task_res.image_click,
|
imageClick: task_res.imageClick,
|
||||||
imageShow: task_res.image_show,
|
imageShow: task_res.imageShow,
|
||||||
messageId: task_res.message_id,
|
messageId: task_res.messageId,
|
||||||
action: MJAction.IMAGINE,
|
action: MJAction.IMAGINE,
|
||||||
status: task_res.status,
|
status: task_res.status,
|
||||||
})
|
})
|
||||||
@ -579,32 +632,32 @@ export class MJOpt {
|
|||||||
type: ResponseMessageType.MJ_IMAGE,
|
type: ResponseMessageType.MJ_IMAGE,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
data: task_res
|
data: task_res
|
||||||
});
|
}, task.messageName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这边也要修改数据
|
// 这边也要修改数据
|
||||||
task_res.id = task.bookTaskDetailId;
|
task_res.id = task.bookTaskDetailId;
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
mjApiUrl: this.mjApi.imagineUrl,
|
mjApiUrl: this.mjApi.imagineUrl,
|
||||||
progress: task_res.progress,
|
progress: task_res.progress,
|
||||||
category: this.mjApi.mjSetting.type,
|
category: this.mjApi.mjSetting.type,
|
||||||
imageClick: task_res.image_click,
|
imageClick: task_res.imageClick,
|
||||||
imageShow: task_res.image_show,
|
imageShow: task_res.imageShow,
|
||||||
messageId: task_res.message_id,
|
messageId: task_res.messageId,
|
||||||
action: MJAction.IMAGINE,
|
action: MJAction.IMAGINE,
|
||||||
status: task_res.status,
|
status: task_res.status,
|
||||||
message: task_res.message
|
message: task_res.message
|
||||||
})
|
})
|
||||||
task_res.outImagePath = task_res.image_path;
|
task_res.outImagePath = task_res.imagePath;
|
||||||
|
|
||||||
this.sendChangeMessage({
|
this.sendChangeMessage({
|
||||||
code: 1,
|
code: 1,
|
||||||
type: ResponseMessageType.MJ_IMAGE,
|
type: ResponseMessageType.MJ_IMAGE,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
data: task_res
|
data: task_res
|
||||||
});
|
}, task.messageName);
|
||||||
// 当获取的图片的进度小于100的时候,等待5秒继续监听
|
// 当获取的图片的进度小于100的时候,等待5秒继续监听
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -622,16 +675,16 @@ export class MJOpt {
|
|||||||
if (isEmpty(task.bookTaskDetailId)) {
|
if (isEmpty(task.bookTaskDetailId)) {
|
||||||
throw new Error("MJ出图,没有找到对应的分镜信息")
|
throw new Error("MJ出图,没有找到对应的分镜信息")
|
||||||
}
|
}
|
||||||
await this.InitService()
|
await this.GetMJSetting()
|
||||||
let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
if (bookTaskDetail == null) {
|
if (bookTaskDetail == null) {
|
||||||
throw new Error("没有找到对应的分镜信息")
|
throw new Error("没有找到对应的分镜信息")
|
||||||
}
|
}
|
||||||
let book = this.bookService.GetBookDataById(bookTaskDetail.bookId)
|
let book = await this.bookServiceBasic.GetBookDataById(bookTaskDetail.bookId)
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
throw new Error("没有找到对应的小说信息")
|
throw new Error("没有找到对应的小说信息")
|
||||||
}
|
}
|
||||||
let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail.bookTaskId)
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId)
|
||||||
if (bookTask == null) {
|
if (bookTask == null) {
|
||||||
throw new Error("没有找到对应的任务信息")
|
throw new Error("没有找到对应的任务信息")
|
||||||
}
|
}
|
||||||
@ -640,11 +693,11 @@ export class MJOpt {
|
|||||||
throw new Error(`${bookTaskDetail.name} 没有找到对应的提示词`)
|
throw new Error(`${bookTaskDetail.name} 没有找到对应的提示词`)
|
||||||
}
|
}
|
||||||
// 这个就是任务ID
|
// 这个就是任务ID
|
||||||
let reqRes = await this.mjApi.SubmitMJImagineAPI(task.id, prompt)
|
let reqRes = await this.mjApi.SubmitMJImagine(task.id, prompt)
|
||||||
if (reqRes == '23') {
|
if (reqRes == '23') {
|
||||||
console.log(task.id, "33333")
|
console.log(task.id, "33333")
|
||||||
// 任务队列过多,重新提交排队
|
// 任务队列过多,重新提交排队
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.RECONNECT,
|
status: BookBackTaskStatus.RECONNECT,
|
||||||
})
|
})
|
||||||
@ -662,8 +715,8 @@ export class MJOpt {
|
|||||||
progress: 0,
|
progress: 0,
|
||||||
status: "re_connect"
|
status: "re_connect"
|
||||||
} as MJ.MJResponseToFront
|
} as MJ.MJResponseToFront
|
||||||
})
|
}, task.messageName)
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
mjApiUrl: this.mjApi.imagineUrl,
|
mjApiUrl: this.mjApi.imagineUrl,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
category: this.mjApi.mjSetting.type,
|
category: this.mjApi.mjSetting.type,
|
||||||
@ -677,10 +730,10 @@ export class MJOpt {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, {
|
||||||
status: BookTaskStatus.IMAGE
|
status: BookTaskStatus.IMAGE
|
||||||
})
|
})
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.RUNNING
|
status: BookBackTaskStatus.RUNNING
|
||||||
})
|
})
|
||||||
@ -698,14 +751,12 @@ export class MJOpt {
|
|||||||
progress: 0,
|
progress: 0,
|
||||||
status: "submited"
|
status: "submited"
|
||||||
} as MJ.MJResponseToFront
|
} as MJ.MJResponseToFront
|
||||||
})
|
}, task.messageName)
|
||||||
await this.FetchImageTask(task, reqRes, book, bookTask, bookTaskDetail);
|
await this.FetchImageTask(task, reqRes, book, bookTask, bookTaskDetail);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error.toString())
|
console.log(error.toString())
|
||||||
let errorMsg = "MJ生图失败,失败信息如下:" + error.toString()
|
let errorMsg = "MJ生图失败,失败信息如下:" + error.toString()
|
||||||
console.log(task.id, "44444")
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
this.bookBackTaskList.UpdateTaskStatus({
|
|
||||||
id: task.id,
|
id: task.id,
|
||||||
status: BookBackTaskStatus.FAIL,
|
status: BookBackTaskStatus.FAIL,
|
||||||
errorMessage: errorMsg
|
errorMessage: errorMsg
|
||||||
@ -721,14 +772,14 @@ export class MJOpt {
|
|||||||
type: MJRespoonseType.UPDATED,
|
type: MJRespoonseType.UPDATED,
|
||||||
mjType: MJAction.IMAGINE,
|
mjType: MJAction.IMAGINE,
|
||||||
category: this.mjSetting.type,
|
category: this.mjSetting.type,
|
||||||
message_id: undefined,
|
messageId: undefined,
|
||||||
id: task.bookTaskDetailId,
|
id: task.bookTaskDetailId,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
message: error.toString(),
|
message: error.toString(),
|
||||||
status: "error"
|
status: "error"
|
||||||
}
|
}
|
||||||
})
|
}, task.messageName)
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
mjApiUrl: this.mjApi.imagineUrl,
|
mjApiUrl: this.mjApi.imagineUrl,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
category: this.mjApi.mjSetting.type,
|
category: this.mjApi.mjSetting.type,
|
||||||
|
|||||||
@ -69,7 +69,6 @@ class MJApi {
|
|||||||
*/
|
*/
|
||||||
async GetMJAPITaskById(taskId: string, backTaskId: string) {
|
async GetMJAPITaskById(taskId: string, backTaskId: string) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await this.InitMJSetting();
|
await this.InitMJSetting();
|
||||||
let url = this.fetchTaskUrl.replace("${id}", taskId)
|
let url = this.fetchTaskUrl.replace("${id}", taskId)
|
||||||
let headers = undefined
|
let headers = undefined
|
||||||
@ -107,15 +106,15 @@ class MJApi {
|
|||||||
type: MJRespoonseType.UPDATED,
|
type: MJRespoonseType.UPDATED,
|
||||||
progress: isNaN(progress) ? 0 : progress,
|
progress: isNaN(progress) ? 0 : progress,
|
||||||
category: this.mjSetting.type,
|
category: this.mjSetting.type,
|
||||||
image_click: res.data.imageUrl,
|
imageClick: res.data.imageUrl,
|
||||||
image_show: res.data.imageUrl,
|
imageShow: res.data.imageUrl,
|
||||||
image_path: res.data.imageUrl,
|
imagePath: res.data.imageUrl,
|
||||||
message_id: taskId,
|
messageId: taskId,
|
||||||
status: status,
|
status: status,
|
||||||
code: code,
|
code: code,
|
||||||
prompt: res.data.prompt == "" ? res.data.promptEn : res.data.prompt,
|
prompt: res.data.prompt == "" ? res.data.promptEn : res.data.prompt,
|
||||||
message: res.data.failReason,
|
message: res.data.failReason,
|
||||||
mj_api_url: this.fetchTaskUrl,
|
mjApiUrl: this.fetchTaskUrl,
|
||||||
} as MJ.MJResponseToFront
|
} as MJ.MJResponseToFront
|
||||||
return resObj
|
return resObj
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -4,18 +4,25 @@ import { checkStringValueAddSuffix, errorMessage, successMessage } from "../../P
|
|||||||
import { define } from '../../../define/define'
|
import { define } from '../../../define/define'
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { ImageStyle } from "../Book/imageStyle";
|
import { ImageStyle } from "../Book/imageStyle";
|
||||||
import { OperateBookType } from "../../../define/enum/bookEnum";
|
import { BookBackTaskStatus, BookType, OperateBookType } from "../../../define/enum/bookEnum";
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { PresetService } from "../presetService";
|
||||||
|
import path from "path";
|
||||||
|
import axios from "axios";
|
||||||
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFileExifData } from "../../../define/Tools/file";
|
||||||
|
import { Base64ToFile } from "../../../define/Tools/image";
|
||||||
|
import { MJAction, MJImageType } from "../../../define/enum/mjEnum";
|
||||||
const fspromise = fs.promises
|
const fspromise = fs.promises
|
||||||
|
|
||||||
export class SDOpt {
|
export class SDOpt {
|
||||||
imageStyle: ImageStyle
|
imageStyle: ImageStyle
|
||||||
|
|
||||||
bookServiceBasic: BookServiceBasic
|
bookServiceBasic: BookServiceBasic
|
||||||
|
presetService: PresetService
|
||||||
constructor() {
|
constructor() {
|
||||||
this.bookServiceBasic = new BookServiceBasic()
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
this.imageStyle = new ImageStyle()
|
this.imageStyle = new ImageStyle()
|
||||||
|
this.presetService = new PresetService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +35,50 @@ export class SDOpt {
|
|||||||
return sdSetting
|
return sdSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region 合并提示词
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有的场景提示词,然后合并
|
||||||
|
* @param ids 需要获取场景的ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetScenePresetStringByIds(ids: string[]): Promise<string> {
|
||||||
|
let result = ''
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
const id = ids[i];
|
||||||
|
let scene = await this.presetService.GetScenePresetDetailById(id)
|
||||||
|
if (scene.code == 1) {
|
||||||
|
// 这边开始拼接
|
||||||
|
result += scene.data.prompt + ', '
|
||||||
|
} else {
|
||||||
|
throw new Error(scene.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有的人物的提示词,然后合并
|
||||||
|
* @param ids 需要获取人物的ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetCharacterPresetStringByIds(ids: string[]): Promise<string> {
|
||||||
|
let result = ''
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
const id = ids[i];
|
||||||
|
let character = await this.presetService.GetCharacterPresetDetailById(id)
|
||||||
|
if (character.code == 1) {
|
||||||
|
result += character.data.prompt + ', '
|
||||||
|
if (character.data.lora && character.data.lora != '无' && character.data.loraWeight) {
|
||||||
|
result += `, <lora:${character.data.lora}:${character.data.lora_weight}>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(character.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SD的提示词合并
|
* SD的提示词合并
|
||||||
* @param id 要处理的ID
|
* @param id 要处理的ID
|
||||||
@ -42,9 +93,9 @@ export class SDOpt {
|
|||||||
let style_weight = sd_setting.setting.style_weight ? sd_setting.setting.style_weight : 1
|
let style_weight = sd_setting.setting.style_weight ? sd_setting.setting.style_weight : 1
|
||||||
|
|
||||||
if (operateBookType == OperateBookType.BOOKTASK) {
|
if (operateBookType == OperateBookType.BOOKTASK) {
|
||||||
bookTaskDetail = (await this.bookServiceBasic.GetBookTaskData({
|
bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
bookTaskId: id
|
bookTaskId: id
|
||||||
})).bookTasks;
|
});
|
||||||
bookTask = await this.bookServiceBasic.GetBookTaskDataById(id);
|
bookTask = await this.bookServiceBasic.GetBookTaskDataById(id);
|
||||||
// 判断是不是有为空的
|
// 判断是不是有为空的
|
||||||
let emptyName = [] as string[]
|
let emptyName = [] as string[]
|
||||||
@ -67,6 +118,7 @@ export class SDOpt {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error("未知的合并类型")
|
throw new Error("未知的合并类型")
|
||||||
}
|
}
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
|
||||||
// 获取合并的排序
|
// 获取合并的排序
|
||||||
let promptSort = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')).prompt_sort; // 没有就直接报错
|
let promptSort = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')).prompt_sort; // 没有就直接报错
|
||||||
@ -80,33 +132,50 @@ export class SDOpt {
|
|||||||
for (let i = 0; i < styleArr.length; i++) {
|
for (let i = 0; i < styleArr.length; i++) {
|
||||||
const element = styleArr[i]
|
const element = styleArr[i]
|
||||||
if (element.type == 'style_main') {
|
if (element.type == 'style_main') {
|
||||||
styleString += `(${element.prompt}:${style_weight})` + ', '
|
if (!isEmpty(element.prompt)) {
|
||||||
|
styleString += `(${element.prompt}:${style_weight})` + ', '
|
||||||
|
}
|
||||||
if (element.lora && element.lora != '无' && element.lora_weight) {
|
if (element.lora && element.lora != '无' && element.lora_weight) {
|
||||||
styleString += `<lora:${element.lora}:${element.lora_weight}>, `
|
styleString += `<lora:${element.lora}:${element.lora_weight}>, `
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
styleString += `(${element.english_style}:${style_weight})` + ','
|
if (!isEmpty(element.prompt)) {
|
||||||
|
styleString += `(${element.english_style}:${style_weight})` + ','
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取SD的通用前缀
|
// 获取SD的通用前缀
|
||||||
let sdGlobalPrompt = JSON.parse(await fspromise.readFile(define.sd_setting, 'utf-8')).webui.prompt;
|
let sdGlobalPrompt = JSON.parse(await fspromise.readFile(define.sd_setting, 'utf-8')).webui.prompt;
|
||||||
|
|
||||||
// TODO 反推这边目前就只有风格和提示词,暂时没有人物和场景
|
|
||||||
let sceneString = ""; // 场景
|
|
||||||
let characterString = ""; // 人物
|
|
||||||
|
|
||||||
|
|
||||||
let result = []; // 返回前端的数据数组
|
let result = []; // 返回前端的数据数组
|
||||||
for (let i = 0; i < bookTaskDetail.length; i++) {
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
||||||
const element = bookTaskDetail[i];
|
const element = bookTaskDetail[i];
|
||||||
|
// 没有推理提示词,直接跳过
|
||||||
|
if (isEmpty(element.gptPrompt)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
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];
|
||||||
promptStr += `${'${' + element.value + '}'} `
|
promptStr += `${'${' + element.value + '}'} `
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sceneString = ""; // 场景
|
||||||
|
let characterString = ""; // 人物
|
||||||
|
|
||||||
|
// 只有原创才需要获取人物和场景
|
||||||
|
if (book.type == BookType.ORIGINAL) {
|
||||||
|
// 这边获取对应的人物和场景
|
||||||
|
let sceneIds = element.sceneTags ? element.sceneTags : [];
|
||||||
|
let characterIds = element.characterTags ? element.characterTags : [];
|
||||||
|
if (sceneIds && sceneIds.length > 0) {
|
||||||
|
sceneString = await this.GetScenePresetStringByIds(sceneIds)
|
||||||
|
}
|
||||||
|
if (characterIds && characterIds.length > 0) {
|
||||||
|
characterString = await this.GetCharacterPresetStringByIds(characterIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 开始合并
|
// 开始合并
|
||||||
promptStr = promptStr.replace('${style}', styleString) // 风格
|
promptStr = promptStr.replace('${style}', styleString) // 风格
|
||||||
promptStr = promptStr.replace('${character}', characterString) // 人物
|
promptStr = promptStr.replace('${character}', characterString) // 人物
|
||||||
@ -145,4 +214,157 @@ export class SDOpt {
|
|||||||
return errorMessage("SD合并提示词,错误信息如下:" + error.toString(), "SDOpt_MergePrompt")
|
return errorMessage("SD合并提示词,错误信息如下:" + error.toString(), "SDOpt_MergePrompt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 生图相关任务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SD单个生成图片任务
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async SDImageGenerate(task: TaskModal.Task) {
|
||||||
|
let sdSetting = undefined
|
||||||
|
try {
|
||||||
|
// 开始生图
|
||||||
|
sdSetting = await this.GetSDSetting();
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId);
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
|
||||||
|
let prompt = bookTaskDetail.prompt;
|
||||||
|
let url = sdSetting.setting.webui_api_url
|
||||||
|
if (url.endsWith('/')) {
|
||||||
|
url = url + "sdapi/v1/txt2img"
|
||||||
|
} else {
|
||||||
|
url = url + "/sdapi/v1/txt2img"
|
||||||
|
}
|
||||||
|
if (!isEmpty(sdSetting.webui.prompt)) {
|
||||||
|
prompt = sdSetting.webui.prompt + ', ' + prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前是不是有开修脸修手
|
||||||
|
let ADetailer = {
|
||||||
|
args: sdSetting.adetailer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 种子默认 -1,随机
|
||||||
|
let seed = -1;
|
||||||
|
let body = {
|
||||||
|
prompt: prompt,
|
||||||
|
negative_prompt: sdSetting.webui.negative_prompt,
|
||||||
|
seed: seed,
|
||||||
|
sampler_name: sdSetting.webui.sampler_name,
|
||||||
|
// 提示词相关性
|
||||||
|
cfg_scale: sdSetting.webui.cfg_scale,
|
||||||
|
width: sdSetting.webui.width,
|
||||||
|
height: sdSetting.webui.height,
|
||||||
|
batch_size: sdSetting.setting.batch_size,
|
||||||
|
n_iter: 1,
|
||||||
|
steps: sdSetting.webui.steps,
|
||||||
|
save_images: false
|
||||||
|
}
|
||||||
|
if (bookTaskDetail.adetailer) {
|
||||||
|
body['alwayson_scripts'] = {
|
||||||
|
"ADetailer": ADetailer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const response = await axios.post(url, body)
|
||||||
|
// TODO 对SD图片种子的一些处理,待定
|
||||||
|
// let info = JSON.parse(res.data.info)
|
||||||
|
// if (seed == -1) {
|
||||||
|
// seed = info.seed
|
||||||
|
// }
|
||||||
|
let images = response.data.images
|
||||||
|
let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage');
|
||||||
|
await CheckFolderExistsOrCreate(SdOriginalImage);
|
||||||
|
let outputFolder = bookTask.imageFolder;
|
||||||
|
await CheckFolderExistsOrCreate(outputFolder);
|
||||||
|
let inputFolder = path.join(book.bookFolderPath, 'tmp/input')
|
||||||
|
await CheckFolderExistsOrCreate(inputFolder);
|
||||||
|
|
||||||
|
let subImagePath = []
|
||||||
|
let outImagePath = ''
|
||||||
|
// 开始写出图片
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
const element = images[i];
|
||||||
|
// 包含info信息的图片地址
|
||||||
|
let infoImgPath = path.join(SdOriginalImage, `info_${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
// 不包含info信息的图片地址
|
||||||
|
let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
await Base64ToFile(element, infoImgPath)
|
||||||
|
// 这边去图片信息
|
||||||
|
await DeleteFileExifData(path.join(define.package_path, 'exittool/exiftool.exe'), infoImgPath, imgPath);
|
||||||
|
// 写出去
|
||||||
|
if (bookTask.name == 'output_00001') {
|
||||||
|
// 复制一个到input
|
||||||
|
let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, inputImgPath)
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
// 复制到对应的文件夹里面
|
||||||
|
let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, outPath)
|
||||||
|
outImagePath = outPath
|
||||||
|
}
|
||||||
|
subImagePath.push(imgPath)
|
||||||
|
}
|
||||||
|
// 修改数据库
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
outImagePath: path.relative(define.project_path, outImagePath),
|
||||||
|
subImagePath: subImagePath.map((item) => path.relative(define.project_path, item))
|
||||||
|
})
|
||||||
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
|
id: task.id,
|
||||||
|
status: BookBackTaskStatus.DONE
|
||||||
|
});
|
||||||
|
let resp = {
|
||||||
|
mjApiUrl: url,
|
||||||
|
progress: 100,
|
||||||
|
category: MJImageType.LOCAL_SD,
|
||||||
|
imageClick: subImagePath.join(','),
|
||||||
|
imageShow: subImagePath.join(','),
|
||||||
|
messageId: subImagePath.join(','),
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "success",
|
||||||
|
subImagePath: subImagePath,
|
||||||
|
outImagePath: outImagePath,
|
||||||
|
message: "SD生成图片成功"
|
||||||
|
}
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp)
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 1,
|
||||||
|
message: "SD生成图片成功",
|
||||||
|
data: {
|
||||||
|
...resp,
|
||||||
|
id: bookTaskDetail.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
let errorMsg = "SD生成图片失败,错误信息如下:" + error.toString()
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
|
mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "",
|
||||||
|
progress: 0,
|
||||||
|
category: MJImageType.LOCAL_SD,
|
||||||
|
imageClick: "",
|
||||||
|
imageShow: "",
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "error",
|
||||||
|
message: errorMsg,
|
||||||
|
id: task.bookTaskDetailId
|
||||||
|
})
|
||||||
|
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 0,
|
||||||
|
message: errorMsg,
|
||||||
|
data: {
|
||||||
|
status: 'error',
|
||||||
|
message: errorMsg
|
||||||
|
}
|
||||||
|
})
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
@ -43,6 +43,7 @@ export class BookServiceBasic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//#region 事务操作
|
//#region 事务操作
|
||||||
transaction(callback: (realm: any) => void) {
|
transaction(callback: (realm: any) => void) {
|
||||||
this.bookService.transaction(() => {
|
this.bookService.transaction(() => {
|
||||||
@ -57,7 +58,7 @@ export class BookServiceBasic {
|
|||||||
/**
|
/**
|
||||||
* 通过小说ID获取小说数据
|
* 通过小说ID获取小说数据
|
||||||
* @param bookId 小说ID
|
* @param bookId 小说ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetBookDataById(bookId: string): Promise<Book.SelectBook> {
|
async GetBookDataById(bookId: string): Promise<Book.SelectBook> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -96,7 +97,7 @@ export class BookServiceBasic {
|
|||||||
/**
|
/**
|
||||||
* 通过小说ID获取小说批次任务数据
|
* 通过小说ID获取小说批次任务数据
|
||||||
* @param bookTaskId 小说批次任务ID
|
* @param bookTaskId 小说批次任务ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetBookTaskDataById(bookTaskId: string): Promise<Book.SelectBookTask> {
|
async GetBookTaskDataById(bookTaskId: string): Promise<Book.SelectBookTask> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -138,7 +139,7 @@ export class BookServiceBasic {
|
|||||||
/**
|
/**
|
||||||
* 更新小说批次任务的数据
|
* 更新小说批次任务的数据
|
||||||
* @param bookTaskId 小说批次任务ID
|
* @param bookTaskId 小说批次任务ID
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
async UpdetedBookTaskData(bookTaskId: string, data: Book.SelectBookTask): Promise<void> {
|
async UpdetedBookTaskData(bookTaskId: string, data: Book.SelectBookTask): Promise<void> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -166,10 +167,15 @@ export class BookServiceBasic {
|
|||||||
|
|
||||||
//#region 小说批次任务对应的分镜的相关的基础服务
|
//#region 小说批次任务对应的分镜的相关的基础服务
|
||||||
|
|
||||||
|
async AddBookTaskDetail(bookTaskDetail: Book.SelectBookTaskDetail): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskDetailService.AddBookTaskDetail(bookTaskDetail)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定的小说批次任务分镜数据,通过分镜ID
|
* 获取指定的小说批次任务分镜数据,通过分镜ID
|
||||||
* @param bookTaskDetailId 小说批次任务分镜ID
|
* @param bookTaskDetailId 小说批次任务分镜ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetBookTaskDetailDataById(bookTaskDetailId: string): Promise<Book.SelectBookTaskDetail> {
|
async GetBookTaskDetailDataById(bookTaskDetailId: string): Promise<Book.SelectBookTaskDetail> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -184,12 +190,13 @@ export class BookServiceBasic {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定的小说批次任务分镜数据,通过查询条件
|
* 获取指定的小说批次任务分镜数据,通过查询条件
|
||||||
* @param condition
|
* @param condition
|
||||||
|
* @param returnEmpty 是否返回空数据,默认 false 不返回,如果返回空数据,会抛出异常
|
||||||
*/
|
*/
|
||||||
async GetBookTaskDetailData(condition: Book.QueryBookTaskDetailCondition): Promise<Book.SelectBookTaskDetail[]> {
|
async GetBookTaskDetailData(condition: Book.QueryBookTaskDetailCondition, returnEmpty: boolean = false): Promise<Book.SelectBookTaskDetail[]> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData(condition)
|
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData(condition)
|
||||||
if (bookTaskDetails.data.length <= 0) {
|
if (!returnEmpty && bookTaskDetails.data.length <= 0) {
|
||||||
let msg = "未找到对应的小说批次任务分镜数据,请检查";
|
let msg = "未找到对应的小说批次任务分镜数据,请检查";
|
||||||
throw new Error(msg)
|
throw new Error(msg)
|
||||||
}
|
}
|
||||||
@ -221,7 +228,7 @@ export class BookServiceBasic {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定的小说分镜的反推提示词
|
* 删除指定的小说分镜的反推提示词
|
||||||
* @param bookTaskDetail
|
* @param bookTaskDetail
|
||||||
*/
|
*/
|
||||||
async DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): Promise<void> {
|
async DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): Promise<void> {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -230,13 +237,35 @@ export class BookServiceBasic {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定的小说分镜生成的图片
|
* 删除指定的小说分镜生成的图片
|
||||||
* @param bookTaskDetailId
|
* @param bookTaskDetailId
|
||||||
*/
|
*/
|
||||||
async DeleteBoookTaskDetailGenerateImage(bookTaskDetailId: string): Promise<void> {
|
async DeleteBoookTaskDetailGenerateImage(bookTaskDetailId: string): Promise<void> {
|
||||||
await this.InitService()
|
await this.InitService()
|
||||||
this.bookTaskDetailService.DeleteBoookTaskDetailGenerateImage(bookTaskDetailId);
|
this.bookTaskDetailService.DeleteBoookTaskDetailGenerateImage(bookTaskDetailId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改小说分镜数据的反推提示词
|
||||||
|
* @param bookTaskDetailId 小说分镜的ID
|
||||||
|
* @param reversePromptId 反推提示词的ID
|
||||||
|
* @param data 反推提示词数据
|
||||||
|
*/
|
||||||
|
async UpdateBookTaskDetailReversePrompt(bookTaskDetailId: string, reversePromptId: string, data: Book.ReversePrompt): Promise<void> {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskDetailService.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更行小说分镜的MJ消息,就是出图信息
|
||||||
|
* @param bookTaskDetailId 小说分镜的数据信息
|
||||||
|
* @param mjMessage 要保存到分镜信息
|
||||||
|
*/
|
||||||
|
async UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage) {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookTaskDetailService.UpdateBookTaskDetailMjMessage(bookTaskDetailId, mjMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 小说后台任务相关操作
|
//#region 小说后台任务相关操作
|
||||||
@ -253,10 +282,12 @@ export class BookServiceBasic {
|
|||||||
taskType: BookBackTaskType,
|
taskType: BookBackTaskType,
|
||||||
executeType = TaskExecuteType.AUTO,
|
executeType = TaskExecuteType.AUTO,
|
||||||
bookTaskId = null,
|
bookTaskId = null,
|
||||||
bookTaskDetailId = null): Promise<TaskModal.Task> {
|
bookTaskDetailId = null,
|
||||||
|
responseMessageName: string = null
|
||||||
|
): Promise<TaskModal.Task> {
|
||||||
|
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
let res = this.bookBackTaskListService.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId)
|
let res = this.bookBackTaskListService.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName)
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
throw new Error(res.message)
|
throw new Error(res.message)
|
||||||
}
|
}
|
||||||
@ -270,7 +301,7 @@ export class BookServiceBasic {
|
|||||||
* 通过小说ID和小说批次任务ID获取小说和小说批次任务数据
|
* 通过小说ID和小说批次任务ID获取小说和小说批次任务数据
|
||||||
* @param bookId 小说ID
|
* @param bookId 小说ID
|
||||||
* @param bookTaskName 小说批次的名字,或者是小说批次任务的ID
|
* @param bookTaskName 小说批次的名字,或者是小说批次任务的ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetBookAndTask(bookId: string, bookTaskName: string) {
|
async GetBookAndTask(bookId: string, bookTaskName: string) {
|
||||||
await this.InitService();
|
await this.InitService();
|
||||||
@ -295,4 +326,13 @@ export class BookServiceBasic {
|
|||||||
}
|
}
|
||||||
return { book: book as Book.SelectBook, bookTask: bookTaskRes.data.bookTasks[0] as Book.SelectBookTask }
|
return { book: book as Book.SelectBook, bookTask: bookTaskRes.data.bookTasks[0] as Book.SelectBookTask }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改后台队列的状态
|
||||||
|
* @param bookBackTask 要修改的数据
|
||||||
|
*/
|
||||||
|
async UpdateTaskStatus(bookBackTask: Book.UpdateBookTaskListStatus) {
|
||||||
|
await this.InitService();
|
||||||
|
this.bookBackTaskListService.UpdateTaskStatus(bookBackTask)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,26 @@
|
|||||||
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService';
|
import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService';
|
||||||
|
import { MJSettingService } from '../../../define/db/service/SoftWare/mjSettingService';
|
||||||
|
import { MJSetting } from '../../../model/Setting/mjSetting';
|
||||||
|
|
||||||
|
|
||||||
export class SoftWareServiceBasic {
|
export class SoftWareServiceBasic {
|
||||||
softwareService: SoftwareService
|
softwareService: SoftwareService
|
||||||
|
mjSettingService: MJSettingService
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
async InitService() {
|
async InitService() {
|
||||||
if (!this.softwareService) {
|
if (!this.softwareService) {
|
||||||
this.softwareService = await SoftwareService.getInstance()
|
this.softwareService = await SoftwareService.getInstance()
|
||||||
}
|
}
|
||||||
|
if (!this.mjSettingService) {
|
||||||
|
this.mjSettingService = await MJSettingService.getInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region software相关的基础服务
|
//#region software相关的基础服务
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新软件配置信息
|
* 更新软件配置信息,如果没有ID则修改指定属性
|
||||||
* @param software
|
* @param software
|
||||||
*/
|
*/
|
||||||
async UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): Promise<void> {
|
async UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): Promise<void> {
|
||||||
@ -73,4 +79,26 @@ export class SoftWareServiceBasic {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region MJ设置相关
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取MJ的设置信息
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetMjSetting(): Promise<MJSetting.MjSetting> {
|
||||||
|
await this.InitService();
|
||||||
|
let mjSetting = this.mjSettingService.GetMjSetting({})
|
||||||
|
if (mjSetting.code == 1) {
|
||||||
|
if (mjSetting.data.length <= 0) {
|
||||||
|
throw new Error("未找到MJ的设置信息,请检查");
|
||||||
|
}
|
||||||
|
// 这边只是返回第一个
|
||||||
|
return mjSetting.data[0]
|
||||||
|
} else {
|
||||||
|
throw new Error(mjSetting.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ import { CheckFileOrDirExist } from "../../../define/Tools/file";
|
|||||||
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
import { Subtitle } from "./subtitle";
|
import { Subtitle } from "./subtitle";
|
||||||
import { TaskScheduler } from "../taskScheduler";
|
import { TaskScheduler } from "../taskScheduler";
|
||||||
import { BookType, OperateBookType } from "../../../define/enum/bookEnum";
|
import { BookTaskStatus, BookType, OperateBookType } from "../../../define/enum/bookEnum";
|
||||||
import { Book } from "../../../model/book";
|
import { Book } from "../../../model/book";
|
||||||
import { TimeStringToMilliseconds } from "../../../define/Tools/time";
|
import { TimeStringToMilliseconds } from "../../../define/Tools/time";
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ export class SubtitleService {
|
|||||||
* @param bookTaskId 小说批次任务ID
|
* @param bookTaskId 小说批次任务ID
|
||||||
* @param operateBookType 操作的小说类型
|
* @param operateBookType 操作的小说类型
|
||||||
* @param coverData 是不是要覆盖旧的数据
|
* @param coverData 是不是要覆盖旧的数据
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async GetCopywriting(bookId: string, bookTaskId: string, operateBookType: OperateBookType, coverData: boolean): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async GetCopywriting(bookId: string, bookTaskId: string, operateBookType: OperateBookType, coverData: boolean): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
@ -195,7 +195,7 @@ export class SubtitleService {
|
|||||||
/**
|
/**
|
||||||
* 导出指定导出指定小说的文案
|
* 导出指定导出指定小说的文案
|
||||||
* @param bookTaskId 小说批次任务ID
|
* @param bookTaskId 小说批次任务ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async ExportCopywriting(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async ExportCopywriting(bookTaskId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
@ -233,11 +233,11 @@ export class SubtitleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将
|
* 导入修改过后的文案数据
|
||||||
* @param bookId
|
* @param bookId
|
||||||
* @param bookTaskId
|
* @param bookTaskId
|
||||||
* @param txtPath
|
* @param txtPath
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async ImportCopywriting(bookId: string, bookTaskId: string, txtPath: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
async ImportCopywriting(bookId: string, bookTaskId: string, txtPath: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
try {
|
try {
|
||||||
@ -305,7 +305,7 @@ export class SubtitleService {
|
|||||||
originalTime = JSON.parse(originalTimeString)
|
originalTime = JSON.parse(originalTimeString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 判断分镜数据和批次数据是不是相同的
|
// 判断分镜数据和批次数据是不是相同的 好好办办
|
||||||
if (originalTime.length != bookTaskDetails.length) {
|
if (originalTime.length != bookTaskDetails.length) {
|
||||||
originalTime = []
|
originalTime = []
|
||||||
}
|
}
|
||||||
@ -337,5 +337,68 @@ export class SubtitleService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文案的对齐信息,这边会做一些判断
|
||||||
|
* @param bookTaskId 小说任务ID
|
||||||
|
* @param copywritingData 要保存的文案数据
|
||||||
|
* @param operateBookType 操作的小说类型
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async SaveCopywriting(bookTaskId: string, copywritingData: SubtitleModel.SaveCopywritingData[], operateBookType: OperateBookType): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
if (operateBookType != OperateBookType.BOOKTASK) {
|
||||||
|
throw new Error('目前只支持对小说任务的文案保存')
|
||||||
|
}
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskId)
|
||||||
|
let bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({
|
||||||
|
bookTaskId: bookTaskId
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
if (bookTaskDetails.length == 0) {
|
||||||
|
// 新增
|
||||||
|
for (let i = 0; i < copywritingData.length; i++) {
|
||||||
|
const element = copywritingData[i];
|
||||||
|
await this.bookServiceBasic.AddBookTaskDetail({
|
||||||
|
bookTaskId: bookTaskId,
|
||||||
|
bookId: bookTask.bookId,
|
||||||
|
startTime: element.start_time,
|
||||||
|
endTime: element.end_time,
|
||||||
|
status: BookTaskStatus.WAIT,
|
||||||
|
word: element.word,
|
||||||
|
afterGpt: element.after_gpt,
|
||||||
|
subValue: JSON.stringify(element.subValue),
|
||||||
|
timeLimit: element.timeLimit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 修改,这边就要判断是不是数量一致了
|
||||||
|
if (bookTaskDetails.length != copywritingData.length) {
|
||||||
|
throw new Error("已有文案,再导入的时候,文案函数数量和分镜数据不一致,请检查")
|
||||||
|
}
|
||||||
|
// 开始修改。修改使用事务吧
|
||||||
|
this.bookServiceBasic.transaction((realm) => {
|
||||||
|
for (let i = 0; i < copywritingData.length; i++) {
|
||||||
|
const element = copywritingData[i];
|
||||||
|
let btd = realm.objectForPrimaryKey("BookTaskDetail", bookTaskDetails[i].id);
|
||||||
|
if (btd == null) {
|
||||||
|
throw new Error("未找到对应的分镜数据,请检查")
|
||||||
|
}
|
||||||
|
// 开始修改
|
||||||
|
btd.startTime = element.start_time;
|
||||||
|
btd.endTime = element.end_time;
|
||||||
|
btd.word = element.word;
|
||||||
|
btd.afterGpt = element.after_gpt;
|
||||||
|
btd.subValue = JSON.stringify(element.subValue);
|
||||||
|
btd.timeLimit = element.timeLimit
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("保存文案数据失败,失败信息如下:" + error.toString(), 'SubtitleService_SaveCopywriting')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -299,19 +299,11 @@ export class Translate {
|
|||||||
for (let j = 0; j < req_arr.length; j++) {
|
for (let j = 0; j < req_arr.length; j++) {
|
||||||
const item = req_arr[j];
|
const item = req_arr[j];
|
||||||
let res_tmp = translateList.find(item => item.index == j);
|
let res_tmp = translateList.find(item => item.index == j);
|
||||||
if (to == "zh") {
|
let obj = {
|
||||||
let obj = {
|
src: item,
|
||||||
src: item,
|
dst: res_tmp.translated
|
||||||
dst: res_tmp.translated
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
} else if (to == "en") {
|
|
||||||
let obj = {
|
|
||||||
src: res_tmp.translated,
|
|
||||||
dst: item
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
}
|
}
|
||||||
|
res_data.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接返回数据
|
// 直接返回数据
|
||||||
@ -388,19 +380,11 @@ export class Translate {
|
|||||||
let res_data = [];
|
let res_data = [];
|
||||||
for (let j = 0; j < req_data.length; j++) {
|
for (let j = 0; j < req_data.length; j++) {
|
||||||
const item = req_data[j];
|
const item = req_data[j];
|
||||||
if (to == "zh") {
|
let obj = {
|
||||||
let obj = {
|
src: item,
|
||||||
src: item,
|
dst: translateList[j]
|
||||||
dst: translateList[j]
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
} else if (to == "en") {
|
|
||||||
let obj = {
|
|
||||||
src: translateList[j],
|
|
||||||
dst: item
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
}
|
}
|
||||||
|
res_data.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接返回数据
|
// 直接返回数据
|
||||||
@ -474,19 +458,11 @@ export class Translate {
|
|||||||
let res_data = [];
|
let res_data = [];
|
||||||
for (let j = 0; j < req_data.length; j++) {
|
for (let j = 0; j < req_data.length; j++) {
|
||||||
const item = req_data[j];
|
const item = req_data[j];
|
||||||
if (to == "zh") {
|
let obj = {
|
||||||
let obj = {
|
src: item,
|
||||||
src: item,
|
dst: translateList[j].Translation
|
||||||
dst: translateList[j].Translation
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
} else if (to == "en") {
|
|
||||||
let obj = {
|
|
||||||
src: translateList[j].Translation,
|
|
||||||
dst: item
|
|
||||||
}
|
|
||||||
res_data.push(obj);
|
|
||||||
}
|
}
|
||||||
|
res_data.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接返回数据
|
// 直接返回数据
|
||||||
@ -568,20 +544,20 @@ export class Translate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let res_data = []
|
let res_data = []
|
||||||
|
res_data = res.data.trans_result
|
||||||
// 将所有的数据协会到本地(然后发送消息到前台界面)
|
// 将所有的数据协会到本地(然后发送消息到前台界面)
|
||||||
if (res.data.to == "zh") {
|
// if (res.data.to == "zh") {
|
||||||
res_data = res.data.trans_result
|
// } else {
|
||||||
} else {
|
// // 直接在这边处理(前端不用处理)
|
||||||
// 直接在这边处理(前端不用处理)
|
// for (let i = 0; i < res.data.trans_result.length; i++) {
|
||||||
for (let i = 0; i < res.data.trans_result.length; i++) {
|
// const element = res.data.trans_result[i];
|
||||||
const element = res.data.trans_result[i];
|
// let obj = {
|
||||||
let obj = {
|
// src: element.dst,
|
||||||
src: element.dst,
|
// dst: element.src
|
||||||
dst: element.src
|
// };
|
||||||
};
|
// res_data.push(obj);
|
||||||
res_data.push(obj);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
// 直接返回数据
|
// 直接返回数据
|
||||||
return successMessage({
|
return successMessage({
|
||||||
to: value.to,
|
to: value.to,
|
||||||
|
|||||||
@ -4,46 +4,38 @@ import { errorMessage, successMessage } from "../../Public/generalTools";
|
|||||||
import { Translate } from "./Translate";
|
import { Translate } from "./Translate";
|
||||||
import { DEFINE_STRING } from "../../../define/define_string"
|
import { DEFINE_STRING } from "../../../define/define_string"
|
||||||
import { TranslateAPIType, TranslateType } from "../../../define/enum/translate";
|
import { TranslateAPIType, TranslateType } from "../../../define/enum/translate";
|
||||||
import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService";
|
|
||||||
import { Book } from "../../../model/book";
|
import { Book } from "../../../model/book";
|
||||||
import { ResponseMessageType } from "../../../define/enum/softwareEnum";
|
import { ResponseMessageType } from "../../../define/enum/softwareEnum";
|
||||||
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";
|
import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic";
|
||||||
|
import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic";
|
||||||
|
import { ExecuteConcurrently } from "../../../define/Tools/common";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 翻译实现服务
|
* 翻译实现服务
|
||||||
*/
|
*/
|
||||||
export class TranslateService {
|
export class TranslateService {
|
||||||
translate: Translate
|
translate: Translate
|
||||||
bookTaskDetail: BookTaskDetailService;
|
|
||||||
softwareService: SoftwareService
|
|
||||||
bookServiceBasic: BookServiceBasic
|
bookServiceBasic: BookServiceBasic
|
||||||
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.bookServiceBasic = new BookServiceBasic();
|
this.bookServiceBasic = new BookServiceBasic();
|
||||||
}
|
this.translate = new Translate();
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic();
|
||||||
async InitService() {
|
|
||||||
if (!this.bookTaskDetail) {
|
|
||||||
this.bookTaskDetail = await BookTaskDetailService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.softwareService) {
|
|
||||||
this.softwareService = await SoftwareService.getInstance()
|
|
||||||
}
|
|
||||||
if (!this.translate) {
|
|
||||||
this.translate = new Translate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回翻译结果。用于前端修改
|
// 返回翻译结果。用于前端修改
|
||||||
private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse): void {
|
private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.MAIN_DATA_RETURN): void {
|
||||||
let win = global.newWindow[0]
|
let win = global.newWindow[0]
|
||||||
if (windowId) {
|
if (windowId) {
|
||||||
win = global.newWindow.filter(item => item.id == windowId)[0];
|
win = global.newWindow.filter(item => item.id == windowId)[0];
|
||||||
}
|
}
|
||||||
win.win.webContents.send(DEFINE_STRING.BOOK.MAIN_DATA_RETURN, data)
|
if (!message_name) {
|
||||||
|
message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN
|
||||||
|
}
|
||||||
|
win.win.webContents.send(message_name, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,14 +89,13 @@ export class TranslateService {
|
|||||||
*/
|
*/
|
||||||
async GetTranslateSetting(): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
async GetTranslateSetting(): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
let translateSetting = undefined as TranslateModel.TranslateModel
|
let translateSetting = undefined as TranslateModel.TranslateModel
|
||||||
let translateSettingString = this.softwareService.GetSoftWarePropertyData('translationSetting');
|
let translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting');
|
||||||
if (isEmpty(translateSettingString)) {
|
if (isEmpty(translateSettingString)) {
|
||||||
// 初始化
|
// 初始化
|
||||||
translateSetting = this.InitialTranslateSetting();
|
translateSetting = this.InitialTranslateSetting();
|
||||||
await this.ResetTranslateSetting();
|
await this.ResetTranslateSetting();
|
||||||
translateSettingString = this.softwareService.GetSoftWarePropertyData('translationSetting');
|
translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting');
|
||||||
translateSetting = JSON.parse(translateSettingString);
|
translateSetting = JSON.parse(translateSettingString);
|
||||||
} else {
|
} else {
|
||||||
// 解析
|
// 解析
|
||||||
@ -140,7 +131,7 @@ export class TranslateService {
|
|||||||
async ResetTranslateSetting(): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
async ResetTranslateSetting(): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
try {
|
try {
|
||||||
let translateSetting = this.InitialTranslateSetting()
|
let translateSetting = this.InitialTranslateSetting()
|
||||||
let res = this.softwareService.SaveSoftwarePropertyData('translationSetting', JSON.stringify(translateSetting))
|
let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(translateSetting))
|
||||||
return successMessage(translateSetting, "重置翻译设置成功", "TranslateService_ResetTranslateSetting")
|
return successMessage(translateSetting, "重置翻译设置成功", "TranslateService_ResetTranslateSetting")
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -155,7 +146,7 @@ export class TranslateService {
|
|||||||
*/
|
*/
|
||||||
async SaveTranslateSetting(value: TranslateModel.TranslateModel): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
async SaveTranslateSetting(value: TranslateModel.TranslateModel): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
try {
|
try {
|
||||||
let res = this.softwareService.SaveSoftwarePropertyData('translationSetting', JSON.stringify(value))
|
let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(value))
|
||||||
// 这边要判断是不是用的laitool
|
// 这边要判断是不是用的laitool
|
||||||
let laitool = value.translates.filter(item => item.name == TranslateAPIType.LAITOOL)
|
let laitool = value.translates.filter(item => item.name == TranslateAPIType.LAITOOL)
|
||||||
if (laitool.length > 0) {
|
if (laitool.length > 0) {
|
||||||
@ -194,7 +185,7 @@ export class TranslateService {
|
|||||||
updateData.promptCN = dstString
|
updateData.promptCN = dstString
|
||||||
}
|
}
|
||||||
// 修改数据
|
// 修改数据
|
||||||
this.bookTaskDetail.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, updateData)
|
await this.bookServiceBasic.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, updateData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理返回的数据
|
// 处理返回的数据
|
||||||
@ -214,56 +205,62 @@ export class TranslateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 翻译
|
/**
|
||||||
|
* 翻译
|
||||||
|
* @param value
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
async TranslateNowReturn(value: TranslateModel.TranslateNowIPCParams[]): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
async TranslateNowReturn(value: TranslateModel.TranslateNowIPCParams[]): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
try {
|
try {
|
||||||
await this.InitService()
|
|
||||||
// 循环所有的数据,返回翻译结果
|
// 循环所有的数据,返回翻译结果
|
||||||
|
let tasks = []
|
||||||
for (let i = 0; i < value.length; i++) {
|
for (let i = 0; i < value.length; i++) {
|
||||||
const element = value[i];
|
const element = value[i];
|
||||||
let res = await this.translate.TranslateReturnNow(element)
|
tasks.push(async () => {
|
||||||
// 单个翻译,将返回的数据写入到原数据中
|
let res = await this.translate.TranslateReturnNow(element)
|
||||||
|
// global.logger.info("断点写出", JSON.stringify(res))
|
||||||
|
// 单个翻译,将返回的数据写入到原数据中
|
||||||
|
|
||||||
// 添加一个对返回信息进行处理的函数
|
// 添加一个对返回信息进行处理的函数
|
||||||
let data = res.data
|
let data = res.data
|
||||||
// 先将数据进行拼接
|
// 先将数据进行拼接
|
||||||
let srcString = ""
|
let srcString = ""
|
||||||
if (element.isSplit) {
|
if (element.isSplit) {
|
||||||
let dstStrs = []
|
let dstStrs = []
|
||||||
} else {
|
} else {
|
||||||
// 没有拆分的,只有一句
|
// 没有拆分的,只有一句
|
||||||
srcString = data.data[0].dst
|
srcString = data.data[0].dst
|
||||||
}
|
|
||||||
// 写回数据库
|
|
||||||
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, {
|
|
||||||
code: 1,
|
|
||||||
id: element.bookTaskDetailId,
|
|
||||||
type: responseType,
|
|
||||||
data: {
|
|
||||||
progress: i + 1,
|
|
||||||
total: value.length,
|
|
||||||
from: element.from,
|
|
||||||
to: data.to,
|
|
||||||
bookTaskDetailId: element.bookTaskDetailId,
|
|
||||||
reversePromptId: element.reversePromptId,
|
|
||||||
prompt: srcString,
|
|
||||||
promptCN: 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, {
|
||||||
|
code: 1,
|
||||||
|
id: element.bookTaskDetailId,
|
||||||
|
type: responseType,
|
||||||
|
data: {
|
||||||
|
progress: i + 1,
|
||||||
|
total: value.length,
|
||||||
|
from: element.from,
|
||||||
|
to: data.to,
|
||||||
|
bookTaskDetailId: element.bookTaskDetailId,
|
||||||
|
reversePromptId: element.reversePromptId,
|
||||||
|
prompt: srcString,
|
||||||
|
promptCN: srcString
|
||||||
|
}
|
||||||
|
}, element.responseMessgeName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
let res = await ExecuteConcurrently(tasks, global.config.task_number)
|
||||||
|
// 将翻译后的数据返回,前端进行修改
|
||||||
return successMessage(null, "全部翻译完成", "TranslateService_TranslateNowReturn")
|
return successMessage(null, "全部翻译完成", "TranslateService_TranslateNowReturn")
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage("翻译失败,失败信息如下:" + error.toString(), "TranslateService_TranslateNowReturn")
|
return errorMessage("翻译失败,失败信息如下:" + error.toString(), "TranslateService_TranslateNowReturn")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,15 +1,193 @@
|
|||||||
|
import { BookServiceBasic } from "./ServiceBasic/bookServiceBasic";
|
||||||
|
import { define } from '../../define/define'
|
||||||
|
import fs from 'fs'
|
||||||
|
import { GptService } from "./GPT/gpt";
|
||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import path from 'path'
|
||||||
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from "../../define/Tools/file";
|
||||||
|
import { Base64ToFile, GetImageBase64 } from "../../define/Tools/image";
|
||||||
|
import { BookBackTaskStatus } from "../../define/enum/bookEnum";
|
||||||
|
import { MJAction, MJImageType } from "../../define/enum/mjEnum";
|
||||||
|
import axios from "axios";
|
||||||
|
export class D3Opt {
|
||||||
|
bookServiceBasic: BookServiceBasic
|
||||||
|
gptService: GptService
|
||||||
|
constructor() {
|
||||||
|
this.gptService = new GptService()
|
||||||
|
this.bookServiceBasic = new BookServiceBasic()
|
||||||
|
}
|
||||||
|
|
||||||
export class D3 {
|
/**
|
||||||
constructor() { }
|
* 获取SD的设置,之后要删掉,改为数据库
|
||||||
|
*/
|
||||||
|
private async GetSDSetting() {
|
||||||
|
let sdSetting = JSON.parse(await fs.promises.readFile(define.sd_setting, 'utf-8'))
|
||||||
|
return sdSetting
|
||||||
|
}
|
||||||
|
|
||||||
//#region D3进行画图的基础方法
|
//#region D3生图
|
||||||
|
|
||||||
//#endregion
|
/**
|
||||||
|
* 异步发送D3 API图像请求
|
||||||
|
* 该函数用于向指定的D3 API发送图像生成请求,通过提供模型、提示和图像大小等参数来定制生成的图像
|
||||||
|
*
|
||||||
|
* @param url {string} - API的基础URL字符串,指定了发送请求的目标地址
|
||||||
|
* @param key {string} - API密钥字符串,用于认证请求,使函数能够访问API服务
|
||||||
|
* @param body {object} - 包含模型、提示和图像大小的对象
|
||||||
|
* - model {string} 模型字段,指定用于生成图像的AI模型
|
||||||
|
* - prompt {string} 提示字段,提供生成图像的文本描述或提示
|
||||||
|
* - size {string} 大小字段,定义生成图像的尺寸
|
||||||
|
* @returns 无返回值,但函数内部可能包含对API的异步请求操作
|
||||||
|
*/
|
||||||
|
async D3APIImageRequest(url: string, key: string, body: { model: string; prompt: string; size: string; }) {
|
||||||
|
let response = await axios.post(url, { ...body, n: 1 }, {
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer ' + key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (response.data && response.data.data && response.data.data.length > 0) {
|
||||||
|
return response.data.data[0].url
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//#region 软件相关的方法
|
/**
|
||||||
|
* 异步生成D3图像
|
||||||
|
* @param task 任务模型
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
async D3ImageGenerate(task: TaskModal.Task): Promise<void> {
|
||||||
|
let sdSetting = undefined
|
||||||
|
try {
|
||||||
|
console.log("D3ImageGenerate", task)
|
||||||
|
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
|
||||||
|
let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId);
|
||||||
|
let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId);
|
||||||
|
sdSetting = await this.GetSDSetting()
|
||||||
|
await this.gptService.RefreshGptSetting();
|
||||||
|
|
||||||
|
let prompt = bookTaskDetail.prompt;
|
||||||
|
let requestUrl = this.gptService.gptUrl
|
||||||
|
let uil = new URL(requestUrl);
|
||||||
|
let url = `${uil.protocol}//${uil.hostname}` + "/v1/images/generations"
|
||||||
|
|
||||||
|
if (!isEmpty(sdSetting.webui.prompt)) {
|
||||||
|
prompt = sdSetting.webui.prompt + ', ' + prompt
|
||||||
|
}
|
||||||
|
let size = `${sdSetting.webui.width}x${sdSetting.webui.height}`
|
||||||
|
// 这边需要判断下size是不是合法的
|
||||||
|
if (!['1024x1024', '1024x1792', '1792x1024'].includes(size)) {
|
||||||
|
throw new Error('D3 生成图片的尺寸不合法,只支持 1024x1024、1024x1792、1792x1024')
|
||||||
|
}
|
||||||
|
let model = 'dall-e-3'
|
||||||
|
// 一次请求生成一张 多个请求
|
||||||
|
|
||||||
|
let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage');
|
||||||
|
await CheckFolderExistsOrCreate(SdOriginalImage);
|
||||||
|
let outputFolder = bookTask.imageFolder;
|
||||||
|
await CheckFolderExistsOrCreate(outputFolder);
|
||||||
|
let inputFolder = path.join(book.bookFolderPath, 'tmp/input')
|
||||||
|
await CheckFolderExistsOrCreate(inputFolder);
|
||||||
|
|
||||||
|
let outImagePath = ''
|
||||||
|
let subImagePath = []
|
||||||
|
|
||||||
|
let batchSize = sdSetting.setting.batch_size; 7
|
||||||
|
for (let i = 0; i < batchSize; i++) {
|
||||||
|
const element = batchSize;
|
||||||
|
let imageUrl = await this.D3APIImageRequest(url, this.gptService.gptApiKey, {
|
||||||
|
model: model,
|
||||||
|
prompt: prompt,
|
||||||
|
size: size
|
||||||
|
})
|
||||||
|
// 这边开始处理返回的数据
|
||||||
|
if (isEmpty(imageUrl)) {
|
||||||
|
throw new Error('D3 生图返回的图片地址为空')
|
||||||
|
}
|
||||||
|
// 下载指定的文件
|
||||||
|
let base64 = await GetImageBase64(imageUrl)
|
||||||
|
// 将base64 写出
|
||||||
|
let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`)
|
||||||
|
await Base64ToFile(base64, imgPath);
|
||||||
|
|
||||||
|
// 写出去
|
||||||
|
if (bookTask.name == 'output_00001') {
|
||||||
|
// 复制一个到input
|
||||||
|
let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, inputImgPath)
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
// 复制到对应的文件夹里面
|
||||||
|
let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`)
|
||||||
|
await CopyFileOrFolder(imgPath, outPath)
|
||||||
|
outImagePath = outPath
|
||||||
|
}
|
||||||
|
subImagePath.push(imgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束 开始返回
|
||||||
|
// 修改数据库
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, {
|
||||||
|
outImagePath: path.relative(define.project_path, outImagePath),
|
||||||
|
subImagePath: subImagePath.map((item) => path.relative(define.project_path, item))
|
||||||
|
})
|
||||||
|
await this.bookServiceBasic.UpdateTaskStatus({
|
||||||
|
id: task.id,
|
||||||
|
status: BookBackTaskStatus.DONE
|
||||||
|
});
|
||||||
|
let resp = {
|
||||||
|
mjApiUrl: url,
|
||||||
|
progress: 100,
|
||||||
|
category: MJImageType.FLUX_API,
|
||||||
|
imageClick: subImagePath.join(','),
|
||||||
|
imageShow: subImagePath.join(','),
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "success",
|
||||||
|
subImagePath: subImagePath,
|
||||||
|
outImagePath: outImagePath,
|
||||||
|
message: "D3 生成图片成功"
|
||||||
|
}
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp)
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 1,
|
||||||
|
message: "D3 生成图片成功",
|
||||||
|
data: {
|
||||||
|
...resp,
|
||||||
|
id: bookTaskDetail.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
let errorMsg = "D3 生成图片失败,错误信息如下:" + error.toString()
|
||||||
|
await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, {
|
||||||
|
mjApiUrl: "",
|
||||||
|
progress: 0,
|
||||||
|
category: MJImageType.FLUX_API,
|
||||||
|
imageClick: "",
|
||||||
|
imageShow: "",
|
||||||
|
messageId: "",
|
||||||
|
action: MJAction.IMAGINE,
|
||||||
|
status: "error",
|
||||||
|
message: errorMsg,
|
||||||
|
})
|
||||||
|
|
||||||
|
global.newWindow[0].win.webContents.send(task.messageName, {
|
||||||
|
code: 0,
|
||||||
|
message: errorMsg,
|
||||||
|
data: {
|
||||||
|
status: 'error',
|
||||||
|
message: errorMsg,
|
||||||
|
id: task.bookTaskDetailId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
129
src/main/Service/presetService.ts
Normal file
129
src/main/Service/presetService.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { errorMessage, successMessage } from "../Public/generalTools";
|
||||||
|
import { define } from '../../define/define'
|
||||||
|
import { CheckFileOrDirExist } from "../../define/Tools/file";
|
||||||
|
import fs from 'fs'
|
||||||
|
import { ValidateJson } from "../../define/Tools/validate";
|
||||||
|
import { GeneralResponse } from "../../model/generalResponse";
|
||||||
|
import { PresetModel } from "../../model/preset";
|
||||||
|
|
||||||
|
export class PresetService {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
//TODO 这边现在都是基于文件的,后面需要改为基于数据库的
|
||||||
|
|
||||||
|
//#region 人物预设
|
||||||
|
/**
|
||||||
|
*获取所有的人物显示的预设(只要label和id)
|
||||||
|
*/
|
||||||
|
async GetCharacterPreset(): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let result = []
|
||||||
|
let tagPath = define.tag_setting
|
||||||
|
if (!(await CheckFileOrDirExist(tagPath))) {
|
||||||
|
return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tagString = await fs.promises.readFile(tagPath, 'utf-8');
|
||||||
|
if (!ValidateJson(tagString)) {
|
||||||
|
return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tags = JSON.parse(tagString)
|
||||||
|
let characterTags = tags.character_tags
|
||||||
|
for (let i = 0; characterTags && i < characterTags.length; i++) {
|
||||||
|
let element = characterTags[i]
|
||||||
|
if (element.isShow) {
|
||||||
|
result.push({
|
||||||
|
label: element.label,
|
||||||
|
id: element.key
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取人物预设失败,失败信息如下: " + error.toString(), "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定ID的人物预设的详细信息
|
||||||
|
* @param id 人物预设的ID
|
||||||
|
*/
|
||||||
|
async GetCharacterPresetDetailById(id: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let result = undefined as PresetModel.Preset
|
||||||
|
let tagPath = define.tag_setting
|
||||||
|
if (!(await CheckFileOrDirExist(tagPath))) {
|
||||||
|
return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tagString = await fs.promises.readFile(tagPath, 'utf-8');
|
||||||
|
if (!ValidateJson(tagString)) {
|
||||||
|
return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tags = JSON.parse(tagString)
|
||||||
|
let characterTags = tags.character_tags
|
||||||
|
result = characterTags.find((item: any) => item.key === id)
|
||||||
|
return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取人物预设详细信息失败,失败信息如下: " + error.toString(), "PresetService_GetCharacterPresetDetailById")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//#region 场景预设
|
||||||
|
|
||||||
|
// 获取所有的场景预设(label和ID)
|
||||||
|
async GetScenePreset(): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let result = []
|
||||||
|
let tagPath = define.tag_setting
|
||||||
|
if (!(await CheckFileOrDirExist(tagPath))) {
|
||||||
|
return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset")
|
||||||
|
}
|
||||||
|
let tagString = await fs.promises.readFile(tagPath, 'utf-8');
|
||||||
|
if (!ValidateJson(tagString)) {
|
||||||
|
return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset")
|
||||||
|
}
|
||||||
|
let tags = JSON.parse(tagString)
|
||||||
|
let sceneTags = tags.scene_tags
|
||||||
|
for (let i = 0; sceneTags && i < sceneTags.length; i++) {
|
||||||
|
let element = sceneTags[i]
|
||||||
|
if (element.isShow) {
|
||||||
|
result.push({
|
||||||
|
label: element.label,
|
||||||
|
id: element.key
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取场景预设失败,失败信息如下: " + error.toString(), "PresetService_GetScenePreset")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过获取场景预设的详细信息
|
||||||
|
* @param id 场景预设的ID
|
||||||
|
*/
|
||||||
|
async GetScenePresetDetailById(id: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
let result = undefined as PresetModel.Preset
|
||||||
|
let tagPath = define.tag_setting
|
||||||
|
if (!(await CheckFileOrDirExist(tagPath))) {
|
||||||
|
return successMessage(result, '获取场景预设详细数据成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tagString = await fs.promises.readFile(tagPath, 'utf-8');
|
||||||
|
if (!ValidateJson(tagString)) {
|
||||||
|
return successMessage(result, '获取场景预设详细数据成功', "PresetService_GetCharacterPreset")
|
||||||
|
}
|
||||||
|
let tags = JSON.parse(tagString)
|
||||||
|
let sceneTags = tags.scene_tags
|
||||||
|
result = sceneTags.find((item: any) => item.key === id)
|
||||||
|
return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset")
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage("获取场景预设详细信息失败,失败信息如下: " + error.toString(), "PresetService_GetScenePresetDetailById")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
@ -7,7 +7,12 @@ import { ReverseBook } from './Book/ReverseBook'
|
|||||||
import { GeneralResponse } from '../../model/generalResponse'
|
import { GeneralResponse } from '../../model/generalResponse'
|
||||||
import { DEFINE_STRING } from '../../define/define_string'
|
import { DEFINE_STRING } from '../../define/define_string'
|
||||||
import { MJOpt } from './MJ/mj'
|
import { MJOpt } from './MJ/mj'
|
||||||
|
import { SDOpt } from './SD/sd'
|
||||||
|
import { D3Opt } from './d3'
|
||||||
|
import { FluxOpt } from './Flux/flux'
|
||||||
import { AsyncQueue } from '../../main/quene'
|
import { AsyncQueue } from '../../main/quene'
|
||||||
|
import { SoftWareServiceBasic } from './ServiceBasic/softwareServiceBasic'
|
||||||
|
import { MJSetting } from '../../model/Setting/mjSetting'
|
||||||
|
|
||||||
export class TaskManager {
|
export class TaskManager {
|
||||||
isExecuting: boolean = false;
|
isExecuting: boolean = false;
|
||||||
@ -18,12 +23,17 @@ export class TaskManager {
|
|||||||
softwareService!: SoftwareService;
|
softwareService!: SoftwareService;
|
||||||
bookBackTaskListService!: BookBackTaskListService;
|
bookBackTaskListService!: BookBackTaskListService;
|
||||||
eventListeners: Record<string | number, Function[]> = {};
|
eventListeners: Record<string | number, Function[]> = {};
|
||||||
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
|
|
||||||
|
mjSetting: MJSetting.MjSetting
|
||||||
spaceTime: number = 5000;
|
spaceTime: number = 5000;
|
||||||
count = 0;
|
count = 0;
|
||||||
isListening = false;
|
isListening = false;
|
||||||
intervalId: any; // 用于存储 setInterval 的 ID
|
intervalId: any; // 用于存储 setInterval 的 ID
|
||||||
mjOpt: MJOpt
|
mjOpt: MJOpt
|
||||||
|
sdOpt: SDOpt
|
||||||
|
d3Opt: D3Opt
|
||||||
|
fluxOpt: FluxOpt
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isExecuting = false;
|
this.isExecuting = false;
|
||||||
@ -32,6 +42,10 @@ export class TaskManager {
|
|||||||
this.basicReverse = new BasicReverse();
|
this.basicReverse = new BasicReverse();
|
||||||
this.reverseBook = new ReverseBook();
|
this.reverseBook = new ReverseBook();
|
||||||
this.mjOpt = new MJOpt();
|
this.mjOpt = new MJOpt();
|
||||||
|
this.sdOpt = new SDOpt();
|
||||||
|
this.d3Opt = new D3Opt()
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic();
|
||||||
|
this.fluxOpt = new FluxOpt()
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitService(getMJsetting = false) {
|
async InitService(getMJsetting = false) {
|
||||||
@ -42,7 +56,8 @@ export class TaskManager {
|
|||||||
this.bookBackTaskListService = await BookBackTaskListService.getInstance();
|
this.bookBackTaskListService = await BookBackTaskListService.getInstance();
|
||||||
}
|
}
|
||||||
if (getMJsetting) {
|
if (getMJsetting) {
|
||||||
await this.mjOpt.InitService();
|
// 初始化MJ设置
|
||||||
|
this.mjSetting = await this.softWareServiceBasic.GetMjSetting()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +141,8 @@ export class TaskManager {
|
|||||||
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();
|
let taskNumber = global.mjQueue.getConcurrencyLimit();
|
||||||
if (taskNumber != this.mjOpt.mjSetting.taskCount) {
|
if (taskNumber != this.mjSetting.taskCount) {
|
||||||
global.mjQueue.concurrencyLimit = this.mjOpt.mjSetting.taskCount // 重置并发执行的数量
|
global.mjQueue.concurrencyLimit = this.mjSetting.taskCount // 重置并发执行的数量
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.mjQueue.getWaitingQueue() > 10) {
|
if (global.mjQueue.getWaitingQueue() > 10) {
|
||||||
@ -216,6 +231,68 @@ export class TaskManager {
|
|||||||
}, `${batch}_${task.id}`, batch)
|
}, `${batch}_${task.id}`, batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将MJ生图生成任务添加内存任务中
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async AddImageMJImage(task: TaskModal.Task) {
|
||||||
|
// 判断是不是MJ的任务
|
||||||
|
let batch = DEFINE_STRING.MJ.MJ_IMAGE;
|
||||||
|
global.mjQueue.enqueue(async () => {
|
||||||
|
await this.mjOpt.MJImagine(task);
|
||||||
|
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将SD生图任务添加到内存任务中
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async AddSDImage(task: TaskModal.Task) {
|
||||||
|
let batch = DEFINE_STRING.SD.TXT2IMG
|
||||||
|
global.requestQuene.enqueue(async () => {
|
||||||
|
await this.sdOpt.SDImageGenerate(task);
|
||||||
|
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步添加D3图像生成任务
|
||||||
|
*
|
||||||
|
* 此方法接受一个任务对象,将基于该任务生成D3图像
|
||||||
|
* 它使用全局请求队列来管理任务,确保并发处理的效率和稳定性
|
||||||
|
*
|
||||||
|
* @param task 任务对象,包含任务的具体信息和标识
|
||||||
|
*/
|
||||||
|
async AddD3Image(task: TaskModal.Task) {
|
||||||
|
let batch = task.messageName;
|
||||||
|
global.requestQuene.enqueue(async () => {
|
||||||
|
await this.d3Opt.D3ImageGenerate(task);
|
||||||
|
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 flux forge 任务到内存队列中
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async AddFluxForgeImage(task: TaskModal.Task) {
|
||||||
|
let batch = task.messageName
|
||||||
|
global.requestQuene.enqueue(async () => {
|
||||||
|
await this.fluxOpt.FluxForgeImage(task);
|
||||||
|
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 FLUX api 到内存队列中
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
async AddFluxAPIImage(task: TaskModal.Task) {
|
||||||
|
let batch = task.messageName;
|
||||||
|
global.requestQuene.enqueue(async () => {
|
||||||
|
await this.fluxOpt.FluxAPIImage(task);
|
||||||
|
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加任务到内存队列中,分流
|
* 添加任务到内存队列中,分流
|
||||||
* @param task 任务相关
|
* @param task 任务相关
|
||||||
@ -243,10 +320,21 @@ export class TaskManager {
|
|||||||
case BookBackTaskType.MJ_REVERSE || BookBackTaskType.SD_REVERSE:
|
case BookBackTaskType.MJ_REVERSE || BookBackTaskType.SD_REVERSE:
|
||||||
this.AddSingleReversePrompt(task);
|
this.AddSingleReversePrompt(task);
|
||||||
break;
|
break;
|
||||||
|
case BookBackTaskType.FLUX_FORGE_IMAGE:
|
||||||
|
this.AddFluxForgeImage(task);
|
||||||
|
break;
|
||||||
|
case BookBackTaskType.FLUX_API_IMAGE:
|
||||||
|
this.AddFluxAPIImage(task);
|
||||||
|
break;
|
||||||
case BookBackTaskType.MJ_IMAGE:
|
case BookBackTaskType.MJ_IMAGE:
|
||||||
this.AddImageMJImage(task);
|
this.AddImageMJImage(task);
|
||||||
break;
|
break;
|
||||||
|
case BookBackTaskType.SD_IMAGE:
|
||||||
|
this.AddSDImage(task);
|
||||||
|
break;
|
||||||
|
case BookBackTaskType.D3_IMAGE:
|
||||||
|
this.AddD3Image(task);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error('未知的任务类型');
|
throw new Error('未知的任务类型');
|
||||||
}
|
}
|
||||||
@ -276,17 +364,6 @@ export class TaskManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将MJ生图生成
|
|
||||||
* @param task
|
|
||||||
*/
|
|
||||||
async AddImageMJImage(task: TaskModal.Task) {
|
|
||||||
// 判断是不是MJ的任务
|
|
||||||
let batch = DEFINE_STRING.MJ.MJ_IMAGE;
|
|
||||||
global.mjQueue.enqueue(async () => {
|
|
||||||
await this.mjOpt.MJImagine(task);
|
|
||||||
}, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
|||||||
@ -93,15 +93,20 @@ export class Writing extends ServiceBase {
|
|||||||
'Writing_ActionStart'
|
'Writing_ActionStart'
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// 处理不同类型的错误消息
|
// 系统报错
|
||||||
if (setting.gptAI == 'laiapi') {
|
if (dataRes.code == 5000) {
|
||||||
throw new Error(GetRixApiErrorResponse(dataRes.data))
|
throw new Error('系统错误,错误信息如下:' + dataRes.message)
|
||||||
} else if (setting.gptAI == 'kimi') {
|
|
||||||
throw new Error(GetKimiErrorResponse(dataRes.data))
|
|
||||||
} else if (setting.gptAI == 'doubao') {
|
|
||||||
throw new Error(GetDoubaoErrorResponse(dataRes.data))
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(dataRes.data)
|
// 处理不同类型的错误消息
|
||||||
|
if (setting.gptAI == 'laiapi') {
|
||||||
|
throw new Error(GetRixApiErrorResponse(dataRes.data))
|
||||||
|
} else if (setting.gptAI == 'kimi') {
|
||||||
|
throw new Error(GetKimiErrorResponse(dataRes.data))
|
||||||
|
} else if (setting.gptAI == 'doubao') {
|
||||||
|
throw new Error(GetDoubaoErrorResponse(dataRes.data))
|
||||||
|
} else {
|
||||||
|
throw new Error(dataRes.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { PublicMethod } from "./Public/publicMethod"
|
|||||||
import { ImageStyleDefine } from "../define/iamgeStyleDefine";
|
import { ImageStyleDefine } from "../define/iamgeStyleDefine";
|
||||||
let tools = new Tools();
|
let tools = new Tools();
|
||||||
let pm = new PublicMethod(global);
|
let pm = new PublicMethod(global);
|
||||||
|
import { FLxuAPIImageType } from '../define/enum/image'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取对应的轨道
|
* 获取对应的轨道
|
||||||
@ -641,7 +642,15 @@ async function SaveSDConfig(value) {
|
|||||||
sd_config.webui.height = value.height ? value.height : sd_config.webui.height;
|
sd_config.webui.height = value.height ? value.height : sd_config.webui.height;
|
||||||
sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale;
|
sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale;
|
||||||
sd_config.webui.adetailer = value.hasOwnProperty("adetailer") ? value.adetailer : sd_config.webui.adetailer;
|
sd_config.webui.adetailer = value.hasOwnProperty("adetailer") ? value.adetailer : sd_config.webui.adetailer;
|
||||||
|
|
||||||
|
if(!sd_config.flux){
|
||||||
|
let model = {
|
||||||
|
model : value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX
|
||||||
|
}
|
||||||
|
sd_config.flux = model
|
||||||
|
}else{
|
||||||
|
sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX;
|
||||||
|
}
|
||||||
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config));
|
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config));
|
||||||
return {
|
return {
|
||||||
code: 1,
|
code: 1,
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { app, shell, BrowserWindow, ipcMain, dialog, nativeTheme, session } from
|
|||||||
import path, { join } from 'path'
|
import path, { join } from 'path'
|
||||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||||
import icon from '../../resources/icon.ico?asset'
|
import icon from '../../resources/icon.ico?asset'
|
||||||
import { define } from '../define/define.js'
|
import { define } from '../define/define'
|
||||||
import { func } from './func.js'
|
import { func } from './func.js'
|
||||||
import { AsyncQueue } from './quene'
|
import { AsyncQueue } from './quene'
|
||||||
import { DEFINE_STRING } from '../define/define_string'
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
@ -17,6 +17,7 @@ import { Setting } from './setting/setting.js'
|
|||||||
import { has, isEmpty } from 'lodash'
|
import { has, isEmpty } from 'lodash'
|
||||||
import { AutoSync } from './setting/autoSync.js'
|
import { AutoSync } from './setting/autoSync.js'
|
||||||
import { TaskManager } from './Service/taskManage'
|
import { TaskManager } from './Service/taskManage'
|
||||||
|
import { SoftWareServiceBasic } from './Service/ServiceBasic/softwareServiceBasic'
|
||||||
|
|
||||||
// ipc
|
// ipc
|
||||||
import { DiscordIpc, RemoveDiscordIpc } from './IPCEvent/discordIpc.js'
|
import { DiscordIpc, RemoveDiscordIpc } from './IPCEvent/discordIpc.js'
|
||||||
@ -26,6 +27,7 @@ import { RegisterIpc } from './IPCEvent/index.js'
|
|||||||
let tools = new Tools()
|
let tools = new Tools()
|
||||||
let imageGenerate = new ImageGenerate(global)
|
let imageGenerate = new ImageGenerate(global)
|
||||||
let setting = new Setting(global)
|
let setting = new Setting(global)
|
||||||
|
let softWareServiceBasic = new SoftWareServiceBasic()
|
||||||
|
|
||||||
async function InitData(gl) {
|
async function InitData(gl) {
|
||||||
let res = await setting.getSettingDafultData()
|
let res = await setting.getSettingDafultData()
|
||||||
@ -113,6 +115,9 @@ async function createWindow(hash = 'ShowMessage', data, url = null) {
|
|||||||
let window_wh_bm = mainWindow.getBounds()
|
let window_wh_bm = mainWindow.getBounds()
|
||||||
// 记录到文件中
|
// 记录到文件中
|
||||||
await setting.ModifySampleSetting(JSON.stringify({ window_wh_bm: window_wh_bm }))
|
await setting.ModifySampleSetting(JSON.stringify({ window_wh_bm: window_wh_bm }))
|
||||||
|
await softWareServiceBasic.UpdateSoftware({
|
||||||
|
window_wh_bm: JSON.stringify(window_wh_bm)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -141,7 +141,8 @@ export class AsyncQueue {
|
|||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
DEFINE_STRING.QUEUE_BATCH.SD_BACKSTEP_GENERATE_IMAGE,
|
DEFINE_STRING.QUEUE_BATCH.SD_BACKSTEP_GENERATE_IMAGE,
|
||||||
DEFINE_STRING.QUEUE_BATCH.SD_ORIGINAL_GENERATE_IMAGE
|
DEFINE_STRING.QUEUE_BATCH.SD_ORIGINAL_GENERATE_IMAGE,
|
||||||
|
DEFINE_STRING.SD.TXT2IMG
|
||||||
].includes(batchId)
|
].includes(batchId)
|
||||||
) {
|
) {
|
||||||
retryTask()
|
retryTask()
|
||||||
|
|||||||
@ -46,10 +46,8 @@ async function GlobalAutoSync() {
|
|||||||
if (softWareData.globalSetting == null || softWareData.globalSetting == '') {
|
if (softWareData.globalSetting == null || softWareData.globalSetting == '') {
|
||||||
let initGlobalConfig = await fspromises.readFile(initConifgPath, 'utf-8')
|
let initGlobalConfig = await fspromises.readFile(initConifgPath, 'utf-8')
|
||||||
softWareData.globalSetting = initGlobalConfig
|
softWareData.globalSetting = initGlobalConfig
|
||||||
let updateSfotwareRes = _softwareService.UpdateSoftware(softWareData)
|
_softwareService.UpdateSoftware(softWareData)
|
||||||
if (updateSfotwareRes.code == 1) {
|
global.logger.info('AutoSunc_GlobalAutoSync', '初始化全局设置成功')
|
||||||
global.logger.info('AutoSunc_GlobalAutoSync', '初始化全局设置成功')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import SoftwareService from '../../define/db/service/SoftWare/softwareService'
|
|
||||||
import { ComponentSize } from '../../define/enum/softwareEnum'
|
import { ComponentSize } from '../../define/enum/softwareEnum'
|
||||||
import { errorMessage, successMessage } from '../Public/generalTools'
|
import { errorMessage, successMessage } from '../Public/generalTools'
|
||||||
|
import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic'
|
||||||
|
|
||||||
export class BasicSetting {
|
export class BasicSetting {
|
||||||
constructor() {}
|
softWareServiceBasic: SoftWareServiceBasic
|
||||||
|
constructor() {
|
||||||
// 初始化数据
|
this.softWareServiceBasic = new SoftWareServiceBasic()
|
||||||
async init() {
|
|
||||||
this.setting = await SoftwareService.getInstance()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取修改尺寸的下拉菜单的尺寸
|
* 获取修改尺寸的下拉菜单的尺寸
|
||||||
* @returns
|
* @returns
|
||||||
@ -46,9 +43,8 @@ export class BasicSetting {
|
|||||||
// 获取基础配置信息
|
// 获取基础配置信息
|
||||||
async GetSoftwareSetting() {
|
async GetSoftwareSetting() {
|
||||||
try {
|
try {
|
||||||
await this.init()
|
let res = await this.softWareServiceBasic.GetSoftwareData()
|
||||||
let res = this.setting.GetSoftwareData()
|
return successMessage(res, '获取软件配置信息成功', 'BasicSetting_GetSoftwareSetting')
|
||||||
return res
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(error.message, 'BasicSetting_GetSoftwareSetting')
|
return errorMessage(error.message, 'BasicSetting_GetSoftwareSetting')
|
||||||
}
|
}
|
||||||
@ -60,11 +56,10 @@ export class BasicSetting {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async SaveSoftWareSetting(paramms) {
|
async SaveSoftWareSetting(paramms: SoftwareSettingModel.SoftwareSetting) {
|
||||||
try {
|
try {
|
||||||
await this.init()
|
await this.softWareServiceBasic.UpdateSoftware(paramms)
|
||||||
let res = this.setting.UpdateSoftware(paramms)
|
return successMessage(null, '保存软件设置成功', 'BasicSetting_SaveSoftWareSetting')
|
||||||
return res
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(error.message, 'BasicSetting_SaveSoftWareSetting')
|
return errorMessage(error.message, 'BasicSetting_SaveSoftWareSetting')
|
||||||
}
|
}
|
||||||
@ -10,12 +10,15 @@ import { DEFINE_STRING } from '../../define/define_string'
|
|||||||
import { TagDefine } from '../../define/tagDefine'
|
import { TagDefine } from '../../define/tagDefine'
|
||||||
import { errorMessage } from '../Public/generalTools'
|
import { errorMessage } from '../Public/generalTools'
|
||||||
import { TaskManager } from '../Service/taskManage'
|
import { TaskManager } from '../Service/taskManage'
|
||||||
|
import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic'
|
||||||
|
import { FLxuAPIImageType } from '../../define/enum/image'
|
||||||
|
|
||||||
let tagDefine = new TagDefine(global)
|
let tagDefine = new TagDefine(global)
|
||||||
export class Setting {
|
export class Setting {
|
||||||
constructor(global) {
|
constructor(global) {
|
||||||
this.global = global
|
this.global = global
|
||||||
this.tools = new Tools()
|
this.tools = new Tools()
|
||||||
|
this.softWareServiceBasic = new SoftWareServiceBasic()
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 剪映设置
|
//#region 剪映设置
|
||||||
@ -172,7 +175,8 @@ export class Setting {
|
|||||||
cfg_scale: sd_config.webui.cfg_scale,
|
cfg_scale: sd_config.webui.cfg_scale,
|
||||||
sd_model: sd_config.sd_model,
|
sd_model: sd_config.sd_model,
|
||||||
lora: sd_config.lora,
|
lora: sd_config.lora,
|
||||||
sampler: sd_config.sampler
|
sampler: sd_config.sampler,
|
||||||
|
flux_model: sd_config.flux?.model ? sd_config.flux.model : FLxuAPIImageType.FLUX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
26
src/model/Setting/softwareSetting.d.ts
vendored
26
src/model/Setting/softwareSetting.d.ts
vendored
@ -14,4 +14,30 @@ declare namespace SoftwareSettingModel {
|
|||||||
translationSetting?: string
|
translationSetting?: string
|
||||||
subtitleSetting?: string
|
subtitleSetting?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GlobalSetting = {
|
||||||
|
draft_path: string = undefined // 草稿路径
|
||||||
|
project_path: string = undefined // 项目路径
|
||||||
|
project_name: string = undefined // 项目名称
|
||||||
|
gpt_business: string = undefined // GPT服务商ID
|
||||||
|
gpt_model: string = undefined // GPT模型
|
||||||
|
task_number: number = undefined // 任务数量
|
||||||
|
theme: string = undefined // 主题
|
||||||
|
gpt_auto_inference: string = undefined // GPT自动推理模式
|
||||||
|
webui_api_url: string = undefined // webui地址
|
||||||
|
gpt_count: number = 10 // GPT上下文数量
|
||||||
|
customize_gpt_prompt: string = undefined // 自定义GPT提示ID
|
||||||
|
character_select_model: "drop" | 'tag' = 'drop' // 人物选择模式,
|
||||||
|
image_generate_category: 'sd' | 'mj' | 'd3' | 'fulx-forge' | 'flux-api' = 'mj' // 生图方式
|
||||||
|
window_wh_bm_remember: boolean = false// 记住窗口大小
|
||||||
|
window_wh_bm: {
|
||||||
|
x: number = 0, // 窗口x坐标
|
||||||
|
y: number = 0, // 窗口y坐标
|
||||||
|
width: number = 800, // 窗口宽度
|
||||||
|
height: number = 600, // 窗口高度
|
||||||
|
},
|
||||||
|
space_image: string = undefined // 空白图片
|
||||||
|
gpt_key: string = undefined // GPT KEY,
|
||||||
|
laiApiSelect: string = undefined // LaiAPI选择
|
||||||
|
}
|
||||||
}
|
}
|
||||||
3
src/model/book.d.ts
vendored
3
src/model/book.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, TaskExecuteType, BookRepalceDataType } from "../define/enum/bookEnum"
|
import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, TaskExecuteType, BookRepalceDataType, BookImageCategory } from "../define/enum/bookEnum"
|
||||||
import { MJAction } from "../define/enum/bookEnum"
|
import { MJAction } from "../define/enum/bookEnum"
|
||||||
import { MJImageType } from "../define/enum/mjEnum"
|
import { MJImageType } from "../define/enum/mjEnum"
|
||||||
|
|
||||||
@ -154,6 +154,7 @@ declare namespace Book {
|
|||||||
timeLimit?: string // 事件实现(0 -- 3000)
|
timeLimit?: string // 事件实现(0 -- 3000)
|
||||||
subValue?: string // 包含的字幕数据
|
subValue?: string // 包含的字幕数据
|
||||||
characterTags?: string[] // 角色标签
|
characterTags?: string[] // 角色标签
|
||||||
|
sceneTags?: string[] // 场景标签
|
||||||
gptPrompt?: string // GPT提示词
|
gptPrompt?: string // GPT提示词
|
||||||
mjMessage?: MJMessage // MJ消息
|
mjMessage?: MJMessage // MJ消息
|
||||||
outImagePath?: string // 输出图片地址
|
outImagePath?: string // 输出图片地址
|
||||||
|
|||||||
2
src/model/generalResponse.d.ts
vendored
2
src/model/generalResponse.d.ts
vendored
@ -30,7 +30,7 @@ declare namespace GeneralResponse {
|
|||||||
type MessageResponse = {
|
type MessageResponse = {
|
||||||
code: number,
|
code: number,
|
||||||
id: string, // 消息的唯一标识(可以和前端相关联)
|
id: string, // 消息的唯一标识(可以和前端相关联)
|
||||||
type: ResponseMessageType,
|
type?: ResponseMessageType,
|
||||||
dialogType?: DialogType = DialogType.MESSAGE,
|
dialogType?: DialogType = DialogType.MESSAGE,
|
||||||
message?: string,
|
message?: string,
|
||||||
data?: MJ.MJResponseToFront | Buffer | string | TranslateModel.TranslateResponseMessageModel | ProgressResponse | SubtitleProgressResponse
|
data?: MJ.MJResponseToFront | Buffer | string | TranslateModel.TranslateResponseMessageModel | ProgressResponse | SubtitleProgressResponse
|
||||||
|
|||||||
10
src/model/mj.d.ts
vendored
10
src/model/mj.d.ts
vendored
@ -14,15 +14,15 @@ declare namespace MJ {
|
|||||||
type: MJRespoonseType, // 返回前端的操作类型
|
type: MJRespoonseType, // 返回前端的操作类型
|
||||||
mjType: MJAction, // 执行MJ的类型
|
mjType: MJAction, // 执行MJ的类型
|
||||||
category: MJImageType, // 调用MJ分类
|
category: MJImageType, // 调用MJ分类
|
||||||
message_id?: string, // 返回消息的id,就是任务ID
|
messageId?: string, // 返回消息的id,就是任务ID
|
||||||
image_click?: string, // 预览的图片(再使用浏览器模式的时候需要,其他都是null)
|
imageClick?: string, // 预览的图片(再使用浏览器模式的时候需要,其他都是null)
|
||||||
image_show?: string, // 实际下载的图片的地址
|
imageShow?: string, // 实际下载的图片的地址
|
||||||
image_path?: string, //实际下载的图片的地址
|
imagePath?: string, //实际下载的图片的地址
|
||||||
prompt?: string, // 提示词消息
|
prompt?: string, // 提示词消息
|
||||||
progress: number, // 实现的进程
|
progress: number, // 实现的进程
|
||||||
message?: string // 消息
|
message?: string // 消息
|
||||||
status: string
|
status: string
|
||||||
mj_api_url?: string // 请求的MJ地址
|
mjApiUrl?: string // 请求的MJ地址
|
||||||
outImagePath?: string // 输出的图片地址
|
outImagePath?: string // 输出的图片地址
|
||||||
subImagePath?: string[] // 子图片地址
|
subImagePath?: string[] // 子图片地址
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/model/preset.d.ts
vendored
Normal file
31
src/model/preset.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { PresetType } from "../define/enum/preset"
|
||||||
|
|
||||||
|
declare namespace PresetModel {
|
||||||
|
/**
|
||||||
|
* 完整的预设的数据Model
|
||||||
|
*/
|
||||||
|
type Preset = {
|
||||||
|
id?: string
|
||||||
|
label?: string
|
||||||
|
type?: TAGType
|
||||||
|
showImage?: string
|
||||||
|
prompt?: string
|
||||||
|
chinesePrompt?: string
|
||||||
|
imageUrl?: string
|
||||||
|
srefSw?: number
|
||||||
|
crefCw?: number
|
||||||
|
lora?: string
|
||||||
|
loraWeight?: number
|
||||||
|
isShow?: boolean
|
||||||
|
children?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前端界面相关的数据model
|
||||||
|
*/
|
||||||
|
type PresetList = {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
checked: boolean = false
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/model/subtitle.d.ts
vendored
36
src/model/subtitle.d.ts
vendored
@ -1,6 +1,11 @@
|
|||||||
import { GetSubtitleType } from "../define/enum/waterMarkAndSubtitle"
|
import { GetSubtitleType } from "../define/enum/waterMarkAndSubtitle"
|
||||||
|
|
||||||
declare namespace SubtitleModel {
|
declare namespace SubtitleModel {
|
||||||
|
|
||||||
|
//#region 提取视频文案相关
|
||||||
|
/**
|
||||||
|
* 提取文案设置
|
||||||
|
*/
|
||||||
type subtitleSettingModel = {
|
type subtitleSettingModel = {
|
||||||
selectModel: GetSubtitleType,
|
selectModel: GetSubtitleType,
|
||||||
laiWhisper: {
|
laiWhisper: {
|
||||||
@ -10,4 +15,35 @@ declare namespace SubtitleModel {
|
|||||||
prompt: string
|
prompt: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 小说文案相关s
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文案数据包含的字幕数据
|
||||||
|
*/
|
||||||
|
type CopywritingSubValue = {
|
||||||
|
end_time: number,
|
||||||
|
start_time: number,
|
||||||
|
id: string,
|
||||||
|
srt_value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文案数据类型
|
||||||
|
*/
|
||||||
|
type SaveCopywritingData = {
|
||||||
|
id: string,
|
||||||
|
lastId: string,
|
||||||
|
no: number,
|
||||||
|
after_gpt: string,
|
||||||
|
start_time: number,
|
||||||
|
end_time: number,
|
||||||
|
subValue: CopywritingSubValue[]
|
||||||
|
timeLimit: string,
|
||||||
|
word: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
27
src/model/task.d.ts
vendored
27
src/model/task.d.ts
vendored
@ -1,18 +1,19 @@
|
|||||||
|
|
||||||
declare namespace TaskModal {
|
declare namespace TaskModal {
|
||||||
type Task = {
|
type Task = {
|
||||||
id: string
|
id?: string
|
||||||
bookId: string
|
bookId?: string
|
||||||
bookTaskId: string
|
bookTaskId?: string
|
||||||
bookTaskDetailId: string
|
bookTaskDetailId?: string
|
||||||
name: string // 任务名称,小说名+批次名+分镜名
|
name?: string // 任务名称,小说名+批次名+分镜名
|
||||||
type: BookBackTaskType
|
type?: BookBackTaskType
|
||||||
status: BookBackTaskStatus
|
status?: BookBackTaskStatus
|
||||||
errorMessage: string | null
|
errorMessage?: string | null
|
||||||
executeType: TaskExecuteType // 任务执行类型,手动还是自动
|
executeType?: TaskExecuteType // 任务执行类型,手动还是自动
|
||||||
createTime: Date
|
createTime?: Date
|
||||||
updateTime: Date
|
updateTime?: Date
|
||||||
startTime: number
|
startTime?: number
|
||||||
endTime: number
|
endTime?: number,
|
||||||
|
messageName?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
src/model/translate.d.ts
vendored
1
src/model/translate.d.ts
vendored
@ -17,6 +17,7 @@ declare namespace TranslateModel {
|
|||||||
reversePromptId?: string // 反推提示词ID
|
reversePromptId?: string // 反推提示词ID
|
||||||
windowId?: number // 窗口ID
|
windowId?: number // 窗口ID
|
||||||
type: TranslateType // 翻译类型
|
type: TranslateType // 翻译类型
|
||||||
|
responseMessgeName?: string // 返回的消息名称(用作自定义)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TranslateResponseMessageModel = {
|
type TranslateResponseMessageModel = {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import { DEFINE_STRING } from '../define/define_string'
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
import { Book } from '../model/book'
|
import { Book } from '../model/book'
|
||||||
|
import { SubtitleModel } from '../model/subtitle'
|
||||||
|
import { BookType, OperateBookType } from '../define/enum/bookEnum'
|
||||||
|
|
||||||
const book = {
|
const book = {
|
||||||
// 获取小说操作类型(原创/SD反推/MJ反推)
|
// 获取小说操作类型(原创/SD反推/MJ反推)
|
||||||
@ -84,7 +86,7 @@ const book = {
|
|||||||
|
|
||||||
//#region 文案相关信息
|
//#region 文案相关信息
|
||||||
|
|
||||||
// 获取文案信息
|
// 反推识别文案的方法
|
||||||
GetCopywriting: async (bookId, bookTaskId, operateBookType, coverData) =>
|
GetCopywriting: async (bookId, bookTaskId, operateBookType, coverData) =>
|
||||||
await ipcRenderer.invoke(
|
await ipcRenderer.invoke(
|
||||||
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
DEFINE_STRING.BOOK.GET_COPYWRITING,
|
||||||
@ -94,6 +96,11 @@ const book = {
|
|||||||
coverData
|
coverData
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// 保存导入的文案数据(文案和字幕对齐后的)
|
||||||
|
SaveCopywriting: async (bookTaskId: string, copywritingData: SubtitleModel.SaveCopywritingData, operateBookType: OperateBookType) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.SAVE_COPYWRITING, bookTaskId, copywritingData, operateBookType),
|
||||||
|
|
||||||
|
|
||||||
// 将文案信息导出,方便修改
|
// 将文案信息导出,方便修改
|
||||||
ExportCopywriting: async (bookTaskId) =>
|
ExportCopywriting: async (bookTaskId) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.EXPORT_COPYWRITING, bookTaskId),
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.EXPORT_COPYWRITING, bookTaskId),
|
||||||
@ -121,10 +128,6 @@ const book = {
|
|||||||
MergePrompt: async (id, type, operateBookType) =>
|
MergePrompt: async (id, type, operateBookType) =>
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.MERGE_PROMPT, id, type, operateBookType),
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.MERGE_PROMPT, id, type, operateBookType),
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region 一键反推的单个任务
|
|
||||||
|
|
||||||
// 添加单句反推的
|
// 添加单句反推的
|
||||||
AddReversePrompt: async (bookTaskDetailIds, operateBookType, type) =>
|
AddReversePrompt: async (bookTaskDetailIds, operateBookType, type) =>
|
||||||
await ipcRenderer.invoke(
|
await ipcRenderer.invoke(
|
||||||
@ -143,6 +146,30 @@ const book = {
|
|||||||
index
|
index
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// 删除掉所有的反推和GPT提示词数据
|
||||||
|
ResetGptReverseData: async (id: string, operateBookType: OperateBookType, type: BookType) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.RESET_GPT_REVERSE_DATA, id, operateBookType, type),
|
||||||
|
|
||||||
|
// 删除所有的合并提示词数据
|
||||||
|
ResetMergePromptData: async (id, operateBookType) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_MERGE_PROMPT_DATA, id, operateBookType),
|
||||||
|
|
||||||
|
// 原创推理所有的提示词
|
||||||
|
OriginalGetPrompt: async (id: string, operateBookType: OperateBookType, coverData: boolean) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT, id, operateBookType, coverData),
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 图片相关
|
||||||
|
|
||||||
|
// 删除所有的生成图片
|
||||||
|
ResetGenerateImage: async (id: string, operateBookType: OperateBookType, coverData: boolean) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_GENERATE_IMAGE, id, operateBookType, coverData),
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 一键反推的单个任务
|
||||||
|
|
||||||
// 单个重选反推的提示词
|
// 单个重选反推的提示词
|
||||||
SingleReverseToGptPrompt: async (bookTaskDetailId, index) =>
|
SingleReverseToGptPrompt: async (bookTaskDetailId, index) =>
|
||||||
await ipcRenderer.invoke(
|
await ipcRenderer.invoke(
|
||||||
@ -151,17 +178,6 @@ const book = {
|
|||||||
index
|
index
|
||||||
),
|
),
|
||||||
|
|
||||||
// 删除掉所有的反推和GPT提示词数据
|
|
||||||
ResetGptReverseData: async (id, operateBookType, type) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.RESET_GPT_REVERSE_DATA, id, operateBookType, type),
|
|
||||||
|
|
||||||
// 删除所有的合并提示词数据
|
|
||||||
ResetMergePromptData: async (id, operateBookType) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_MERGE_PROMPT_DATA, id, operateBookType),
|
|
||||||
|
|
||||||
// 删除所有的生成图片
|
|
||||||
ResetGenerateImage: async (id, operateBookType) =>
|
|
||||||
await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_GENERATE_IMAGE, id, operateBookType),
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,18 @@ const db = {
|
|||||||
// 修改小说详细任务的数据
|
// 修改小说详细任务的数据
|
||||||
UpdateBookTaskDetailData: async (bookTaskDetailId: string, data: Book.SelectBookTaskDetail) => {
|
UpdateBookTaskDetailData: async (bookTaskDetailId: string, data: Book.SelectBookTaskDetail) => {
|
||||||
return await ipcRenderer.invoke(DEFINE_STRING.DB.UPDATE_BOOK_TASK_DETAIL_DATA, bookTaskDetailId, data)
|
return await ipcRenderer.invoke(DEFINE_STRING.DB.UPDATE_BOOK_TASK_DETAIL_DATA, bookTaskDetailId, data)
|
||||||
}
|
},
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
//#region 软件设置的修改
|
||||||
|
|
||||||
|
// 修改软件通用设置
|
||||||
|
UpdateSoftwareSetting: async (software: SoftwareSettingModel.SoftwareSetting) => {
|
||||||
|
return await ipcRenderer.invoke(DEFINE_STRING.DB.UPDATE_SOFTWARE_SETTING, software)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
export { db }
|
export { db }
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { electronAPI } from '@electron-toolkit/preload'
|
|||||||
import { DEFINE_STRING } from '../define/define_string'
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
import { discord } from './discord.js'
|
import { discord } from './discord.js'
|
||||||
import { mj } from './mj.js'
|
import { mj } from './mj.js'
|
||||||
import { sd } from './sd.js'
|
import { sd } from './sd'
|
||||||
import { img } from './img.js'
|
import { img } from './img.js'
|
||||||
import { system } from './system.js'
|
import { system } from './system.js'
|
||||||
import { setting } from './setting.js'
|
import { setting } from './setting.js'
|
||||||
@ -14,6 +14,8 @@ import { write } from './write.js'
|
|||||||
import { gpt } from './gpt.js'
|
import { gpt } from './gpt.js'
|
||||||
import { db } from './db'
|
import { db } from './db'
|
||||||
import { translate } from './translate.js'
|
import { translate } from './translate.js'
|
||||||
|
import { preset } from './preset'
|
||||||
|
import { task } from './task'
|
||||||
// Custom APIs for renderer
|
// Custom APIs for renderer
|
||||||
|
|
||||||
let events = []
|
let events = []
|
||||||
@ -451,6 +453,9 @@ const api = {
|
|||||||
showGlobalNotificationDialog: (value) =>
|
showGlobalNotificationDialog: (value) =>
|
||||||
ipcRenderer.send(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, value),
|
ipcRenderer.send(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, value),
|
||||||
|
|
||||||
|
// 打开message
|
||||||
|
showGlobalMessage: (value) => ipcRenderer.send(DEFINE_STRING.SHOW_GLOBAL_MESSAGE, value),
|
||||||
|
|
||||||
// 知道文件地址,获取文件base64编码
|
// 知道文件地址,获取文件base64编码
|
||||||
GetFileBase64: async (value, callback) =>
|
GetFileBase64: async (value, callback) =>
|
||||||
callback(await ipcRenderer.invoke(DEFINE_STRING.GET_FILE_BASE64, value)),
|
callback(await ipcRenderer.invoke(DEFINE_STRING.GET_FILE_BASE64, value)),
|
||||||
@ -480,6 +485,8 @@ if (process.contextIsolated) {
|
|||||||
contextBridge.exposeInMainWorld('gpt', gpt)
|
contextBridge.exposeInMainWorld('gpt', gpt)
|
||||||
contextBridge.exposeInMainWorld('translate', translate)
|
contextBridge.exposeInMainWorld('translate', translate)
|
||||||
contextBridge.exposeInMainWorld('db', db)
|
contextBridge.exposeInMainWorld('db', db)
|
||||||
|
contextBridge.exposeInMainWorld('preset', preset)
|
||||||
|
contextBridge.exposeInMainWorld('task', task)
|
||||||
contextBridge.exposeInMainWorld('darkMode', {
|
contextBridge.exposeInMainWorld('darkMode', {
|
||||||
toggle: (value) => ipcRenderer.invoke('dark-mode:toggle', value)
|
toggle: (value) => ipcRenderer.invoke('dark-mode:toggle', value)
|
||||||
})
|
})
|
||||||
@ -501,5 +508,7 @@ if (process.contextIsolated) {
|
|||||||
window.write = write
|
window.write = write
|
||||||
window.gpt = gpt
|
window.gpt = gpt
|
||||||
window.db = db
|
window.db = db
|
||||||
|
window.preset = preset
|
||||||
|
window.task = task
|
||||||
window.translate = translate
|
window.translate = translate
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,8 +70,14 @@ const mj = {
|
|||||||
callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.AUTO_MATCH_USER, value)),
|
callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.AUTO_MATCH_USER, value)),
|
||||||
|
|
||||||
// 单个出图
|
// 单个出图
|
||||||
AddMJGenerateImageTask: async (id, operateBookType) =>
|
AddMJGenerateImageTask: async (id, operateBookType, responseMessageName, coverData) =>
|
||||||
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,
|
||||||
|
responseMessageName,
|
||||||
|
coverData
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { mj }
|
export { mj }
|
||||||
|
|||||||
16
src/preload/preset.ts
Normal file
16
src/preload/preset.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ipcRenderer } from 'electron'
|
||||||
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
|
|
||||||
|
const preset = {
|
||||||
|
/**
|
||||||
|
* 获取人物预设的列表
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
GetCharacterPreset: async () =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.PRESET.GET_CHARACTER_PRESET),
|
||||||
|
|
||||||
|
GetScenePreset: async () =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.PRESET.GET_SCENE_PRESET)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { preset }
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import { DEFINE_STRING } from '../define/define_string'
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
|
import { OperateBookType } from '../define/enum/bookEnum'
|
||||||
|
|
||||||
const sd = {
|
const sd = {
|
||||||
// 加载当前链接的SD服务数据
|
// 加载当前链接的SD服务数据
|
||||||
31
src/preload/task.ts
Normal file
31
src/preload/task.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { ipcRenderer } from 'electron'
|
||||||
|
import { DEFINE_STRING } from '../define/define_string'
|
||||||
|
import { BookBackTaskType, TaskExecuteType } from '../define/enum/bookEnum'
|
||||||
|
|
||||||
|
const task = {
|
||||||
|
/**
|
||||||
|
* 添加单个任务
|
||||||
|
* @param bookId 小说ID
|
||||||
|
* @param taskType 任务类型
|
||||||
|
* @param executeType 任务执行类型
|
||||||
|
* @param bookTaskId 小说任务ID
|
||||||
|
* @param bookTaskDetailId 小说分镜ID
|
||||||
|
* @param responseMessageName 响应消息名称
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
AddBookBackTask: async (bookId: string, taskType: BookBackTaskType,
|
||||||
|
executeType = TaskExecuteType.AUTO,
|
||||||
|
bookTaskId = null,
|
||||||
|
bookTaskDetailId = null,
|
||||||
|
responseMessageName: string = null) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName),
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同时太你家多个任务
|
||||||
|
* @param task
|
||||||
|
*/
|
||||||
|
AddMultiBookBackTask: async (task: TaskModal.Task[]) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, task),
|
||||||
|
}
|
||||||
|
export { task }
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-spin style="z-index: 1000 !important;" :show="softwareStore.spin.spinning">
|
<n-spin style="z-index: 1000 !important" :show="softwareStore.spin.spinning">
|
||||||
<template #description> {{ softwareStore.spin.tip }} </template>
|
<template #description> {{ softwareStore.spin.tip }} </template>
|
||||||
<n-config-provider
|
<n-config-provider
|
||||||
:hljs="hljs"
|
:hljs="hljs"
|
||||||
@ -47,6 +47,7 @@ export default defineComponent({
|
|||||||
softwareStore.SoftColor = SoftColor
|
softwareStore.SoftColor = SoftColor
|
||||||
window.api.getSettingDafultData(async (value) => {
|
window.api.getSettingDafultData(async (value) => {
|
||||||
await window.darkMode.toggle(value.theme)
|
await window.darkMode.toggle(value.theme)
|
||||||
|
softwareStore.globalSetting = value
|
||||||
})
|
})
|
||||||
let software = await window.setting.GetSoftwareSetting()
|
let software = await window.setting.GetSoftwareSetting()
|
||||||
if (software.code == 0) {
|
if (software.code == 0) {
|
||||||
@ -58,7 +59,7 @@ export default defineComponent({
|
|||||||
if (software.data.length == 0) {
|
if (software.data.length == 0) {
|
||||||
throw new Error('初始化信息错误: 未获取到数据')
|
throw new Error('初始化信息错误: 未获取到数据')
|
||||||
}
|
}
|
||||||
softwareStore.softWare = software.data[0]
|
softwareStore.softWare = software.data
|
||||||
await window.darkMode.toggle(softwareStore.softWare.theme)
|
await window.darkMode.toggle(softwareStore.softWare.theme)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="data.subValue && data.subValue.length != 0">
|
<div style="height: 135px; width : 100%;overflow: auto; display: flex; margin: auto">
|
||||||
<div v-for="(item, index) in data.subValue">
|
<div v-if="data.subValue && data.subValue.length != 0" style="width : 100%">
|
||||||
<n-input
|
<div v-for="(item, index) in data.subValue" style="width : 100%">
|
||||||
v-model:value="item.srt_value"
|
<n-input
|
||||||
type="textarea"
|
v-model:value="item.srt_value"
|
||||||
size="tiny"
|
type="textarea"
|
||||||
:autosize="{ minRows: 1, maxRows: 5 }"
|
style="width : 100%"
|
||||||
@input="InputDebounced"
|
size="tiny"
|
||||||
>
|
:autosize="{ minRows: 1, maxRows: 5 }"
|
||||||
</n-input>
|
@input="InputDebounced"
|
||||||
|
>
|
||||||
|
</n-input>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<n-input
|
||||||
|
v-else
|
||||||
|
v-model:value="data.afterGpt"
|
||||||
|
type="textarea"
|
||||||
|
size="tiny"
|
||||||
|
:autosize="{ minRows: 6, maxRows: 6 }"
|
||||||
|
@input="InputDebounced"
|
||||||
|
>
|
||||||
|
</n-input>
|
||||||
</div>
|
</div>
|
||||||
<n-input
|
|
||||||
v-else
|
|
||||||
v-model:value="data.afterGpt"
|
|
||||||
type="textarea"
|
|
||||||
size="tiny"
|
|
||||||
:autosize="{ minRows: 6, maxRows: 6 }"
|
|
||||||
@input="InputDebounced"
|
|
||||||
>
|
|
||||||
</n-input>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -0,0 +1,322 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="height: 22px; display: flex">
|
||||||
|
<div v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'" style="z-index: 100">
|
||||||
|
进度:{{ data.mjMessage?.progress }}%
|
||||||
|
</div>
|
||||||
|
<n-tag
|
||||||
|
v-if="data.mjMessage?.status != 'error'"
|
||||||
|
type="success"
|
||||||
|
style="height: 18px; margin: 2px 0 2px 5px"
|
||||||
|
>{{
|
||||||
|
data.mjMessage?.status != null && data.mjMessage?.status != ''
|
||||||
|
? data.mjMessage?.status
|
||||||
|
: 'wait'
|
||||||
|
}}</n-tag
|
||||||
|
>
|
||||||
|
<div v-else style="margin-left: 5px">
|
||||||
|
<n-popover style="padding: 0; margin: 0" trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-tag style="height: 18px; margin: 2px 0 2px 0" type="error">error</n-tag>
|
||||||
|
</template>
|
||||||
|
<span>{{ data.mjMessage?.message }}</span>
|
||||||
|
</n-popover>
|
||||||
|
</div>
|
||||||
|
<n-popover
|
||||||
|
v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'"
|
||||||
|
style="padding: 0; margin: 0"
|
||||||
|
trigger="hover"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
margin-left: 5px;
|
||||||
|
width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ data.mjMessage?.messageId }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span>{{ data.mjMessage?.messageId }}</span>
|
||||||
|
</n-popover>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
<div
|
||||||
|
style="display: flex; margin-right: 10px; height: auto; min-height: 120px"
|
||||||
|
@dragstart="imageDragStart"
|
||||||
|
@drop="imageDragDrop"
|
||||||
|
@dragover="imageDragOver"
|
||||||
|
>
|
||||||
|
<div style="display: flex; align-items: center; position: relative">
|
||||||
|
<n-image
|
||||||
|
class="g-image-class generate-image-show"
|
||||||
|
:src="data.outImagePath ? data.outImagePath : softwareStore.globalSetting.space_image"
|
||||||
|
fit="cover"
|
||||||
|
:width="120"
|
||||||
|
:height="120"
|
||||||
|
lazy
|
||||||
|
/>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
:type="data.imageLock ? 'error' : 'primary'"
|
||||||
|
style="font-size: 24px; position: absolute; left: -12px; top: -5px"
|
||||||
|
@click="ModifyLock"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<LockClosed v-if="data.imageLock" />
|
||||||
|
<LockOpen v-else />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
type="info"
|
||||||
|
style="font-size: 24px; position: absolute; left: 8px; top: -5px"
|
||||||
|
@click="DownloadImage"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<Download />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<n-divider vertical style="height: 100%" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<n-image-group>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
height: 122px;
|
||||||
|
overflow: auto;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<n-image
|
||||||
|
subImage="true"
|
||||||
|
class="g-image-class"
|
||||||
|
draggable="true"
|
||||||
|
:width="56"
|
||||||
|
style="margin: 1px"
|
||||||
|
v-for="(image, index) in data.subImagePath"
|
||||||
|
:key="image.id"
|
||||||
|
:src="image"
|
||||||
|
alt="图片描述"
|
||||||
|
lazy
|
||||||
|
>
|
||||||
|
</n-image>
|
||||||
|
</div>
|
||||||
|
</n-image-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useDialog,
|
||||||
|
NImageGroup,
|
||||||
|
NDivider,
|
||||||
|
NIcon,
|
||||||
|
NButton,
|
||||||
|
NPopover,
|
||||||
|
NTag,
|
||||||
|
useMessage
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { LockClosed, LockOpen, Download } from '@vicons/ionicons5'
|
||||||
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
|
import { useImageStore } from '../../../../../stores/image'
|
||||||
|
let props = defineProps({
|
||||||
|
initData: undefined,
|
||||||
|
index: undefined
|
||||||
|
})
|
||||||
|
let imageStore = useImageStore()
|
||||||
|
let message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
|
let data = ref(props.initData)
|
||||||
|
let images = ref(props.initData.subImagePath)
|
||||||
|
let outImagePath = ref(props.initData.outImagePath)
|
||||||
|
let width = ref(null)
|
||||||
|
let dragTarget = null
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
|
||||||
|
// 监听 props.initData.subImagePath 修改
|
||||||
|
watch(
|
||||||
|
() => props.initData.subImagePath,
|
||||||
|
(value) => {
|
||||||
|
images.value = value
|
||||||
|
width.value = 170 / 3
|
||||||
|
setNodeAttribute()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听 props.initData.outImagePath 修改
|
||||||
|
watch(
|
||||||
|
() => props.initData.outImagePath,
|
||||||
|
(value) => {
|
||||||
|
outImagePath.value = value + `?t=${new Date().getTime()}`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听 props.initData 修改
|
||||||
|
watch(
|
||||||
|
() => props.initData,
|
||||||
|
(value) => {
|
||||||
|
data.value = value
|
||||||
|
setNodeAttribute()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
setNodeAttribute()
|
||||||
|
outImagePath.value = outImagePath.value + `?t=${new Date().getTime()}`
|
||||||
|
})
|
||||||
|
|
||||||
|
async function setNodeAttribute() {
|
||||||
|
let ele = document.querySelectorAll('.g-image-class')
|
||||||
|
ele.forEach((item) => {
|
||||||
|
item.setAttribute('data-id', data.value.id)
|
||||||
|
Array.from(item.getElementsByTagName('img')).forEach((img) => {
|
||||||
|
img.setAttribute('data-id', data.value.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let mainImage = document.querySelectorAll('.generate-image-show')
|
||||||
|
mainImage.forEach((item) => {
|
||||||
|
item.setAttribute('mainImage', '1')
|
||||||
|
Array.from(item.getElementsByTagName('img')).forEach((img) => {
|
||||||
|
img.setAttribute('mainImage', '1')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片拖拽开始事件
|
||||||
|
async function imageDragStart(e) {
|
||||||
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
|
console.log('move', e.target)
|
||||||
|
dragTarget = e.target
|
||||||
|
imageStore.SetDragTarget(e.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片拖拽结束事件
|
||||||
|
async function imageDragDrop(e) {
|
||||||
|
console.log('end', e.target, dragTarget)
|
||||||
|
// 判断原始数据是不是为空
|
||||||
|
// if (dragTarget == null) {
|
||||||
|
// message.error('只能拖拽到当前行的图片上')
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// 判断结束位置是不是主图片
|
||||||
|
if (e.target.getAttribute('mainImage') != '1') {
|
||||||
|
message.error('图片只能拖拽到主图片上')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let source_img = imageStore.GetDragTarget.src
|
||||||
|
.split('?')[0]
|
||||||
|
.replace(/^file:\/\/\//, '')
|
||||||
|
.replace(/^\//, '')
|
||||||
|
let target_img = e.target.src
|
||||||
|
.split('?')[0]
|
||||||
|
.replace(/^file:\/\/\//, '')
|
||||||
|
.replace(/^\//, '')
|
||||||
|
// 修改主图片
|
||||||
|
await window.api.DownloadImageFile([source_img, 'replace', target_img], (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.value.outImagePath =
|
||||||
|
e.target.src.split('?')[0].replaceAll('\\', '/') + '?time=' + new Date().getTime()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片拖拽进入事件
|
||||||
|
async function imageDragOver(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ModifyLock() {
|
||||||
|
// 锁定之前,判断是不是有
|
||||||
|
if (!outImagePath.value) {
|
||||||
|
message.error('没有生成图片,不能锁定')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let lock = !data.value.imageLock
|
||||||
|
// 修改数据库数据
|
||||||
|
let res = await window.db.UpdateBookTaskDetailData(data.value.id, {
|
||||||
|
imageLock: lock
|
||||||
|
})
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('图片锁定/解锁成功')
|
||||||
|
reverseManageStore.selectBookTaskDetail[props.index].imageLock = data.value.imageLock
|
||||||
|
data.value.imageLock = lock
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载对应的分镜图片
|
||||||
|
*/
|
||||||
|
async function DownloadImage() {
|
||||||
|
// 目前只能判断是不是有mj_message
|
||||||
|
dialog.warning({
|
||||||
|
title: '下载图片警告',
|
||||||
|
content: '单个图片的下载,只支持 MJ API 生图,当前有图片的话会被覆盖掉,是否继续?',
|
||||||
|
positiveText: '继续',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
if (data.value.mj_message) {
|
||||||
|
debugger
|
||||||
|
// 加判断
|
||||||
|
// 只要状态不是success 和 error ,其他的都重新获取
|
||||||
|
if (data.value.mj_message.status == 'error') {
|
||||||
|
message.error('失败状态不能采集图片')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isEmpty(data.value.mj_message.message_id)) {
|
||||||
|
message.error('没有消息ID,不能采集图片')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window.mj.GetGeneratedMJImageAndSplit(JSON.stringify([toRaw(data.value)]), (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 修改数据
|
||||||
|
for (let i = 0; i < value.data.length; i++) {
|
||||||
|
const element = value.data[i]
|
||||||
|
// 修改对应的数据
|
||||||
|
data.value.outImagePath =
|
||||||
|
'file://' +
|
||||||
|
element.outImagePath.replaceAll('\\', '/') +
|
||||||
|
'?time=' +
|
||||||
|
new Date().getTime()
|
||||||
|
|
||||||
|
data.value.subImagePath = element.subImagePath.map(
|
||||||
|
(item) => 'file://' + item.replaceAll('\\', '/') + '?time=' + new Date().getTime()
|
||||||
|
)
|
||||||
|
data.value.mj_message.image_click = element.result
|
||||||
|
data.value.mj_message.image_path = element.image_path
|
||||||
|
data.value.mj_message.progress = 100
|
||||||
|
data.value.mj_message.status = 'success'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (data.value.mjMessage) {
|
||||||
|
message.error('暂时不支持')
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
message.error('没有生图数据')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -159,11 +159,12 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 处理批次的翻译
|
// 处理批次的翻译
|
||||||
function TranslateBatchParams(from, to) {
|
function TranslateBatchParams(from, to) {
|
||||||
|
debugger
|
||||||
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]
|
||||||
// 这边判断GPT提示词是不是存在,存在的话翻译GPT提示词
|
// 这边判断GPT提示词是不是存在,存在的话翻译GPT提示词
|
||||||
if (!isEmpty(data.value.gptPrompt)) {
|
if (!isEmpty(element.gptPrompt)) {
|
||||||
translateData.push({
|
translateData.push({
|
||||||
text: element.gptPrompt,
|
text: element.gptPrompt,
|
||||||
from: from,
|
from: from,
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<div style="display: flex">
|
||||||
|
<span>出图</span>
|
||||||
|
<n-select
|
||||||
|
style="width: 100px; margin-left: 5px"
|
||||||
|
size="tiny"
|
||||||
|
:options="image_options"
|
||||||
|
@update:value="UpdateImageGenerateCategory"
|
||||||
|
v-model:value="reverseManageStore.selectBookTask.imageCategory"
|
||||||
|
placeholder="选择生图模式"
|
||||||
|
></n-select>
|
||||||
|
<n-button
|
||||||
|
v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'"
|
||||||
|
color="#7c461e"
|
||||||
|
size="tiny"
|
||||||
|
style="margin-left: 5px"
|
||||||
|
@click="MJGetImage"
|
||||||
|
>MJ采集图片</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'"
|
||||||
|
color="#e18a3b"
|
||||||
|
size="tiny"
|
||||||
|
style="margin-left: 5px"
|
||||||
|
@click="OneSplitFour"
|
||||||
|
>1拆4</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { NSelect, NButton, useMessage } from 'naive-ui'
|
||||||
|
import { useSoftwareStore } from '../../../../../stores/software'
|
||||||
|
import { useReverseManageStore } from '../../../../../stores/reverseManage'
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
let message = useMessage()
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
let image_options = ref([])
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 获取生图下拉列表的方式
|
||||||
|
await window.api.GetImageGenerateCategory((value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
image_options.value = value.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function UpdateImageGenerateCategory(value, options) {
|
||||||
|
// 调用下保存
|
||||||
|
let res = await window.db.UpdateBookTaskData(reverseManageStore.selectBookTask.id, {
|
||||||
|
imageCategory: value
|
||||||
|
})
|
||||||
|
window.api.showGlobalMessage(res)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -95,7 +95,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 选择风格
|
// 选择风格
|
||||||
async function SelectStyle() {
|
async function SelectStyle() {
|
||||||
debugger
|
|
||||||
// 先获取风格
|
// 先获取风格
|
||||||
// 判断当前数据是不是存在
|
// 判断当前数据是不是存在
|
||||||
// 处理数据。获取当前的所有的数据
|
// 处理数据。获取当前的所有的数据
|
||||||
|
|||||||
@ -0,0 +1,303 @@
|
|||||||
|
<template>
|
||||||
|
<div style="margin-top: 30px">
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<n-button color="#b6a014" size="small" @click="formateWrite">一键格式化</n-button>
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button quaternary circle size="tiny" color="#b6a014" @click="AddSplitChar">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon size="25"> <AddCircleOutline /> </n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<span>添加分割标识符</span>
|
||||||
|
</n-popover>
|
||||||
|
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-input-number
|
||||||
|
style="margin-left: 10px; width: 100px"
|
||||||
|
size="small"
|
||||||
|
placeholder="输入合并的行数"
|
||||||
|
:max="10000"
|
||||||
|
:min="1"
|
||||||
|
@update:value="mergeCountChange"
|
||||||
|
:show-button="false"
|
||||||
|
v-model:value="write_setting.merge_count"
|
||||||
|
></n-input-number>
|
||||||
|
</template>
|
||||||
|
<span>设置将多少行进行合并</span>
|
||||||
|
</n-popover>
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-input
|
||||||
|
style="margin-left: 10px; width: 80px"
|
||||||
|
size="small"
|
||||||
|
placeholder="输入中间拼接的字符"
|
||||||
|
@update:value="mergeCountChange"
|
||||||
|
:show-button="false"
|
||||||
|
v-model:value="write_setting.merge_char"
|
||||||
|
></n-input>
|
||||||
|
</template>
|
||||||
|
<span>设置中间拼接的字符</span>
|
||||||
|
</n-popover>
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-input
|
||||||
|
style="margin-left: 10px; width: 80px"
|
||||||
|
size="small"
|
||||||
|
placeholder="输入结尾拼接的字符"
|
||||||
|
@update:value="mergeCountChange"
|
||||||
|
:show-button="false"
|
||||||
|
v-model:value="write_setting.end_char"
|
||||||
|
></n-input>
|
||||||
|
</template>
|
||||||
|
<span>设置结尾拼接的字符</span>
|
||||||
|
</n-popover>
|
||||||
|
|
||||||
|
<n-button color="#80a492" size="small" style="margin-left: 10px" @click="mergeWord"
|
||||||
|
>合并</n-button
|
||||||
|
>
|
||||||
|
<n-button color="#f3a694" size="small" style="margin-left: 10px" @click="CopyWord"
|
||||||
|
>一键复制内容</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<n-input
|
||||||
|
style="margin-top: 5px"
|
||||||
|
v-model:value="word"
|
||||||
|
:autosize="{ minRows: 30, maxRows: 30 }"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="输入分镜文案"
|
||||||
|
@update:value="ChangeWordInput"
|
||||||
|
/>
|
||||||
|
<div style="margin-top: 5px; display: flex">
|
||||||
|
<div style="flex: 1">共 {{ rowCount }} 行分镜(当前数量不是最后数量,最后会删除空行)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NIcon,
|
||||||
|
NPopover,
|
||||||
|
NInputNumber
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { AddCircleOutline } from '@vicons/ionicons5'
|
||||||
|
import InputDialogContent from '../../../Original/Components/InputDialogContent.vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage,
|
||||||
|
NButton,
|
||||||
|
NInput,
|
||||||
|
NInputNumber,
|
||||||
|
NIcon,
|
||||||
|
AddCircleOutline,
|
||||||
|
NPopover
|
||||||
|
},
|
||||||
|
props: ['initData'],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
|
let rowCount = ref(0)
|
||||||
|
let data = ref(props.initData)
|
||||||
|
let word = ref(null)
|
||||||
|
let word_arr = ref([])
|
||||||
|
let split_ref = ref(null)
|
||||||
|
|
||||||
|
let write_setting = ref({
|
||||||
|
split_char: '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;',
|
||||||
|
merge_count: 3,
|
||||||
|
merge_char: ',',
|
||||||
|
end_char: '。'
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 拼接word
|
||||||
|
let tmp_arr = []
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
const item = data.value[i]
|
||||||
|
tmp_arr.push(item.after_gpt)
|
||||||
|
}
|
||||||
|
word.value = tmp_arr.join('\n')
|
||||||
|
ChangeWordInput()
|
||||||
|
|
||||||
|
// 加载初始配置数据
|
||||||
|
await window.api.GetDefineConfigJsonByProperty(
|
||||||
|
JSON.stringify(['clip_setting', 'write_setting', false, null]),
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value.data) {
|
||||||
|
write_setting.value = value.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改数据框时触发的事件
|
||||||
|
*/
|
||||||
|
async function ChangeWordInput() {
|
||||||
|
let word_arr = word.value.split('\n')
|
||||||
|
// 先判断是不是有空行
|
||||||
|
if (rowCount.value == 1 && word_arr[0] == '') {
|
||||||
|
rowCount.value = 0
|
||||||
|
} else {
|
||||||
|
rowCount.value = word_arr.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加分割符号
|
||||||
|
*/
|
||||||
|
async function AddSplitChar() {
|
||||||
|
// 判断当前数据是不是存在
|
||||||
|
// 处理数据。获取当前的所有的数据
|
||||||
|
let dialogWidth = 400
|
||||||
|
let dialogHeight = 150
|
||||||
|
dialog.create({
|
||||||
|
title: '添加分割符',
|
||||||
|
showIcon: false,
|
||||||
|
closeOnEsc: false,
|
||||||
|
content: () =>
|
||||||
|
h(InputDialogContent, {
|
||||||
|
ref: split_ref,
|
||||||
|
initData: write_setting.value.split_char,
|
||||||
|
placeholder: '请输入分割符'
|
||||||
|
}),
|
||||||
|
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
||||||
|
maskClosable: false,
|
||||||
|
onClose: async () => {
|
||||||
|
write_setting.value.split_char = split_ref.value.data
|
||||||
|
// 保存数据
|
||||||
|
await window.api.SaveDefineConfigJsonByProperty(
|
||||||
|
JSON.stringify(['clip_setting', 'write_setting', toRaw(write_setting.value), false]),
|
||||||
|
(value) => {
|
||||||
|
console.log(value)
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新input-number事件
|
||||||
|
*/
|
||||||
|
let timer = null
|
||||||
|
async function mergeCountChange(value) {
|
||||||
|
// 添加一个防抖函数,防止修改次数太多导致卡顿
|
||||||
|
clearTimeout(timer)
|
||||||
|
timer = setTimeout(async () => {
|
||||||
|
// 执行你的逻辑代码
|
||||||
|
//
|
||||||
|
await window.api.SaveDefineConfigJsonByProperty(
|
||||||
|
JSON.stringify(['clip_setting', 'write_setting', toRaw(write_setting.value), false]),
|
||||||
|
(value) => {
|
||||||
|
console.log(value)
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键格式化
|
||||||
|
*/
|
||||||
|
async function formateWrite() {
|
||||||
|
let split_arr = Array.from(write_setting.value.split_char)
|
||||||
|
split_arr.forEach((item) => {
|
||||||
|
let specialCharacters = [
|
||||||
|
'.',
|
||||||
|
'*',
|
||||||
|
'?',
|
||||||
|
'+',
|
||||||
|
'^',
|
||||||
|
'$',
|
||||||
|
'[',
|
||||||
|
']',
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'{',
|
||||||
|
'}',
|
||||||
|
'|',
|
||||||
|
'\\'
|
||||||
|
]
|
||||||
|
let regex
|
||||||
|
|
||||||
|
if (specialCharacters.includes(item)) {
|
||||||
|
regex = new RegExp('\\' + item, 'g')
|
||||||
|
} else {
|
||||||
|
regex = new RegExp(item, 'g')
|
||||||
|
}
|
||||||
|
word.value = word.value.replace(regex, '\n')
|
||||||
|
})
|
||||||
|
// 删除空行
|
||||||
|
let word_arr = word.value.split('\n')
|
||||||
|
word_arr = word_arr.filter((item) => item != '' && item != null)
|
||||||
|
word.value = word_arr.join('\n')
|
||||||
|
ChangeWordInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并数据
|
||||||
|
*/
|
||||||
|
async function mergeWord() {
|
||||||
|
let step = write_setting.value.merge_count ? write_setting.value.merge_count : 3
|
||||||
|
let tmp_arr = []
|
||||||
|
let word_arr = word.value.split('\n')
|
||||||
|
for (let i = 0; i < word_arr.length; i += step) {
|
||||||
|
let group = word_arr.slice(i, i + step)
|
||||||
|
tmp_arr.push(group.join(write_setting.value.merge_char) + write_setting.value.end_char)
|
||||||
|
}
|
||||||
|
word.value = tmp_arr.join('\n')
|
||||||
|
ChangeWordInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制数据到剪贴板
|
||||||
|
*/
|
||||||
|
async function CopyWord() {
|
||||||
|
// 获取当前的所有的word
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(word.value)
|
||||||
|
message.success('复制成功')
|
||||||
|
} catch (error) {
|
||||||
|
message.error('复制失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
rowCount,
|
||||||
|
ChangeWordInput,
|
||||||
|
word,
|
||||||
|
word_arr,
|
||||||
|
AddSplitChar,
|
||||||
|
split_ref,
|
||||||
|
write_setting,
|
||||||
|
mergeCountChange,
|
||||||
|
formateWrite,
|
||||||
|
mergeWord,
|
||||||
|
CopyWord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,718 @@
|
|||||||
|
<template>
|
||||||
|
<div id="import_word_and_srt">
|
||||||
|
<div style="height: 30px; margin-bottom: 5px">
|
||||||
|
<n-button
|
||||||
|
v-if="type == 'original' || type == 'new_original'"
|
||||||
|
color="#1e90ff"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 20px"
|
||||||
|
@click="OpenOneDialog"
|
||||||
|
>导入字幕</n-button
|
||||||
|
>
|
||||||
|
<n-button color="#1e90ff" size="small" style="margin-left: 20px" @click="ImportSrtAndGetTime"
|
||||||
|
>导入srt</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
color="#1e90ff"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 20px"
|
||||||
|
@click="SaveCopywritingInformation"
|
||||||
|
>保存文案信息</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<n-data-table
|
||||||
|
:max-height="maxHeight"
|
||||||
|
:row-key="rowKey"
|
||||||
|
:columns="columns"
|
||||||
|
:data="data"
|
||||||
|
:pagination="false"
|
||||||
|
:bordered="false"
|
||||||
|
@update:checked-row-keys="handleCheck"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { h, defineComponent, onMounted, ref, toRaw, watch, onUnmounted } from 'vue'
|
||||||
|
import { NButton, NDataTable, useMessage, NInput, NImage, useDialog } from 'naive-ui'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import EditWord from './EditWord.vue'
|
||||||
|
import { checkStringValueDeleteSuffix } from '../../../../../../main/Public/generalTools'
|
||||||
|
import { useReverseManageStore } from '../../../../../../stores/reverseManage'
|
||||||
|
import InputDialogContent from '../../../Original/Components/InputDialogContent.vue'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
import { OperateBookType } from '../../../../../../define/enum/bookEnum'
|
||||||
|
const buttonArr = [
|
||||||
|
{
|
||||||
|
title: '下对齐',
|
||||||
|
key: 'AlignNextWord',
|
||||||
|
color: '#8a2be0'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NButton,
|
||||||
|
NDataTable,
|
||||||
|
NInput,
|
||||||
|
NImage
|
||||||
|
},
|
||||||
|
props: ['initData', 'menuType', 'height', 'type'],
|
||||||
|
setup(props) {
|
||||||
|
let hh = props.height
|
||||||
|
let maxHeight = props.height - 80
|
||||||
|
debugger
|
||||||
|
let data = ref(JSON.parse(JSON.stringify(props.initData)))
|
||||||
|
const message = useMessage()
|
||||||
|
let dialog = useDialog()
|
||||||
|
let selectKey = ref([])
|
||||||
|
let editWordRef = ref(null)
|
||||||
|
let wenkeRef = ref(null)
|
||||||
|
let type = ref(props.type ? props.type : 'original')
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
|
||||||
|
const createColumns = ({ AlignNextWord }) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'selection',
|
||||||
|
disabled(row) {
|
||||||
|
return row.name === 'Edward King 3'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '编号',
|
||||||
|
key: 'no',
|
||||||
|
width: 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分镜文案',
|
||||||
|
key: 'after_gpt',
|
||||||
|
width: 300,
|
||||||
|
render(row, index) {
|
||||||
|
return h(NInput, {
|
||||||
|
value: row.word,
|
||||||
|
type: 'textarea',
|
||||||
|
autosize: true,
|
||||||
|
onUpdateValue(v) {
|
||||||
|
data.value[index].word = v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '字幕',
|
||||||
|
key: 'srt',
|
||||||
|
width: '300',
|
||||||
|
render(row) {
|
||||||
|
let tmp = row.subValue.map((item) =>
|
||||||
|
h('div', { style: 'display:flex; height : auto; margin: 2px 0' }, [
|
||||||
|
h(NInput, {
|
||||||
|
size: 'tiny',
|
||||||
|
value: item.srt_value
|
||||||
|
}),
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
style: 'margin : 0 2px',
|
||||||
|
size: 'tiny',
|
||||||
|
color: '#ecd452',
|
||||||
|
onClick: () => Upper(row, item, true)
|
||||||
|
},
|
||||||
|
{ default: () => '向上' }
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
style: 'margin : 0 2px',
|
||||||
|
size: 'tiny',
|
||||||
|
color: '#ee7959',
|
||||||
|
onClick: () => Down(row, item)
|
||||||
|
},
|
||||||
|
{ default: () => '向下' }
|
||||||
|
)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'options',
|
||||||
|
width: 130,
|
||||||
|
render(row) {
|
||||||
|
const btn = buttonArr.map((item) => {
|
||||||
|
return h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
style: 'margin : 2px',
|
||||||
|
strong: true,
|
||||||
|
size: 'tiny',
|
||||||
|
color: item.color,
|
||||||
|
onClick: () => {
|
||||||
|
if (item.key == 'AlignNextWord') {
|
||||||
|
AlignNextWord(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => item.title
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return btn
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '时间范围',
|
||||||
|
key: 'timeLimit',
|
||||||
|
width: 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置窗体的高度
|
||||||
|
function setHeight() {
|
||||||
|
let div = document.getElementById('import_word_and_srt')
|
||||||
|
div.style.height = hh + 'px'
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
setHeight()
|
||||||
|
|
||||||
|
// 监听 ctrl + alt + w 键盘的按键事件
|
||||||
|
window.addEventListener('keydown', ImportWenKeSrt)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('keydown', ImportWenKeSrt)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入文刻软件里面的srt
|
||||||
|
*/
|
||||||
|
async function ImportWenKeSrt(e) {
|
||||||
|
if (!(e.ctrlKey && e.altKey && e.key == 'k')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let dialogWidth = 400
|
||||||
|
let dialogHeight = 150
|
||||||
|
dialog.create({
|
||||||
|
name: 'importWenkeWord',
|
||||||
|
title: '导入外部对齐文件',
|
||||||
|
showIcon: false,
|
||||||
|
closeOnEsc: false,
|
||||||
|
content: () =>
|
||||||
|
h(InputDialogContent, {
|
||||||
|
ref: wenkeRef,
|
||||||
|
initData: null,
|
||||||
|
placeholder: '请导入外部对齐文件'
|
||||||
|
}),
|
||||||
|
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
||||||
|
maskClosable: false,
|
||||||
|
onClose: async () => {
|
||||||
|
debugger
|
||||||
|
console.log(wenkeRef.value.word)
|
||||||
|
let word = wenkeRef.value.data
|
||||||
|
if (word == null || word == '') {
|
||||||
|
message.error('数据为空')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
word = JSON.parse(word)
|
||||||
|
// 将文案数据写入到本地
|
||||||
|
data.value = []
|
||||||
|
let word_arr = word.rows
|
||||||
|
let lastId = ''
|
||||||
|
let end_word = []
|
||||||
|
for (let i = 0; i < word_arr.length; i++) {
|
||||||
|
const element = word_arr[i]
|
||||||
|
// 判断下面的text是不是存在,存在的话,获取数据然后记录事件
|
||||||
|
let row_text = ''
|
||||||
|
let start_time = 0
|
||||||
|
let end_time = 0
|
||||||
|
let subValue = []
|
||||||
|
if (element.texts) {
|
||||||
|
for (let j = 0; j < element.texts.length; j++) {
|
||||||
|
const text = element.texts[j]
|
||||||
|
row_text += text.text + ','
|
||||||
|
if (j == 0) {
|
||||||
|
start_time = text.start
|
||||||
|
}
|
||||||
|
if (j == element.texts.length - 1) {
|
||||||
|
end_time = text.start + text.duration
|
||||||
|
}
|
||||||
|
subValue.push({
|
||||||
|
id: uuidv4(),
|
||||||
|
srt_value: text.text,
|
||||||
|
start_time: text.start / 1000,
|
||||||
|
end_time: text.start / 1000 + text.duration / 1000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let id = uuidv4()
|
||||||
|
lastId = id
|
||||||
|
|
||||||
|
data.value.push({
|
||||||
|
no: i + 1,
|
||||||
|
id: id,
|
||||||
|
lastId: lastId,
|
||||||
|
word: checkStringValueDeleteSuffix(row_text, ','),
|
||||||
|
after_gpt: checkStringValueDeleteSuffix(row_text, ','),
|
||||||
|
start_time: start_time / 1000,
|
||||||
|
end_time: end_time / 1000,
|
||||||
|
timeLimit: `${start_time / 1000} -- ${end_time / 1000}`,
|
||||||
|
subValue: subValue
|
||||||
|
})
|
||||||
|
end_word.push(checkStringValueDeleteSuffix(row_text, ','))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将文案数据写入到本地
|
||||||
|
let local_word = end_word.filter((item) => item != '' && item != null)
|
||||||
|
await window.api.saveWordTxt(toRaw(local_word), (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error('文案写入失败' + value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新计算指定索引值的时间
|
||||||
|
* @param {int} index
|
||||||
|
*/
|
||||||
|
function modifyTime(index) {
|
||||||
|
// 判断下一个行或者是上一行是不是存在,存在才会计算时间
|
||||||
|
if (data.value[index]) {
|
||||||
|
let s_v = data.value[index].subValue
|
||||||
|
let len = s_v.length
|
||||||
|
if (len > 0) {
|
||||||
|
let s_t = s_v[0].start_time
|
||||||
|
let e_t = s_v[len - 1].end_time
|
||||||
|
data.value[index].start_time = s_t
|
||||||
|
data.value[index].end_time = e_t
|
||||||
|
data.value[index].timeLimit = `${s_t} -- ${e_t}`
|
||||||
|
} else {
|
||||||
|
data.value[index].start_time = null
|
||||||
|
data.value[index].end_time = null
|
||||||
|
data.value[index].timeLimit = ``
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前行的子数据的长度是不是大于0。不大于0 的话下面的字幕往上替补
|
||||||
|
* @param {data value 的索引} index
|
||||||
|
*/
|
||||||
|
function moveUp(index) {
|
||||||
|
let s_v = data.value[index].subValue
|
||||||
|
if (s_v.length == 0) {
|
||||||
|
// 将下面所有的字幕数据往上移动
|
||||||
|
for (let i = index; i < data.value.length; i++) {
|
||||||
|
// const element = data.value[i];
|
||||||
|
if (data.value[i + 1] != null) {
|
||||||
|
data.value[i].subValue = data.value[i + 1].subValue
|
||||||
|
} else {
|
||||||
|
// 检查当前这个是不是为空。为空直接删除
|
||||||
|
// 判断当前行的文案、洗稿后文件、以及字幕是不是还有。(没有的话直接删除)
|
||||||
|
if (
|
||||||
|
data.value[i].word == null ||
|
||||||
|
data.value[i].word == '' ||
|
||||||
|
data.value[i].after_gpt == null ||
|
||||||
|
data.value[i].after_gpt == ''
|
||||||
|
) {
|
||||||
|
// 直接删除
|
||||||
|
data.value.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字幕文件向上
|
||||||
|
*/
|
||||||
|
async function Upper(row, item, isM) {
|
||||||
|
// 向上合并。
|
||||||
|
// 当前item。向上的话。判断是不是第一个。是第一个的话。直接网上一个合并。
|
||||||
|
// 不是第一个的话。将上面的所有的合并。
|
||||||
|
// 若是当前只有一个。判断当前文案和洗稿后文件是不是存在。存在不删除。没有的话直接删除。
|
||||||
|
// 向下合并。逻辑相同。
|
||||||
|
if (row.lastId == null || row.lastId == '') {
|
||||||
|
message.error('当前是第一个。不能向上合并')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//判断当前行是不是第一个
|
||||||
|
let itemId = item.id
|
||||||
|
let itemIndex = row.subValue.findIndex((item) => item.id == itemId)
|
||||||
|
let thisIndex = data.value.findIndex((item) => item.id == row.id)
|
||||||
|
if (itemIndex < 0 && isM) {
|
||||||
|
message.error('数据错误')
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// 先获取上一行的数据
|
||||||
|
let lastRowIndex = data.value.findIndex((item) => item.id == row.lastId)
|
||||||
|
//将当前及之前的数据向上合并
|
||||||
|
for (let i = 0; i <= itemIndex; i++) {
|
||||||
|
const element = row.subValue[i]
|
||||||
|
data.value[lastRowIndex].subValue.push(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除指定的数据
|
||||||
|
data.value[lastRowIndex + 1].subValue.splice(0, itemIndex + 1)
|
||||||
|
moveUp(thisIndex)
|
||||||
|
|
||||||
|
// 判断当前行的文案和洗稿后文件是不是还有。(没有的话直接删除)
|
||||||
|
if (
|
||||||
|
data.value[thisIndex] &&
|
||||||
|
data.value[thisIndex].subValue == null &&
|
||||||
|
(row.word == null || row.word == '' || row.after_gpt == null || row.after_gpt == '')
|
||||||
|
) {
|
||||||
|
// 先调整lastId (判断下一行是不是存在。存在的话修改lastId为当前的lastId)
|
||||||
|
if (data.value[thisIndex + 1] != null) {
|
||||||
|
data.value[thisIndex + 1].lastId = row.lastId
|
||||||
|
}
|
||||||
|
// 直接删除
|
||||||
|
data.value.splice(thisIndex, 1)
|
||||||
|
// 调整下面的所有的编号
|
||||||
|
for (let i = thisIndex; i < data.value.length; i++) {
|
||||||
|
data.value[i].no = data.value[i].no - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 合并之后重新计算时间(计算上一个和当前的)
|
||||||
|
modifyTime(lastRowIndex)
|
||||||
|
modifyTime(thisIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字幕文件向下
|
||||||
|
*/
|
||||||
|
async function Down(row, item) {
|
||||||
|
// 向下合并。逻辑相同。
|
||||||
|
// 当前item。。判断是不是最后一个。是最后一个的话。直接向下合并。
|
||||||
|
// 不是第一个的话。将下面的所有的合并。
|
||||||
|
// 若是当前只有一个。判断当前文案和洗稿后文件是不是存在。存在不删除。没有的话直接删除。
|
||||||
|
//判断当前行是不是第一个
|
||||||
|
let itemId = item.id
|
||||||
|
let itemIndex = row.subValue.findIndex((item) => item.id == itemId)
|
||||||
|
let thisIndex = data.value.findIndex((item) => item.id == row.id)
|
||||||
|
// 判断下一个是不是存在
|
||||||
|
if (data.value[thisIndex + 1] == null) {
|
||||||
|
message.error('当前已经是最后一个。不能向下合并')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemIndex < 0) {
|
||||||
|
message.error('数据错误')
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// 获取下一行数据
|
||||||
|
let nextRowIndex = data.value.findIndex((item) => item.lastId == row.id)
|
||||||
|
|
||||||
|
//将当前以及下面的所有进行合并
|
||||||
|
for (let i = row.subValue.length - 1; i >= itemIndex; i--) {
|
||||||
|
const element = row.subValue[i]
|
||||||
|
data.value[nextRowIndex].subValue.unshift(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除指定的数据
|
||||||
|
data.value[thisIndex].subValue.splice(itemIndex)
|
||||||
|
|
||||||
|
// 判断该当前字幕是不是为空(为空的话。下面的往上移动)
|
||||||
|
moveUp(thisIndex)
|
||||||
|
|
||||||
|
// 判断当前行的文案、洗稿后文件、以及字幕是不是还有。(没有的话直接删除)
|
||||||
|
if (
|
||||||
|
data.value[thisIndex].subValue == null &&
|
||||||
|
(row.word == null || row.word == '' || row.after_gpt == null || row.after_gpt == '')
|
||||||
|
) {
|
||||||
|
// 先调整lastId (判断下一行是不是存在。存在的话修改lastId为当前的lastId)
|
||||||
|
if (data.value[nextRowIndex] != null) {
|
||||||
|
data.value[nextRowIndex].lastId = row.lastId
|
||||||
|
}
|
||||||
|
// 直接删除
|
||||||
|
data.value.splice(thisIndex, 1)
|
||||||
|
// 调整下面的所有的编号
|
||||||
|
for (let i = thisIndex; i < data.value.length; i++) {
|
||||||
|
data.value[i].no = data.value[i].no - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 合并之后重新计算时间(计算上一个和当前的)
|
||||||
|
modifyTime(nextRowIndex)
|
||||||
|
modifyTime(thisIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePunctuationIncludingEllipsis(sentence) {
|
||||||
|
// 扩展正则表达式以包含中文标点符号和省略号
|
||||||
|
// 注意英文省略号可能由三个连续点表示,也可能直接使用特殊的省略号字符
|
||||||
|
const punctuationRegExp = /[., \/#!$%\^&\*;:{}=\-_`~()\[\],。、;:?!‘’“”()【】《》…]+/g
|
||||||
|
|
||||||
|
// 使用正则表达式的replace方法替换掉所有匹配到的标点符号为空字符串
|
||||||
|
return sentence.replace(punctuationRegExp, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对齐当前列即下面的数据
|
||||||
|
*/
|
||||||
|
async function AlignNextWord(row) {
|
||||||
|
// 判断是不是已经到到导入过字幕了
|
||||||
|
dialog.create({
|
||||||
|
type: 'warning',
|
||||||
|
title: '警告',
|
||||||
|
showIcon: true,
|
||||||
|
content: '会自动对齐下面的数据。没有对齐成功就要手动调整在自动对齐',
|
||||||
|
style: `width : 400px;`,
|
||||||
|
maskClosable: false,
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
// 下对齐
|
||||||
|
let itemId = row.id
|
||||||
|
let thisIndex = data.value.findIndex((item) => item.id == itemId)
|
||||||
|
if (thisIndex < 0) {
|
||||||
|
message.error('数据错误')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let nextSrt = []
|
||||||
|
// 先将当前行下面的所有的数据拿出来
|
||||||
|
for (let i = thisIndex; i < data.value.length; i++) {
|
||||||
|
const element = data.value[i]
|
||||||
|
nextSrt = nextSrt.concat(element.subValue)
|
||||||
|
}
|
||||||
|
let init_num = thisIndex
|
||||||
|
// let data
|
||||||
|
let tmp_str = ''
|
||||||
|
for (let i = 0; i < nextSrt.length; ) {
|
||||||
|
const element = nextSrt[i]
|
||||||
|
let current_text = `第 ${thisIndex + 1} 数据。字幕:${
|
||||||
|
element.srt_value
|
||||||
|
}与文案不匹配。亲检查上下文。`
|
||||||
|
tmp_str += element.srt_value
|
||||||
|
|
||||||
|
if (
|
||||||
|
removePunctuationIncludingEllipsis(data.value[thisIndex].after_gpt).startsWith(
|
||||||
|
removePunctuationIncludingEllipsis(tmp_str)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// data.value[thisIndex].subValue.push(element);
|
||||||
|
if (init_num < thisIndex || i > 0) {
|
||||||
|
Upper(data.value[thisIndex + 1], element, false)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
removePunctuationIncludingEllipsis(data.value[thisIndex + 1].after_gpt).startsWith(
|
||||||
|
removePunctuationIncludingEllipsis(element.srt_value)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
thisIndex++
|
||||||
|
tmp_str = ''
|
||||||
|
} else {
|
||||||
|
window.api.showGlobalMessageDialog({
|
||||||
|
code: 0,
|
||||||
|
message: current_text
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存字幕文案信息,用于自动生成视频
|
||||||
|
*/
|
||||||
|
async function SaveCopywritingInformation() {
|
||||||
|
if (type.value == 'original') {
|
||||||
|
if (props.menuType == 'mj') {
|
||||||
|
await window.mj.SvaeMJWordSrt([toRaw(data.value), 'srt_time_information'], (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('保存成功')
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// 先保存单个文件(然后在config文件中指向对应的文件)
|
||||||
|
await window.api.OriginalAddWebuiJson(JSON.stringify(data.value), async (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value.data) {
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
let name = String(data.value[i].no).padStart(5, '0')
|
||||||
|
data.value[i].prompt_json = value.data + '/' + name + '.png.json'
|
||||||
|
data.value[i].name = name + '.png'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await window.api.SaveCopywritingInformation(
|
||||||
|
[toRaw(data.value), 'srt_time_information'],
|
||||||
|
(value) => {
|
||||||
|
if (value.code != 1) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success('保存成功')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (type.value == 'mj_reverse' || type.value == 'sd_reverse') {
|
||||||
|
debugger
|
||||||
|
if (data.value.length != reverseManageStore.selectBookTaskDetail.length) {
|
||||||
|
message.error('检测到导入的字幕数据和分镜对不上,请先对齐')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 将对齐后的数据写入到数据库中
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
const element = data.value[i]
|
||||||
|
let res = await window.db.UpdateBookTaskDetailData(element.id, {
|
||||||
|
startTime: element.start_time,
|
||||||
|
endTime: element.end_time,
|
||||||
|
timeLimit: element.timeLimit,
|
||||||
|
subValue: JSON.stringify(element.subValue)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (type.value == 'new_original') {
|
||||||
|
// 判断是不是没有对齐(就是所有的数据 文案 时间 srt 都要有,不然就报错)
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
const element = data.value[i]
|
||||||
|
if (
|
||||||
|
isEmpty(element.word) ||
|
||||||
|
isEmpty(element.after_gpt) ||
|
||||||
|
!element.hasOwnProperty('start_time') ||
|
||||||
|
!element.hasOwnProperty('end_time') ||
|
||||||
|
!element.hasOwnProperty('subValue') ||
|
||||||
|
element.subValue.length == 0
|
||||||
|
) {
|
||||||
|
message.error("保存数据失败,数据不完整,请检查'文案'、'时间'、'字幕' 等,数据是否完整")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 开始保存数据(这个要全部保存。会提前判断是不是又分镜信息存在,存在的话就直修改时间,但是需要判断分镜数量是不是对的,不存在的话就会新建分镜数据)后端判断
|
||||||
|
let res = await window.book.SaveCopywriting(
|
||||||
|
reverseManageStore.selectBookTask.id,
|
||||||
|
toRaw(data.value),
|
||||||
|
OperateBookType.BOOKTASK
|
||||||
|
)
|
||||||
|
window.api.showGlobalMessageDialog(res)
|
||||||
|
} else {
|
||||||
|
message.error('未知的小说类型,请检查')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入字幕并进行分镜输出,显示时间,将分镜给他传进去
|
||||||
|
*/
|
||||||
|
async function ImportSrtAndGetTime() {
|
||||||
|
let srt_path = null
|
||||||
|
// 先选择SRT文件
|
||||||
|
await window.api.SelectFile(['srt'], (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srt_path = value.value
|
||||||
|
})
|
||||||
|
|
||||||
|
await window.api.ImportSrtAndGetTime([toRaw(data.value), srt_path], (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 写入时间
|
||||||
|
for (let i = 0; i < value.data.length; i++) {
|
||||||
|
const item = value.data[i]
|
||||||
|
if (i >= data.value.length) {
|
||||||
|
item.no = i + 1
|
||||||
|
item.timeLimit = `${item.start_time} -- ${item.end_time}`
|
||||||
|
data.value.push(item)
|
||||||
|
} else {
|
||||||
|
data.value[i].start_time = item.start_time
|
||||||
|
data.value[i].end_time = item.end_time
|
||||||
|
data.value[i].timeLimit = `${item.start_time} -- ${item.end_time}`
|
||||||
|
data.value[i].subValue = item.subValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开添加字幕信息的窗口
|
||||||
|
*/
|
||||||
|
async function OpenOneDialog() {
|
||||||
|
// 判断当前数据是不是存在
|
||||||
|
// 处理数据。获取当前的所有的数据
|
||||||
|
let dialogWidth = window.innerWidth * 0.7
|
||||||
|
let dialogHeight = window.innerHeight * 0.9
|
||||||
|
// ImportWordAndSrt
|
||||||
|
dialog.create({
|
||||||
|
showIcon: false,
|
||||||
|
closeOnEsc: false,
|
||||||
|
content: () => h(EditWord, { ref: editWordRef, initData: data }),
|
||||||
|
style: `width : ${dialogWidth}px; minHeight : ${dialogHeight}px`,
|
||||||
|
maskClosable: false,
|
||||||
|
positiveText: '保存',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: async () => {
|
||||||
|
data.value = []
|
||||||
|
let word_arr = editWordRef.value.word.split('\n')
|
||||||
|
let lastId = ''
|
||||||
|
for (let i = 0; i < word_arr.length; i++) {
|
||||||
|
const element = word_arr[i]
|
||||||
|
if (element != '' && element != null) {
|
||||||
|
let id = uuidv4()
|
||||||
|
let obj = {
|
||||||
|
no: i + 1,
|
||||||
|
id: id,
|
||||||
|
lastId: lastId,
|
||||||
|
word: element,
|
||||||
|
after_gpt: element,
|
||||||
|
subValue: []
|
||||||
|
}
|
||||||
|
lastId = id
|
||||||
|
data.value.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将文案数据写入到本地
|
||||||
|
let local_word = word_arr.filter((item) => item != '' && item != null)
|
||||||
|
await window.api.saveWordTxt(toRaw(local_word), (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error('文案写入失败' + value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
columns: createColumns({
|
||||||
|
AlignNextWord
|
||||||
|
}),
|
||||||
|
rowKey: (row) => row.id,
|
||||||
|
handleCheck(rowKeys) {
|
||||||
|
selectKey.value = rowKeys
|
||||||
|
},
|
||||||
|
ImportSrtAndGetTime,
|
||||||
|
SaveCopywritingInformation,
|
||||||
|
OpenOneDialog,
|
||||||
|
maxHeight,
|
||||||
|
hh,
|
||||||
|
wenkeRef,
|
||||||
|
type,
|
||||||
|
reverseManageStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -119,6 +119,7 @@ import { useReverseManageStore } from '../../../../../../stores/reverseManage.ts
|
|||||||
import { CloseSharp } from '@vicons/ionicons5'
|
import { CloseSharp } from '@vicons/ionicons5'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { useSoftwareStore } from '../../../../../../stores/software.ts'
|
import { useSoftwareStore } from '../../../../../../stores/software.ts'
|
||||||
|
import { BookType } from '../../../../../../define/enum/bookEnum'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -175,6 +176,16 @@ export default defineComponent({
|
|||||||
} else if (propertyName == 'srtPath') {
|
} else if (propertyName == 'srtPath') {
|
||||||
ext = ['srt']
|
ext = ['srt']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是不是原创,原创不能选择视频文件
|
||||||
|
if (
|
||||||
|
reverseManageStore.selectBook.type == BookType.ORIGINAL &&
|
||||||
|
propertyName == 'oldVideoPath'
|
||||||
|
) {
|
||||||
|
message.error('原创小说不能选择视频文件')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 选择MP4文件夹
|
// 选择MP4文件夹
|
||||||
await window.api.SelectFile(ext, (value) => {
|
await window.api.SelectFile(ext, (value) => {
|
||||||
debugger
|
debugger
|
||||||
@ -212,8 +223,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
let rules = {
|
let rules = {
|
||||||
name: ruleObj('书名必填'),
|
name: ruleObj('书名必填'),
|
||||||
oldVideoPath: ruleObj('反推的视频文件地址必填'),
|
type: ruleObj('小说类型必填'),
|
||||||
type: ruleObj('小说类型必填')
|
oldVideoPath: {
|
||||||
|
required: true,
|
||||||
|
validator(rule, value) {
|
||||||
|
// 判断是不是原创,原创不能选择视频文件,反推必选
|
||||||
|
if(reverseManageStore.selectBook.type == BookType.SD_REVERSE || reverseManageStore.selectBook.type == BookType.MJ_REVERSE){
|
||||||
|
return new Error("MJ反推和SD反推,视频文件必选")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur', 'change']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,7 +311,8 @@ export default defineComponent({
|
|||||||
bookRef,
|
bookRef,
|
||||||
softwareStore,
|
softwareStore,
|
||||||
OpenFolder,
|
OpenFolder,
|
||||||
backgroundMusicOptions,loading
|
backgroundMusicOptions,
|
||||||
|
loading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -774,7 +774,8 @@ export default defineComponent({
|
|||||||
after_gpt: element.afterGpt,
|
after_gpt: element.afterGpt,
|
||||||
subValue: element.subValue ? element.subValue : [],
|
subValue: element.subValue ? element.subValue : [],
|
||||||
name: element.name + '.png',
|
name: element.name + '.png',
|
||||||
prompt: element.prompt
|
prompt: element.prompt,
|
||||||
|
timeLimit: element.timeLimit
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,361 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="width: 500px; position: relative">
|
||||||
|
<n-form ref="formRef" label-placement="top" :model="characterData" :rules="rules">
|
||||||
|
<n-form-item label="人物名称" path="label">
|
||||||
|
<n-input
|
||||||
|
style="width: 400px"
|
||||||
|
v-model:value="characterData.label"
|
||||||
|
placeholder="请输入人物名称"
|
||||||
|
/>
|
||||||
|
<n-checkbox style="margin-left: 20px" v-model:checked="characterData.isShow"
|
||||||
|
>显示</n-checkbox
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="position: absolute; left: 520px; top: 0; display: flex; flex-direction: column"
|
||||||
|
>
|
||||||
|
<n-image
|
||||||
|
width="120"
|
||||||
|
height="120"
|
||||||
|
:src="png_base64 ? png_base64 : characterData.show_image"
|
||||||
|
/>
|
||||||
|
<n-button color="#e18a3b" style="margin-top: 5px" size="tiny" @click="SelecImage"
|
||||||
|
>本地上传图片</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="人物别名(可多个)">
|
||||||
|
<n-dynamic-tags type="success" v-model:value="alias_tags" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="人物提示词(中文)">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
v-model:value="characterData.chinese_prompt"
|
||||||
|
placeholder="请输入人物提示词"
|
||||||
|
/>
|
||||||
|
<!-- 里面的按钮设置上下居中 -->
|
||||||
|
|
||||||
|
<div style="width: 100px; margin-left: 20px">
|
||||||
|
<n-button color="#a76283" size="tiny" @click="TranslatePrompt" :loading="loading"
|
||||||
|
>翻译提示词</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
color="#e18a3b"
|
||||||
|
size="tiny"
|
||||||
|
style="margin-top: 10px"
|
||||||
|
@click="GenerateCharacterImage"
|
||||||
|
:loading="imageLoading"
|
||||||
|
>SD生成图片</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="人物提示词(英文)" path="prompt">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
v-model:value="characterData.prompt"
|
||||||
|
placeholder="请输入人物提示词"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:人物图片链接(cref)">
|
||||||
|
<n-input
|
||||||
|
v-model:value="characterData.image_url"
|
||||||
|
placeholder="请输入人物图片链接"
|
||||||
|
style="margin-right: 20px"
|
||||||
|
/>
|
||||||
|
<n-image
|
||||||
|
v-if="characterData.image_url"
|
||||||
|
:src="characterData.image_url"
|
||||||
|
style="width: 80px; height: 80px"
|
||||||
|
:alt="characterData.image_url"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:角色迁移 cw 值(0-100)">
|
||||||
|
<n-input-number
|
||||||
|
:show-button="false"
|
||||||
|
v-model:value="characterData.cref_cw"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
placeholder="请输入人物风格迁移的CW值"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="SD:Lora选择">
|
||||||
|
<n-select
|
||||||
|
v-model:value="characterData.lora"
|
||||||
|
style="width: 250px"
|
||||||
|
:options="lora_options"
|
||||||
|
placeholder="选择人物lora"
|
||||||
|
/>
|
||||||
|
<n-input-number
|
||||||
|
style="width: 120px; margin-left: 10px"
|
||||||
|
placeholder="权重"
|
||||||
|
v-model:value="characterData.lora_weight"
|
||||||
|
:show-button="false"
|
||||||
|
:max="2"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
S
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<n-button type="success" @click="SaveCharacterTag">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw, watch, nextTick } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NSelect,
|
||||||
|
NCheckbox
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage,
|
||||||
|
NButton,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NSelect,
|
||||||
|
NCheckbox
|
||||||
|
},
|
||||||
|
props: ['currentCharacter', 'initFunc', 'currentTags', 'lora_options'],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage()
|
||||||
|
let alias_tags = ref(props.currentTags)
|
||||||
|
let characterData = ref(props.currentCharacter)
|
||||||
|
let lora_options = ref(props.lora_options)
|
||||||
|
let loading = ref(false)
|
||||||
|
let imageLoading = ref(false)
|
||||||
|
let formRef = ref(null)
|
||||||
|
|
||||||
|
let png_base64 = ref(null)
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(
|
||||||
|
() => props.currentCharacter,
|
||||||
|
(value) => {
|
||||||
|
characterData.value = value
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.currentTags,
|
||||||
|
(value) => {
|
||||||
|
alias_tags.value = value
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {})
|
||||||
|
|
||||||
|
async function SaveCharacterTag(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
formRef.value?.validate(async (errors) => {
|
||||||
|
if (errors) {
|
||||||
|
message.error('请检查必填字段')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 保存之前要处理数据(判断该当前的将别名数组中的数据进行拆分)
|
||||||
|
let children = []
|
||||||
|
alias_tags.value.forEach((item) => {
|
||||||
|
children.push({
|
||||||
|
label: item,
|
||||||
|
key: uuidv4(),
|
||||||
|
type: 'min',
|
||||||
|
chinese_prompt: characterData.value.chinese_prompt,
|
||||||
|
prompt: characterData.value.prompt,
|
||||||
|
image_url: characterData.value.image_url,
|
||||||
|
show_image: characterData.value.show_image
|
||||||
|
? characterData.value.show_image.split('?t')[0]
|
||||||
|
: null,
|
||||||
|
cref_cw: characterData.value.cref_cw,
|
||||||
|
lora: characterData.value.lora,
|
||||||
|
lora_weight: characterData.value.lora_weight
|
||||||
|
})
|
||||||
|
})
|
||||||
|
characterData.value['children'] = children
|
||||||
|
console.log(characterData.value)
|
||||||
|
characterData.value['type'] = 'character_main'
|
||||||
|
characterData.value['show_image'] = characterData.value.show_image
|
||||||
|
? characterData.value.show_image.split('?t')[0]
|
||||||
|
: null
|
||||||
|
// 开始保存
|
||||||
|
await window.mj.SaveTagPropertyData(
|
||||||
|
[JSON.stringify(characterData.value), 'character_tags'],
|
||||||
|
(value) => {
|
||||||
|
console.log(value)
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
//保存成功在initFunc
|
||||||
|
props.initFunc()
|
||||||
|
// 清楚数据
|
||||||
|
characterData.value = {
|
||||||
|
label: null,
|
||||||
|
key: null,
|
||||||
|
type: 'character_main',
|
||||||
|
chinese_prompt: null,
|
||||||
|
prompt: null,
|
||||||
|
image_url: null,
|
||||||
|
show_image: window.config.space_image,
|
||||||
|
cref_cw: 20,
|
||||||
|
chinese_prompt: null,
|
||||||
|
lora: '无',
|
||||||
|
lora_weight: 1
|
||||||
|
}
|
||||||
|
png_base64.value = null
|
||||||
|
alias_tags.value = []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻译提示词
|
||||||
|
async function TranslatePrompt() {
|
||||||
|
loading.value = true
|
||||||
|
if (characterData.value.chinese_prompt == '' || characterData.value.chinese_prompt == null) {
|
||||||
|
message.error('请输入中文提示词')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await window.api.TranslateReturnNow(
|
||||||
|
[characterData.value.chinese_prompt, 'zh', 'en', false],
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
characterData.value.prompt = value.data[0].src
|
||||||
|
}
|
||||||
|
)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let ruleObj = (errorMessage) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator(rule, value) {
|
||||||
|
if (value == null || value == '') return new Error(errorMessage)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur', 'change']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let rules = {
|
||||||
|
label: ruleObj('必填人物名称'),
|
||||||
|
prompt: ruleObj('必填英文提示词')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单张生成角色图片,预览
|
||||||
|
*/
|
||||||
|
async function GenerateCharacterImage() {
|
||||||
|
// 判断lora是不是存在
|
||||||
|
let lora = ''
|
||||||
|
if (
|
||||||
|
characterData.value.lora != null &&
|
||||||
|
characterData.value.lora != '' &&
|
||||||
|
characterData.value.lora != '无'
|
||||||
|
) {
|
||||||
|
lora = `<lora:${characterData.value.lora}:${characterData.value.lora_weight}>`
|
||||||
|
}
|
||||||
|
let d = {
|
||||||
|
prompt: `${characterData.value.prompt}, ${lora}`,
|
||||||
|
width: 1024,
|
||||||
|
height: 1024
|
||||||
|
}
|
||||||
|
if (isEmpty(characterData.value.prompt)) {
|
||||||
|
message.error('请填写英文提示词')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imageLoading.value = true
|
||||||
|
await window.sd.txt2img(JSON.stringify([d]), async (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
imageLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value.data && value.data.length > 0) {
|
||||||
|
let d = value.data[0]
|
||||||
|
characterData.value.show_image = d.image_path.replaceAll('\\', '/')
|
||||||
|
png_base64.value = 'data:image/png;base64,' + d.base64
|
||||||
|
console.log(characterData.value.show_image)
|
||||||
|
imageLoading.value = false
|
||||||
|
}
|
||||||
|
// 使用 Vue.nextTick 等待 Vue 更新视图
|
||||||
|
imageLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择本地图片
|
||||||
|
*/
|
||||||
|
async function SelecImage() {
|
||||||
|
await window.api.SelectFile(
|
||||||
|
[
|
||||||
|
'jpeg',
|
||||||
|
'jpg',
|
||||||
|
'png',
|
||||||
|
'gif',
|
||||||
|
'bmp',
|
||||||
|
'tiff',
|
||||||
|
'tif',
|
||||||
|
'webp',
|
||||||
|
'svg',
|
||||||
|
'raw',
|
||||||
|
'cr2',
|
||||||
|
'nef',
|
||||||
|
'arw'
|
||||||
|
],
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
png_base64.value = null
|
||||||
|
characterData.value.show_image = value.value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
characterData,
|
||||||
|
SelecImage,
|
||||||
|
alias_tags,
|
||||||
|
SaveCharacterTag,
|
||||||
|
TranslatePrompt,
|
||||||
|
loading,
|
||||||
|
rules,
|
||||||
|
formRef,
|
||||||
|
lora_options,
|
||||||
|
imageLoading,
|
||||||
|
GenerateCharacterImage,
|
||||||
|
png_base64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 500px;">
|
||||||
|
<n-form label-placement="top">
|
||||||
|
<n-form-item label="前缀名称">
|
||||||
|
<n-input v-model:value="prefixData.label" placeholder="请输入场景名称" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="前缀提示词描述">
|
||||||
|
<n-input type="textarea" :rows="3" v-model:value="prefixData.prompt" placeholder="请输入前缀提示词描述" />
|
||||||
|
</n-form-item>
|
||||||
|
<!-- <n-form-item label="MJ:风格垫图链接(sref)">
|
||||||
|
<n-input v-model:value="prefixData.image_url" placeholder="请输入风格垫图链接" style="margin-right: 20px;" />
|
||||||
|
<n-image v-if="prefixData.image_url" :src="prefixData.image_url" style="width: 80px; height: 80px" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:风格迁移 cw 值(0-1000)">
|
||||||
|
<n-input-number :show-button="false" v-model:value="prefixData.sref_cw" min="0" max="1000"
|
||||||
|
placeholder="请输入人物风格迁移的CW值" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="SD:Lora选择">
|
||||||
|
<n-input v-model:value="prefixData.lora" placeholder="请输入风格Lora" />
|
||||||
|
<n-button color="#e18a3b" style="margin-left: 20px;">选择</n-button>
|
||||||
|
</n-form-item> -->
|
||||||
|
</n-form>
|
||||||
|
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<n-button type="success" @click="SavePrefixTag">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw, watch } from "vue"
|
||||||
|
import { NImage, useMessage, NButton, useDialog, NInput, NForm, NFormItem, NDynamicTags, NInputNumber } from "naive-ui";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage, NButton, NInput, NForm, NFormItem, NDynamicTags, NInputNumber
|
||||||
|
},
|
||||||
|
props: ["currentPrefix", "initFunc"],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage();
|
||||||
|
let prefixData = ref(props.currentPrefix);
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(() => props.currentPrefix, (value) => {
|
||||||
|
prefixData.value = value;
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
async function SavePrefixTag() {
|
||||||
|
// 直接保存
|
||||||
|
// 开始保存
|
||||||
|
prefixData.value['type'] = "prefix_main";
|
||||||
|
await window.mj.SaveTagPropertyData([JSON.stringify(prefixData.value), "prefix_tags"], (value) => {
|
||||||
|
|
||||||
|
console.log(value);
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.success(value.message);
|
||||||
|
//保存成功在initFunc
|
||||||
|
props.initFunc();
|
||||||
|
// 清楚数据
|
||||||
|
prefixData.value = {
|
||||||
|
label: null,
|
||||||
|
key: null,
|
||||||
|
type: "prefix_main",
|
||||||
|
prompt: null,
|
||||||
|
// image_url: null,
|
||||||
|
// cref_cw: 20,
|
||||||
|
// lora: null,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
prefixData,
|
||||||
|
SavePrefixTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 500px">
|
||||||
|
<n-form label-placement="top" ref="formRef" :rules="rules" :model="sceneData">
|
||||||
|
<n-form-item label="场景名称" path="label">
|
||||||
|
<n-input
|
||||||
|
style="width: 400px"
|
||||||
|
v-model:value="sceneData.label"
|
||||||
|
placeholder="请输入场景名称"
|
||||||
|
/>
|
||||||
|
<n-checkbox style="margin-left: 20px" v-model:checked="sceneData.isShow"
|
||||||
|
>显示</n-checkbox
|
||||||
|
>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="场景提示词描述(中文)">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
v-model:value="sceneData.chinese_prompt"
|
||||||
|
placeholder="请输入场景提示词描述"
|
||||||
|
/>
|
||||||
|
<n-button
|
||||||
|
type="info"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 20px"
|
||||||
|
@click="TranslatePrompt"
|
||||||
|
:loading="loading"
|
||||||
|
>翻译提示词</n-button
|
||||||
|
>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="场景提示词描述(英文)" path="prompt">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
v-model:value="sceneData.prompt"
|
||||||
|
placeholder="请输入场景提示词描述"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<!-- <n-form-item label="MJ:风格垫图链接(sref)">
|
||||||
|
<n-input v-model:value="sceneData.image_url" placeholder="请输入风格垫图链接" style="margin-right: 20px;" />
|
||||||
|
<n-image v-if="sceneData.image_url" :src="sceneData.image_url" style="width: 80px; height: 80px" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:风格迁移 cw 值(0-1000)">
|
||||||
|
<n-input-number :show-button="false" v-model:value="sceneData.sref_cw" min="0" max="1000"
|
||||||
|
placeholder="请输入人物风格迁移的CW值" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="SD:Lora选择">
|
||||||
|
<n-input v-model:value="sceneData.lora" placeholder="请输入风格Lora" />
|
||||||
|
<n-button color="#e18a3b" style="margin-left: 20px;">选择</n-button>
|
||||||
|
</n-form-item> -->
|
||||||
|
</n-form>
|
||||||
|
|
||||||
|
<div style="text-align: right">
|
||||||
|
<n-button type="success" @click="SaveSceneTag">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NCheckbox
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage,
|
||||||
|
NButton,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NCheckbox
|
||||||
|
},
|
||||||
|
props: ['currentScene', 'initFunc'],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage()
|
||||||
|
let sceneData = ref(props.currentScene)
|
||||||
|
let loading = ref(false)
|
||||||
|
let formRef = ref(null)
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(
|
||||||
|
() => props.currentScene,
|
||||||
|
(value) => {
|
||||||
|
sceneData.value = value
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {})
|
||||||
|
|
||||||
|
// 保存操作
|
||||||
|
async function SaveSceneTag(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
formRef.value?.validate(async (errors) => {
|
||||||
|
if (errors) {
|
||||||
|
message.error('请检查必填字段')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 直接保存
|
||||||
|
// 开始保存
|
||||||
|
sceneData.value['type'] = 'scene_main'
|
||||||
|
await window.mj.SaveTagPropertyData(
|
||||||
|
[JSON.stringify(sceneData.value), 'scene_tags'],
|
||||||
|
(value) => {
|
||||||
|
|
||||||
|
console.log(value)
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
//保存成功在initFunc
|
||||||
|
props.initFunc()
|
||||||
|
// 清楚数据
|
||||||
|
sceneData.value = {
|
||||||
|
label: null,
|
||||||
|
key: null,
|
||||||
|
type: 'scene_main',
|
||||||
|
prompt: null
|
||||||
|
// image_url: null,
|
||||||
|
// cref_cw: 20,
|
||||||
|
// lora: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻译提示词
|
||||||
|
async function TranslatePrompt() {
|
||||||
|
loading.value = true
|
||||||
|
if (sceneData.value.chinese_prompt == '' || sceneData.value.chinese_prompt == null) {
|
||||||
|
message.error('请输入中文提示词')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await window.api.TranslateReturnNow(
|
||||||
|
[sceneData.value.chinese_prompt, 'zh', 'en', false],
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//
|
||||||
|
console.log(value.data)
|
||||||
|
sceneData.value.prompt = value.data[0].src
|
||||||
|
}
|
||||||
|
)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let ruleObj = (errorMessage) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator(rule, value) {
|
||||||
|
if (value == null || value == '') return new Error(errorMessage)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur', 'change']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let rules = {
|
||||||
|
label: ruleObj('必填人物名称'),
|
||||||
|
prompt: ruleObj('必填英文提示词')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sceneData,
|
||||||
|
SaveSceneTag,
|
||||||
|
loading,
|
||||||
|
TranslatePrompt,
|
||||||
|
rules,
|
||||||
|
formRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,327 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 500px">
|
||||||
|
<n-form label-placement="top" ref="formRef" :rules="rules" :model="styleData">
|
||||||
|
<n-form-item label="风格名称" path="label">
|
||||||
|
<n-input v-model:value="styleData.label" placeholder="请输入风格名称" />
|
||||||
|
<div style="position: absolute; left: 520px; top: 0; display: flex; flex-direction: column">
|
||||||
|
<n-image width="120" height="120" :src="png_base64 ? png_base64 : styleData.show_image" />
|
||||||
|
<n-button color="#e18a3b" style="margin-top: 5px" size="tiny" @click="SelecImage"
|
||||||
|
>本地上传图片</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="风格提示词描述(中文)">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
v-model:value="styleData.chinese_prompt"
|
||||||
|
placeholder="请输入风格提示词描述(中文)"
|
||||||
|
/>
|
||||||
|
<div style="width: 100px; margin-left: 20px">
|
||||||
|
<n-button type="info" size="tiny" @click="TranslatePrompt" :loading="loading"
|
||||||
|
>翻译提示词</n-button
|
||||||
|
>
|
||||||
|
<n-tooltip trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button
|
||||||
|
color="#e18a3b"
|
||||||
|
size="tiny"
|
||||||
|
style="margin-top: 10px"
|
||||||
|
@click="GenerateStyleImage"
|
||||||
|
:loading="imageLoading"
|
||||||
|
>SD生成图片</n-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
使用SD出图模式生成风格图片,提示词为1gril加上风格提示词
|
||||||
|
</n-tooltip>
|
||||||
|
</div>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="风格提示词描述(英文)" path="prompt">
|
||||||
|
<n-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
v-model:value="styleData.prompt"
|
||||||
|
placeholder="请输入风格提示词描述(英文)"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:风格垫图链接(sref)">
|
||||||
|
<n-input
|
||||||
|
v-model:value="styleData.image_url"
|
||||||
|
placeholder="请输入风格垫图链接"
|
||||||
|
style="margin-right: 20px"
|
||||||
|
/>
|
||||||
|
<n-image
|
||||||
|
v-if="styleData.image_url"
|
||||||
|
:src="styleData.image_url"
|
||||||
|
style="width: 80px; height: 80px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:风格迁移 sw 值(0-1000)">
|
||||||
|
<n-input-number
|
||||||
|
:show-button="false"
|
||||||
|
v-model:value="styleData.sref_sw"
|
||||||
|
min="0"
|
||||||
|
max="1000"
|
||||||
|
placeholder="请输入人物风格迁移的SW值"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="SD:Lora选择">
|
||||||
|
<n-select :options="lora_options" v-model:value="styleData.lora"> </n-select>
|
||||||
|
<n-input-number
|
||||||
|
style="width: 120px; margin-left: 10px"
|
||||||
|
placeholder="权重"
|
||||||
|
v-model:value="styleData.lora_weight"
|
||||||
|
:show-button="false"
|
||||||
|
:max="2"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
S
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
|
||||||
|
<div style="text-align: right">
|
||||||
|
<n-button type="success" @click="SaveStyleTag">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NSelect,
|
||||||
|
NTooltip
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage,
|
||||||
|
NButton,
|
||||||
|
NInput,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NDynamicTags,
|
||||||
|
NInputNumber,
|
||||||
|
NSelect,
|
||||||
|
NTooltip
|
||||||
|
},
|
||||||
|
props: ['currentStyle', 'initFunc', 'lora_options'],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage()
|
||||||
|
let styleData = ref(
|
||||||
|
props.currentStyle
|
||||||
|
? props.currentStyle
|
||||||
|
: { show_image: window.config.space_image, lora_weight: 1, sref_sw: 50, lora: '无' }
|
||||||
|
)
|
||||||
|
let loading = ref(false)
|
||||||
|
let imageLoading = ref(false)
|
||||||
|
let formRef = ref(null)
|
||||||
|
let lora_options = ref(props.lora_options)
|
||||||
|
let png_base64 = ref(null)
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(
|
||||||
|
() => props.currentStyle,
|
||||||
|
(value) => {
|
||||||
|
styleData.value = value
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {})
|
||||||
|
|
||||||
|
async function SaveStyleTag(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
formRef.value?.validate(async (errors) => {
|
||||||
|
if (errors) {
|
||||||
|
message.error('请检查必填字段')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
styleData.value['type'] = 'style_main'
|
||||||
|
styleData.value['show_image'] = styleData.value.show_image
|
||||||
|
? styleData.value.show_image.split('?t')[0]
|
||||||
|
: null
|
||||||
|
// 直接保存
|
||||||
|
// 开始保存
|
||||||
|
await window.mj.SaveTagPropertyData(
|
||||||
|
[JSON.stringify(styleData.value), 'style_tags'],
|
||||||
|
(value) => {
|
||||||
|
console.log(value)
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
//保存成功在initFunc
|
||||||
|
props.initFunc()
|
||||||
|
// 清楚数据
|
||||||
|
styleData.value = {
|
||||||
|
label: null,
|
||||||
|
key: null,
|
||||||
|
type: 'style_main',
|
||||||
|
prompt: null,
|
||||||
|
show_image: window.config.space_image,
|
||||||
|
image_url: null,
|
||||||
|
cref_cw: 20,
|
||||||
|
lora: '无'
|
||||||
|
}
|
||||||
|
png_base64.value = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻译中文提示词
|
||||||
|
*/
|
||||||
|
async function TranslatePrompt() {
|
||||||
|
loading.value = true
|
||||||
|
if (styleData.value.chinese_prompt == '' || styleData.value.chinese_prompt == null) {
|
||||||
|
message.error('请输入中文提示词')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await window.api.TranslateReturnNow(
|
||||||
|
[styleData.value.chinese_prompt, 'zh', 'en', false],
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(value.data)
|
||||||
|
styleData.value.prompt = value.data[0].src
|
||||||
|
}
|
||||||
|
)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let ruleObj = (errorMessage) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator(rule, value) {
|
||||||
|
if (value == null || value == '') return new Error(errorMessage)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
trigger: ['input', 'blur', 'change']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let rules = {
|
||||||
|
label: ruleObj('必填人物名称')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成风格图片
|
||||||
|
*/
|
||||||
|
async function GenerateStyleImage() {
|
||||||
|
if (isEmpty(styleData.value.prompt)) {
|
||||||
|
message.error('请输入提示词')
|
||||||
|
imageLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 判断lora是不是存在
|
||||||
|
let lora = ''
|
||||||
|
if (
|
||||||
|
styleData.value.lora != null &&
|
||||||
|
styleData.value.lora != '' &&
|
||||||
|
styleData.value.lora != '无'
|
||||||
|
) {
|
||||||
|
lora = `<lora:${styleData.value.lora}:${styleData.value.lora_weight}>`
|
||||||
|
}
|
||||||
|
let d = {
|
||||||
|
prompt: `1gril, ${styleData.value.prompt}, ${lora}`,
|
||||||
|
width: 1024,
|
||||||
|
height: 1024
|
||||||
|
}
|
||||||
|
imageLoading.value = true
|
||||||
|
await window.sd.txt2img(JSON.stringify([d]), async (value) => {
|
||||||
|
debugger
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
imageLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value.data && value.data.length > 0) {
|
||||||
|
let d = value.data[0]
|
||||||
|
styleData.value.show_image =
|
||||||
|
d.image_path.replaceAll('\\', '/') + '?t=' + new Date().getTime()
|
||||||
|
png_base64.value = 'data:image/png;base64,' + d.base64
|
||||||
|
console.log(styleData.value.show_image)
|
||||||
|
imageLoading.value = false
|
||||||
|
}
|
||||||
|
// 使用 Vue.nextTick 等待 Vue 更新视图
|
||||||
|
imageLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择本地的图片应用到风格图片
|
||||||
|
*/
|
||||||
|
async function SelecImage() {
|
||||||
|
await window.api.SelectFile(
|
||||||
|
[
|
||||||
|
'jpeg',
|
||||||
|
'jpg',
|
||||||
|
'png',
|
||||||
|
'gif',
|
||||||
|
'bmp',
|
||||||
|
'tiff',
|
||||||
|
'tif',
|
||||||
|
'webp',
|
||||||
|
'svg',
|
||||||
|
'raw',
|
||||||
|
'cr2',
|
||||||
|
'nef',
|
||||||
|
'arw'
|
||||||
|
],
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 读取文件并转换为Base64
|
||||||
|
fetch(value.value)
|
||||||
|
.then((response) => response.blob())
|
||||||
|
.then((blob) => {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onloadend = () => {
|
||||||
|
png_base64.value = reader.result
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(blob)
|
||||||
|
})
|
||||||
|
// 更新显示的图片
|
||||||
|
|
||||||
|
png_base64.value = null
|
||||||
|
styleData.value.show_image = value.value + '?t=' + new Date().getTime()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
styleData,
|
||||||
|
SelecImage,
|
||||||
|
SaveStyleTag,
|
||||||
|
loading,
|
||||||
|
imageLoading,
|
||||||
|
rules,
|
||||||
|
formRef,
|
||||||
|
TranslatePrompt,
|
||||||
|
lora_options,
|
||||||
|
png_base64,
|
||||||
|
GenerateStyleImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 500px;">
|
||||||
|
<n-form label-placement="top">
|
||||||
|
<n-form-item label="后缀名称">
|
||||||
|
<n-input v-model:value="suffixData.label" placeholder="请输入后缀名称" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="后缀提示词描述">
|
||||||
|
<n-input type="textarea" :rows="3" v-model:value="suffixData.prompt" placeholder="请输入后缀提示词描述" />
|
||||||
|
</n-form-item>
|
||||||
|
<!-- <n-form-item label="MJ:风格垫图链接(sref)">
|
||||||
|
<n-input v-model:value="suffixData.image_url" placeholder="请输入风格垫图链接" style="margin-right: 20px;" />
|
||||||
|
<n-image v-if="suffixData.image_url" :src="suffixData.image_url" style="width: 80px; height: 80px" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="MJ:风格迁移 cw 值(0-1000)">
|
||||||
|
<n-input-number :show-button="false" v-model:value="suffixData.sref_cw" min="0" max="1000"
|
||||||
|
placeholder="请输入人物风格迁移的CW值" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="SD:Lora选择">
|
||||||
|
<n-input v-model:value="suffixData.lora" placeholder="请输入风格Lora" />
|
||||||
|
<n-button color="#e18a3b" style="margin-left: 20px;">选择</n-button>
|
||||||
|
</n-form-item> -->
|
||||||
|
</n-form>
|
||||||
|
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<n-button type="success" @click="SavePrefixTag">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw, watch } from "vue"
|
||||||
|
import { NImage, useMessage, NButton, useDialog, NInput, NForm, NFormItem, NDynamicTags, NInputNumber } from "naive-ui";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage, NButton, NInput, NForm, NFormItem, NDynamicTags, NInputNumber
|
||||||
|
},
|
||||||
|
props: ["currentSuffix", "initFunc"],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage();
|
||||||
|
let suffixData = ref(props.currentSuffix);
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(() => props.currentSuffix, (value) => {
|
||||||
|
suffixData.value = value;
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
async function SavePrefixTag() {
|
||||||
|
// 直接保存
|
||||||
|
// 开始保存
|
||||||
|
suffixData.value['type'] = "suffix_main";
|
||||||
|
await window.mj.SaveTagPropertyData([JSON.stringify(suffixData.value), "suffix_tags"], (value) => {
|
||||||
|
|
||||||
|
console.log(value);
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.success(value.message);
|
||||||
|
//保存成功在initFunc
|
||||||
|
props.initFunc();
|
||||||
|
// 清楚数据
|
||||||
|
suffixData.value = {
|
||||||
|
label: null,
|
||||||
|
key: null,
|
||||||
|
type: "suffix_main",
|
||||||
|
prompt: null,
|
||||||
|
// image_url: null,
|
||||||
|
// cref_cw: 20,
|
||||||
|
// lora: null,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
suffixData,
|
||||||
|
SavePrefixTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div style="margin-top: 30px">
|
||||||
|
<n-card>
|
||||||
|
<n-tabs
|
||||||
|
class="card-tabs"
|
||||||
|
default-value="autoAnalyze"
|
||||||
|
size="large"
|
||||||
|
animated
|
||||||
|
pane-wrapper-style="margin: 0 -4px"
|
||||||
|
pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;"
|
||||||
|
>
|
||||||
|
<n-tab-pane name="autoAnalyze" tab="自动分析">
|
||||||
|
<n-button color="#ee7959" size="medium" @click="autoAnalyzeCharacter" :loading="loading"
|
||||||
|
>自动分析</n-button
|
||||||
|
>
|
||||||
|
<n-input
|
||||||
|
style="margin-top: 20px"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 10,
|
||||||
|
maxRows: 10
|
||||||
|
}"
|
||||||
|
placeholder="自动分析的数据"
|
||||||
|
v-model:value="autoCharacterString"
|
||||||
|
></n-input>
|
||||||
|
<div>
|
||||||
|
<div style="color: red">注意:上面推理的不满意可以手动修改</div>
|
||||||
|
<div style="color: red">自动推理的的人物只能对内置的四种模式生效</div>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<n-button type="success" @click="SaveAutoAnalyzeCharacter">保存</n-button>
|
||||||
|
</div>
|
||||||
|
</n-tab-pane>
|
||||||
|
<n-tab-pane name="Analyze" tab="手动设置标签集">
|
||||||
|
<CharacterTags :height="height"></CharacterTags>
|
||||||
|
</n-tab-pane>
|
||||||
|
</n-tabs>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, h, onMounted, toRaw } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NCard,
|
||||||
|
NTabs,
|
||||||
|
NTabPane,
|
||||||
|
NTree
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import CharacterTags from './CharacterTags.vue'
|
||||||
|
import { useReverseManageStore } from '../../../../../../stores/reverseManage'
|
||||||
|
let reverseManageStore = useReverseManageStore()
|
||||||
|
let autoCharacterString = ref('')
|
||||||
|
|
||||||
|
let props = defineProps({
|
||||||
|
word: undefined,
|
||||||
|
height: undefined
|
||||||
|
})
|
||||||
|
let message = useMessage()
|
||||||
|
let word = ref(props.word)
|
||||||
|
let height = ref(props.height)
|
||||||
|
let loading = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
autoCharacterString.value = reverseManageStore.selectBookTask.autoAnalyzeCharacter
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动分析角色
|
||||||
|
*/
|
||||||
|
async function autoAnalyzeCharacter() {
|
||||||
|
if (word.value == '' || word.value == null) {
|
||||||
|
message.error('请输入要分析的文案')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
await window.api.AutoAnalyzeCharacter(toRaw(word.value), (value) => {
|
||||||
|
loading.value = false
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
autoCharacterString.value = value.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存自动分析的设置
|
||||||
|
*/
|
||||||
|
async function SaveAutoAnalyzeCharacter() {
|
||||||
|
if (autoCharacterString.value == '' || autoCharacterString.value == null) {
|
||||||
|
message.error('没有分析出来的人物信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 保存信息
|
||||||
|
reverseManageStore.selectBookTask.autoAnalyzeCharacter = autoCharacterString.value
|
||||||
|
let res = await window.db.UpdateBookTaskData(reverseManageStore.selectBookTask.id, {
|
||||||
|
autoAnalyzeCharacter: autoCharacterString.value
|
||||||
|
})
|
||||||
|
if (res.code == 1) {
|
||||||
|
message.success(res.message)
|
||||||
|
} else {
|
||||||
|
message.error(res.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card-tabs .n-tabs-nav--bar-type {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,470 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-split direction="horizontal" :max="0.3" :min="0.18" :default-size="0.18">
|
||||||
|
<template #1>
|
||||||
|
<div id="tree_define_content" style="display: flex; overflow-y: auto">
|
||||||
|
<n-tree :node-props="nodeProps" style="width: 200px" block-line :data="treeData" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #2>
|
||||||
|
<div style="margin-left: 20px">
|
||||||
|
<AddCharacterTag
|
||||||
|
v-if="currentType.startsWith('character')"
|
||||||
|
:currentCharacter="currentCharacter"
|
||||||
|
:currentTags="currentTags"
|
||||||
|
:initFunc="InitData"
|
||||||
|
:lora_options="lora_options"
|
||||||
|
/>
|
||||||
|
<AddStyleTags
|
||||||
|
v-else-if="currentType.startsWith('style')"
|
||||||
|
:currentStyle="currentStyle"
|
||||||
|
:initFunc="InitData"
|
||||||
|
:lora_options="lora_options"
|
||||||
|
/>
|
||||||
|
<AddSceneTags
|
||||||
|
v-else-if="currentType.startsWith('scene')"
|
||||||
|
:currentScene="currentScene"
|
||||||
|
:initFunc="InitData"
|
||||||
|
/>
|
||||||
|
<AddPrefixTags
|
||||||
|
v-else-if="currentType.startsWith('prefix')"
|
||||||
|
:currentPrefix="currentPrefix"
|
||||||
|
:initFunc="InitData"
|
||||||
|
/>
|
||||||
|
<AddSuffixTags
|
||||||
|
v-else-if="currentType.startsWith('suffix')"
|
||||||
|
:currentSuffix="currentSuffix"
|
||||||
|
:initFunc="InitData"
|
||||||
|
/>
|
||||||
|
<n-empty v-else description="是一个飞机">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<airplane />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-empty>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</n-split>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, h, onMounted, defineComponent, toRaw } from 'vue'
|
||||||
|
import {
|
||||||
|
NImage,
|
||||||
|
useMessage,
|
||||||
|
NButton,
|
||||||
|
useDialog,
|
||||||
|
NInput,
|
||||||
|
NCard,
|
||||||
|
NTabs,
|
||||||
|
NTabPane,
|
||||||
|
NTree,
|
||||||
|
NSplit,
|
||||||
|
NIcon,
|
||||||
|
NEmpty
|
||||||
|
} from 'naive-ui'
|
||||||
|
import { DEFINE_STRING } from '../../../../../../define/define_string'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import AddCharacterTag from './AddCharacterTag.vue'
|
||||||
|
import AddStyleTags from './AddStyleTags.vue'
|
||||||
|
import AddSceneTags from './AddSceneTags.vue'
|
||||||
|
import AddPrefixTags from './AddPrefixTags.vue'
|
||||||
|
import AddSuffixTags from './AddSuffixTags.vue'
|
||||||
|
import { Trash, Airplane } from '@vicons/ionicons5'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
NImage,
|
||||||
|
NButton,
|
||||||
|
NInput,
|
||||||
|
NCard,
|
||||||
|
NTabs,
|
||||||
|
NTabPane,
|
||||||
|
NTree,
|
||||||
|
NSplit,
|
||||||
|
AddCharacterTag,
|
||||||
|
AddStyleTags,
|
||||||
|
AddSceneTags,
|
||||||
|
AddPrefixTags,
|
||||||
|
AddSuffixTags,
|
||||||
|
NIcon,
|
||||||
|
Trash,
|
||||||
|
NEmpty,
|
||||||
|
Airplane
|
||||||
|
},
|
||||||
|
props: ['height'],
|
||||||
|
setup(props) {
|
||||||
|
let message = useMessage()
|
||||||
|
let currentCharacter = ref({})
|
||||||
|
let currentStyle = ref({})
|
||||||
|
let currentScene = ref({})
|
||||||
|
let currentPrefix = ref({})
|
||||||
|
let currentSuffix = ref({})
|
||||||
|
let currentTags = ref([])
|
||||||
|
let currentType = ref('default')
|
||||||
|
|
||||||
|
let lora_options = ref([])
|
||||||
|
|
||||||
|
let treeData = ref([
|
||||||
|
{
|
||||||
|
label: '人物',
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'character',
|
||||||
|
suffix: () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
color: '#e18a3b',
|
||||||
|
onClick: (e) => {
|
||||||
|
AddCharacterTags(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '新加' }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '场景',
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'scene',
|
||||||
|
suffix: () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
color: '#e18a3b',
|
||||||
|
onClick: (e) => {
|
||||||
|
AddSceneTags(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '新加' }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '风格预设',
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'style',
|
||||||
|
suffix: () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
color: '#e18a3b',
|
||||||
|
onClick: (e) => {
|
||||||
|
AddStyleTags(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '新加' }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '前缀',
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'prefix',
|
||||||
|
suffix: () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
color: '#e18a3b',
|
||||||
|
onClick: (e) => {
|
||||||
|
AddPrefixTags(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '新加' }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '后缀',
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'suffix',
|
||||||
|
suffix: () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
color: '#e18a3b',
|
||||||
|
onClick: (e) => {
|
||||||
|
AddSuffixTags(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => '新加' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化标签数据
|
||||||
|
*/
|
||||||
|
async function InitData() {
|
||||||
|
// 获取动态配置里面是不是又标签数(有加载,没有设置默认值)
|
||||||
|
await window.mj.GetTagDataByTypeAndProperty(['dynamic', null], (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 判断是不是包含指定的属性
|
||||||
|
if (value.data.hasOwnProperty('character_tags')) {
|
||||||
|
treeData.value[0].children = value.data.character_tags
|
||||||
|
}
|
||||||
|
if (value.data.hasOwnProperty('scene_tags')) {
|
||||||
|
treeData.value[1].children = value.data.scene_tags
|
||||||
|
}
|
||||||
|
if (value.data.hasOwnProperty('style_tags')) {
|
||||||
|
treeData.value[2].children = value.data.style_tags
|
||||||
|
}
|
||||||
|
if (value.data.hasOwnProperty('prefix_tags')) {
|
||||||
|
treeData.value[3].children = value.data.prefix_tags
|
||||||
|
}
|
||||||
|
if (value.data.hasOwnProperty('suffix_tags')) {
|
||||||
|
treeData.value[4].children = value.data.suffix_tags
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < treeData.value.length; i++) {
|
||||||
|
treeData.value[i].children.map((item) => {
|
||||||
|
item.suffix = () =>
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
type: 'error',
|
||||||
|
size: 'medium',
|
||||||
|
onClick: (e) => {
|
||||||
|
DeleteTags(e, item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ default: () => h(NIcon, null, { default: () => h(Trash) }) }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 加载lora数据
|
||||||
|
// 获取当前mj配置信息
|
||||||
|
await window.api.GetDefineConfigJsonByProperty(
|
||||||
|
JSON.stringify(['sd_setting', 'lora', false, []]),
|
||||||
|
(value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 判断是不是有数据
|
||||||
|
if (value.data) {
|
||||||
|
for (let i = 0; i < value.data.length; i++) {
|
||||||
|
const element = value.data[i]
|
||||||
|
lora_options.value.push({
|
||||||
|
label: element.name,
|
||||||
|
value: element.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
SetAutoHeight()
|
||||||
|
await InitData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置标签集的自动高度,传一个外面的高度进来
|
||||||
|
function SetAutoHeight() {
|
||||||
|
let div = document.getElementById('tree_define_content')
|
||||||
|
div.style.height = props.height - 180 + 'px'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定的数据
|
||||||
|
*/
|
||||||
|
async function DeleteTags(e, value) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = value.type.replace('main', 'tags')
|
||||||
|
await window.mj.DeleteTagPropertyData([value.key, type], async (value) => {
|
||||||
|
if (value.code == 0) {
|
||||||
|
message.error(value.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.success(value.message)
|
||||||
|
await InitData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新加人物标签
|
||||||
|
*/
|
||||||
|
async function AddCharacterTags(e) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
// 初始化值,然后赋值给当前添加人物的组件
|
||||||
|
currentCharacter.value = {
|
||||||
|
label: null,
|
||||||
|
key: uuidv4(),
|
||||||
|
children: [],
|
||||||
|
type: 'character_main',
|
||||||
|
chinese_prompt: null,
|
||||||
|
prompt: null,
|
||||||
|
image_url: null,
|
||||||
|
show_image: window.config.space_image,
|
||||||
|
cref_cw: 50,
|
||||||
|
lora: '无',
|
||||||
|
lora_weight: 1,
|
||||||
|
isShow: false
|
||||||
|
}
|
||||||
|
currentTags.value = []
|
||||||
|
currentType.value = 'character_main'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新加场景标签
|
||||||
|
*/
|
||||||
|
function AddSceneTags(e) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
currentScene.value = {
|
||||||
|
label: null,
|
||||||
|
key: uuidv4(),
|
||||||
|
type: 'scene_main',
|
||||||
|
prompt: null,
|
||||||
|
isShow: false
|
||||||
|
}
|
||||||
|
currentType.value = 'scene_main'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新加 风格迁移预设
|
||||||
|
* @param {*} e
|
||||||
|
*/
|
||||||
|
function AddStyleTags(e) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
currentStyle.value = {
|
||||||
|
label: null,
|
||||||
|
key: uuidv4(),
|
||||||
|
type: 'style_main',
|
||||||
|
show_image: window.config.space_image,
|
||||||
|
prompt: null,
|
||||||
|
image_url: null,
|
||||||
|
sref_sw: 50,
|
||||||
|
lora: '无',
|
||||||
|
lora_weight: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加前缀
|
||||||
|
*/
|
||||||
|
function AddPrefixTags(e) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
currentPrefix.value = {
|
||||||
|
label: null,
|
||||||
|
key: uuidv4(),
|
||||||
|
type: 'prefix_main',
|
||||||
|
prompt: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加后缀
|
||||||
|
* @param {*} e
|
||||||
|
*/
|
||||||
|
function AddSuffixTags(e) {
|
||||||
|
if (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
currentSuffix.value = {
|
||||||
|
label: null,
|
||||||
|
key: uuidv4(),
|
||||||
|
type: 'suffix_main',
|
||||||
|
prompt: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeProps({ option }) {
|
||||||
|
return {
|
||||||
|
onClick() {
|
||||||
|
// 执行切换组件和数据
|
||||||
|
if (option.type == 'style') {
|
||||||
|
currentType.value = 'style'
|
||||||
|
AddStyleTags(null)
|
||||||
|
return
|
||||||
|
} else if (option.type == 'scene') {
|
||||||
|
AddSceneTags(null)
|
||||||
|
currentType.value = 'scene'
|
||||||
|
// message.error("主节点不允许操作");
|
||||||
|
return
|
||||||
|
} else if (option.type == 'character') {
|
||||||
|
AddCharacterTags(null)
|
||||||
|
currentType.value = 'character'
|
||||||
|
return
|
||||||
|
} else if (option.type == 'prefix') {
|
||||||
|
AddPrefixTags(null)
|
||||||
|
currentType.value = 'prefix'
|
||||||
|
return
|
||||||
|
} else if (option.type == 'suffix') {
|
||||||
|
AddSuffixTags(null)
|
||||||
|
currentType.value = 'suffix'
|
||||||
|
return
|
||||||
|
} else if (option.type == 'min') {
|
||||||
|
message.error('别名节点不允许操作')
|
||||||
|
} else {
|
||||||
|
console.log(option)
|
||||||
|
currentType.value = option.type
|
||||||
|
// 修改当前属性
|
||||||
|
if (currentType.value.startsWith('character')) {
|
||||||
|
// 修改tags的值
|
||||||
|
currentCharacter.value = option
|
||||||
|
if (!currentCharacter.value.hasOwnProperty('isShow')) {
|
||||||
|
currentCharacter.value.isShow = false
|
||||||
|
}
|
||||||
|
currentTags.value = option.children.map((item) => {
|
||||||
|
return item.label
|
||||||
|
})
|
||||||
|
} else if (currentType.value.startsWith('scene')) {
|
||||||
|
currentScene.value = option
|
||||||
|
} else if (currentType.value.startsWith('style')) {
|
||||||
|
currentStyle.value = option
|
||||||
|
} else if (currentType.value.startsWith('prefix')) {
|
||||||
|
currentPrefix.value = option
|
||||||
|
} else if (currentType.value.startsWith('suffix')) {
|
||||||
|
currentSuffix.value = option
|
||||||
|
} else {
|
||||||
|
message.error('未知的类型')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
treeData,
|
||||||
|
AddCharacterTags,
|
||||||
|
AddSceneTags,
|
||||||
|
AddStyleTags,
|
||||||
|
nodeProps,
|
||||||
|
currentCharacter,
|
||||||
|
currentTags,
|
||||||
|
InitData,
|
||||||
|
currentType,
|
||||||
|
currentStyle,
|
||||||
|
currentScene,
|
||||||
|
currentPrefix,
|
||||||
|
currentSuffix,
|
||||||
|
lora_options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -38,7 +38,7 @@ export default defineComponent({
|
|||||||
{
|
{
|
||||||
title: 'No.',
|
title: 'No.',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
width: 80,
|
width: 50,
|
||||||
fixed: 'left'
|
fixed: 'left'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -145,7 +145,7 @@ export default defineComponent({
|
|||||||
debugger
|
debugger
|
||||||
// 视口的高度
|
// 视口的高度
|
||||||
let height = window.innerHeight
|
let height = window.innerHeight
|
||||||
maxHeight.value = height - 120
|
maxHeight.value = height - 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user