LaiTool V3.0.1-preview.5
This commit is contained in:
parent
f64c7ad677
commit
e85b0a986d
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
out
|
out
|
||||||
project
|
project
|
||||||
|
tts/*
|
||||||
resources/scripts/build*
|
resources/scripts/build*
|
||||||
resources/scripts/dist
|
resources/scripts/dist
|
||||||
resources/scripts/model
|
resources/scripts/model
|
||||||
|
|||||||
30
package-lock.json
generated
30
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.4",
|
"version": "3.0.1-preview.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.4",
|
"version": "3.0.1-preview.5",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alicloud/alimt20181012": "^1.2.0",
|
"@alicloud/alimt20181012": "^1.2.0",
|
||||||
@ -1927,13 +1927,18 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.14.11",
|
"version": "22.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.14.11.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.1.0.tgz",
|
||||||
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
|
"integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~6.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node/node_modules/undici-types": {
|
||||||
|
"version": "6.13.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.13.0.tgz",
|
||||||
|
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg=="
|
||||||
|
},
|
||||||
"node_modules/@types/responselike": {
|
"node_modules/@types/responselike": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -5732,6 +5737,14 @@
|
|||||||
"debug": "^4.1.1"
|
"debug": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/httpx/node_modules/@types/node": {
|
||||||
|
"version": "20.14.14",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.14.14.tgz",
|
||||||
|
"integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -11679,9 +11692,10 @@
|
|||||||
"integrity": "sha512-Ka0DBegjuV9IPYFT1h0Qqk5U4pccebNIJCGl8C5uU7xtOs+jpJvKGAY4fHGK25hTmXZOEUl9Cnsg5cS6K/b5DA=="
|
"integrity": "sha512-Ka0DBegjuV9IPYFT1h0Qqk5U4pccebNIJCGl8C5uU7xtOs+jpJvKGAY4fHGK25hTmXZOEUl9Cnsg5cS6K/b5DA=="
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.3.3",
|
"version": "5.5.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.5.4.tgz",
|
||||||
|
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "laitool",
|
"name": "laitool",
|
||||||
"version": "3.0.1-preview.4",
|
"version": "3.0.1-preview.5",
|
||||||
"description": "An AI tool for image processing, video processing, and other functions.",
|
"description": "An AI tool for image processing, video processing, and other functions.",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "laitool.cn",
|
"author": "laitool.cn",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 623 KiB After Width: | Height: | Size: 2.2 MiB |
Binary file not shown.
BIN
resources/scripts/db/tts.realm
Normal file
BIN
resources/scripts/db/tts.realm
Normal file
Binary file not shown.
BIN
resources/scripts/db/tts.realm.lock
Normal file
BIN
resources/scripts/db/tts.realm.lock
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
"draft_path": "你的剪映草稿地址",
|
"draft_path": "你的剪映草稿地址",
|
||||||
"project_path": "你的项目文件地址(存放图片视频等数据的文件夹)",
|
"project_path": "你的项目文件地址(存放图片视频等数据的文件夹)",
|
||||||
"project_name": "你的项目名字",
|
"project_name": "你的项目名字",
|
||||||
"gpt_business": "b8866543-8c27-4888-869c-00aa1eb31272",
|
"gpt_business": "b44c6f24-59e4-4a71-b2c7-3df0c4e35e65",
|
||||||
"gpt_model": "gpt-3.5-turbo",
|
"gpt_model": "gpt-3.5-turbo",
|
||||||
"task_number": 1,
|
"task_number": 1,
|
||||||
"translation_business": "https://fanyi-api.baidu.com/api/trans/vip/translate",
|
"translation_business": "https://fanyi-api.baidu.com/api/trans/vip/translate",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,13 +1,11 @@
|
|||||||
import Realm, { UpdateMode } from 'realm'
|
import Realm, { UpdateMode } from 'realm'
|
||||||
import { BookModel } from '../../model/Book/book.js'
|
import { BookModel } from '../../model/Book/book.js'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { BaseService } from '../baseService.js'
|
|
||||||
import { define } from '../../../define.js'
|
import { define } from '../../../define.js'
|
||||||
import { BookImageCategory, BookTaskStatus, BookType } from '../../../enum/bookEnum.js'
|
import { BookImageCategory, BookTaskStatus, BookType } from '../../../enum/bookEnum.js'
|
||||||
import { successMessage } from '../../../../main/Public/generalTools'
|
import { successMessage } from '../../../../main/Public/generalTools'
|
||||||
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../Tools/file'
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../Tools/file'
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
import { BookTaskService } from './bookTaskService'
|
|
||||||
import { BaseRealmService } from './bookBasic.js'
|
import { BaseRealmService } from './bookBasic.js'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
|
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
import Realm from 'realm'
|
import Realm from 'realm'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { BaseService } from '../baseService.js'
|
|
||||||
import { define } from '../../../define.js'
|
import { define } from '../../../define.js'
|
||||||
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
import { BookTaskModel } from '../../model/Book/bookTask.js'
|
||||||
import { BookTaskStatus } from '../../../enum/bookEnum.js'
|
|
||||||
import { successMessage } from '../../../../main/Public/generalTools'
|
import { successMessage } from '../../../../main/Public/generalTools'
|
||||||
import { BaseRealmService } from './bookBasic'
|
import { BaseRealmService } from './bookBasic'
|
||||||
import { cloneDeep, endsWith, isEmpty } from 'lodash'
|
import { cloneDeep, isEmpty } from 'lodash'
|
||||||
import { book } from '../../../../preload/book.js'
|
|
||||||
import { DefaultObject } from 'realm/dist/public-types/schema.js'
|
|
||||||
import { JoinPath } from '../../../Tools/file'
|
import { JoinPath } from '../../../Tools/file'
|
||||||
import { BookTaskDetailModel, ReversePrompt } from '../../model/Book/bookTaskDetail.js'
|
import { BookTaskDetailModel, ReversePrompt } from '../../model/Book/bookTaskDetail.js'
|
||||||
const { v4: uuidv4 } = require('uuid')
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import Realm, { UpdateMode } from 'realm'
|
import Realm, { UpdateMode } from 'realm'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { BaseService } from '../baseService.js'
|
|
||||||
import { define } from '../../../define.js'
|
|
||||||
import { SoftwareModel } from '../../model/SoftWare/software'
|
|
||||||
import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js'
|
|
||||||
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
|
import { errorMessage, successMessage } from '../../../../main/Public/generalTools'
|
||||||
import { BaseSoftWareService } from './softwareBasic.js'
|
import { BaseSoftWareService } from './softwareBasic.js'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
|
|||||||
@ -1,13 +1,36 @@
|
|||||||
import SoftwareService from './SoftWare/softwareService'
|
import SoftwareService from './SoftWare/softwareService'
|
||||||
|
import { BookService } from './Book/bookService'
|
||||||
|
import { BookTaskService } from './Book/bookTaskService'
|
||||||
|
import { BookTaskDetailService } from './Book/bookTaskDetailService'
|
||||||
|
import { BookBackTaskListService } from './Book/bookBackTaskListService'
|
||||||
|
import { MJSettingService } from './SoftWare/mjSettingService'
|
||||||
|
|
||||||
export class ServiceBase {
|
export class ServiceBase {
|
||||||
softService: SoftwareService
|
softService: SoftwareService | undefined
|
||||||
|
bookService: BookService | undefined
|
||||||
|
bookTaskService: BookTaskService | undefined
|
||||||
|
bookTaskDetailService: BookTaskDetailService | undefined
|
||||||
|
bookBackTaskListService: BookBackTaskListService | undefined
|
||||||
|
mjSettingService: MJSettingService | undefined
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
async InitService() {
|
async InitService() {
|
||||||
if (!this.softService) {
|
if (!this.softService) {
|
||||||
this.softService = await SoftwareService.getInstance()
|
this.softService = await SoftwareService.getInstance()
|
||||||
}
|
}
|
||||||
|
if (!this.bookService) {
|
||||||
|
this.bookService = await BookService.getInstance()
|
||||||
|
}
|
||||||
|
if (!this.bookTaskDetailService) {
|
||||||
|
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
|
||||||
|
}
|
||||||
|
if (!this.bookBackTaskListService) {
|
||||||
|
this.bookBackTaskListService = await BookBackTaskListService.getInstance()
|
||||||
|
}
|
||||||
|
if (this.mjSettingService) {
|
||||||
|
this.mjSettingService = await MJSettingService.getInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/define/db/tts/tts.ts
Normal file
36
src/define/db/tts/tts.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import Realm from 'realm'
|
||||||
|
import { TTSSelectModel } from '../../enum/tts'
|
||||||
|
|
||||||
|
export class TTSModel extends Realm.Object<TTSModel> {
|
||||||
|
id: string
|
||||||
|
no: number
|
||||||
|
name: string // 一把就是配音的前几个字
|
||||||
|
textPath: string // 保存生成文本的地址
|
||||||
|
ttsPath: string // 生成的配置文件地址
|
||||||
|
srtPath: string | null // 生成的SRT地址
|
||||||
|
selectModel: TTSSelectModel // 选择模式
|
||||||
|
hasSrt: boolean
|
||||||
|
srtJsonPath: string | null
|
||||||
|
createTime: Date
|
||||||
|
updateTime: Date
|
||||||
|
|
||||||
|
static schema: Realm.ObjectSchema = {
|
||||||
|
name: 'TTSModel',
|
||||||
|
properties: {
|
||||||
|
id: 'string',
|
||||||
|
no: 'int',
|
||||||
|
name: 'string',
|
||||||
|
textPath: 'string',
|
||||||
|
ttsPath: 'string',
|
||||||
|
srtPath: 'string?',
|
||||||
|
selectModel: 'string',
|
||||||
|
hasSrt: 'bool',
|
||||||
|
srtJsonPath: 'string?',
|
||||||
|
createTime: 'date',
|
||||||
|
updateTime: 'date'
|
||||||
|
},
|
||||||
|
// 主键为_id
|
||||||
|
primaryKey: 'id'
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/define/db/tts/ttsBase.ts
Normal file
60
src/define/db/tts/ttsBase.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import Realm from 'realm'
|
||||||
|
import { BaseService } from '../service/baseService'
|
||||||
|
import { define } from '../../define'
|
||||||
|
import path from 'path'
|
||||||
|
import { TTSModel } from './tts'
|
||||||
|
|
||||||
|
|
||||||
|
let dbPath = path.resolve(define.db_path, 'tts.realm')
|
||||||
|
|
||||||
|
// 版本迁移
|
||||||
|
const migration = (oldRealm: Realm, newRealm: Realm) => {
|
||||||
|
if (oldRealm.schemaVersion < 2) {
|
||||||
|
const oldObjects = oldRealm.objects<TTSModel>('TTSModel')
|
||||||
|
const newObjects = newRealm.objects<TTSModel>('TTSModel')
|
||||||
|
for (let i = 0; i < oldObjects.length; i++) {
|
||||||
|
newObjects[i].textPath = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BaseTTSService extends BaseService {
|
||||||
|
static instance: BaseTTSService | null = null
|
||||||
|
protected realm: Realm | null = null
|
||||||
|
dbpath: string
|
||||||
|
|
||||||
|
protected constructor() {
|
||||||
|
super()
|
||||||
|
this.dbpath = dbPath
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getInstance() {
|
||||||
|
if (BaseTTSService.instance === null) {
|
||||||
|
BaseTTSService.instance = new BaseTTSService()
|
||||||
|
await BaseTTSService.instance.open()
|
||||||
|
}
|
||||||
|
return BaseTTSService.instance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建数据库连接,如果已经存在则直接返回
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async open() {
|
||||||
|
try {
|
||||||
|
if (this.realm != null) return
|
||||||
|
// 判断当前全局是不是又当前这个
|
||||||
|
const config = {
|
||||||
|
schema: [
|
||||||
|
TTSModel
|
||||||
|
],
|
||||||
|
path: this.dbpath,
|
||||||
|
schemaVersion: 2,
|
||||||
|
migration: migration
|
||||||
|
}
|
||||||
|
this.realm = await Realm.open(config)
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
164
src/define/db/tts/ttsService.ts
Normal file
164
src/define/db/tts/ttsService.ts
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import Realm from 'realm'
|
||||||
|
import path from 'path'
|
||||||
|
import { BaseTTSService } from './ttsBase'
|
||||||
|
import { define } from '../../define'
|
||||||
|
import { TTSModel } from './tts'
|
||||||
|
import { tts } from '../../../model/tts'
|
||||||
|
import { isEmpty } from 'lodash'
|
||||||
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
|
||||||
|
export class TTSService extends BaseTTSService {
|
||||||
|
static instance: TTSService | null = null
|
||||||
|
realm: Realm
|
||||||
|
private constructor() {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前实例对象,为空则创建一个新的
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async getInstance() {
|
||||||
|
if (TTSService.instance === null) {
|
||||||
|
TTSService.instance = new TTSService()
|
||||||
|
await super.getInstance()
|
||||||
|
}
|
||||||
|
await TTSService.instance.open()
|
||||||
|
return TTSService.instance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配音历史信息,可以分页和筛选
|
||||||
|
* @param condition 查询的条件参数
|
||||||
|
* @returns 返回当前的查到的所有数据和没有被分割过的数据的数量
|
||||||
|
*/
|
||||||
|
GetTTSHistory(condition: tts.TTSHistoryQueryParams): tts.TTSModelRes {
|
||||||
|
try {
|
||||||
|
let TTSHistory = this.realm.objects<TTSModel>('TTSModel')
|
||||||
|
|
||||||
|
if (condition.name) {
|
||||||
|
TTSHistory = TTSHistory.filtered('name CONTAINS $0', condition.name)
|
||||||
|
}
|
||||||
|
if (condition.id) {
|
||||||
|
TTSHistory = TTSHistory.filtered('id == $0', condition.id)
|
||||||
|
}
|
||||||
|
TTSHistory = TTSHistory.sorted('updateTime', true)
|
||||||
|
|
||||||
|
let TTSCount = TTSHistory.length
|
||||||
|
|
||||||
|
if (condition.page && condition.pageSize) {
|
||||||
|
TTSHistory = TTSHistory.slice(
|
||||||
|
(condition.page - 1) * condition.pageSize,
|
||||||
|
condition.page * condition.pageSize
|
||||||
|
) as unknown as Realm.Results<TTSModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将数据进行处理
|
||||||
|
// 将realm对象数组转换为普通对象数组
|
||||||
|
let TTSHistoryRes = Array.from(TTSHistory).map((item) => {
|
||||||
|
// 这里可以直接操作普通对象
|
||||||
|
let bookObj = {
|
||||||
|
...item,
|
||||||
|
ttsPath: item.ttsPath ? path.resolve(define.tts_path, item.ttsPath.replace(/\\/g, '/')) : '',
|
||||||
|
srtPath: item.srtPath ? path.resolve(define.tts_path, item.srtPath.replace(/\\/g, '/')) : '',
|
||||||
|
srtJsonPath: item.srtJsonPath ? path.resolve(define.tts_path, item.srtJsonPath.replace(/\\/g, '/')) : '',
|
||||||
|
textPath: item.textPath ? path.resolve(define.tts_path, item.textPath.replace(/\\/g, '/')) : ''
|
||||||
|
} as tts.TTSModel
|
||||||
|
return bookObj
|
||||||
|
}) as tts.TTSModel[]
|
||||||
|
return {
|
||||||
|
ttsList: TTSHistoryRes,
|
||||||
|
ttsCount: TTSCount // 返回筛选的总数
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过指定ID获取对应的配音历史信息
|
||||||
|
* @param id 配音历史ID
|
||||||
|
*/
|
||||||
|
GetTTSHistoryById(id: string): tts.TTSModel {
|
||||||
|
try {
|
||||||
|
let res = this.GetTTSHistory({ id: id });
|
||||||
|
if (res.ttsList.length < 0) {
|
||||||
|
throw new Error("没有找到指定ID的配音历史数据,请检查");
|
||||||
|
}
|
||||||
|
// 返回第一个数据
|
||||||
|
return res.ttsList[0];
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增一条TTS生成历史记录
|
||||||
|
* @param data 要新增的数据
|
||||||
|
*/
|
||||||
|
AddTTSHistory(data: tts.TTSModel): tts.TTSModel {
|
||||||
|
try {
|
||||||
|
if (isEmpty(data.id)) {
|
||||||
|
throw new Error('新增TTS历史记录失败,缺少ID')
|
||||||
|
}
|
||||||
|
// 获取最大的no
|
||||||
|
let maxNo = this.realm.objects<TTSModel>('TTSModel').max('no')
|
||||||
|
|
||||||
|
data.no = maxNo == undefined ? 1 : Number(maxNo) + 1
|
||||||
|
data.createTime = new Date()
|
||||||
|
data.updateTime = new Date()
|
||||||
|
|
||||||
|
this.transaction(() => {
|
||||||
|
this.realm.create('TTSModel', data)
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新TTS历史记录数据,修改之后,返回修改后的数据
|
||||||
|
* @param ttsId 要更新的TTS历史记录ID
|
||||||
|
* @param data 要更新的数据
|
||||||
|
*/
|
||||||
|
UpdetateTTSHistory(ttsId: string, data: tts.TTSModel): tts.TTSModel {
|
||||||
|
try {
|
||||||
|
this.transaction(() => {
|
||||||
|
let tts = this.realm.objectForPrimaryKey<TTSModel>('TTSModel', ttsId)
|
||||||
|
if (tts == null) {
|
||||||
|
throw new Error('没有找到指定ID的TTS历史记录,请检查')
|
||||||
|
}
|
||||||
|
for (let key in data) {
|
||||||
|
tts[key] = data[key]
|
||||||
|
}
|
||||||
|
tts.updateTime = new Date()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取修改后的数据返回
|
||||||
|
let res = this.GetTTSHistoryById(ttsId)
|
||||||
|
return res
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS历史记录
|
||||||
|
* @param ttsId tts历史记录ID
|
||||||
|
*/
|
||||||
|
DeleteTTSHistory(ttsId: string): void {
|
||||||
|
try {
|
||||||
|
this.transaction(() => {
|
||||||
|
let tts = this.realm.objectForPrimaryKey<TTSModel>('TTSModel', ttsId)
|
||||||
|
if (tts == null) {
|
||||||
|
throw new Error('没有找到指定ID的TTS历史记录,请检查')
|
||||||
|
}
|
||||||
|
this.realm.delete(tts)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -144,7 +144,7 @@ if (!app.isPackaged) {
|
|||||||
|
|
||||||
define['remotemj_api'] = 'https://api.laitool.net/'
|
define['remotemj_api'] = 'https://api.laitool.net/'
|
||||||
define['serverUrl'] = 'http://lapi.laitool.cn'
|
define['serverUrl'] = 'http://lapi.laitool.cn'
|
||||||
define['hkServerUrl'] = 'https://api.laitool.cc/'
|
define['hkServerUrl'] = 'https://laitool.net/'
|
||||||
define['bakServerUrl'] = 'https://bakapi.laitool.cc/'
|
define['bakServerUrl'] = 'https://laitool.net/'
|
||||||
define['API'] = 'f85d39ed5a40fd09966f13f12b6cf0f0'
|
define['API'] = 'f85d39ed5a40fd09966f13f12b6cf0f0'
|
||||||
export { define }
|
export { define }
|
||||||
|
|||||||
@ -283,7 +283,10 @@ export const DEFINE_STRING = {
|
|||||||
TTS: {
|
TTS: {
|
||||||
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
|
GET_TTS_CONFIG: 'GET_TTS_CONFIG',
|
||||||
GENERATE_AUDIO: 'GENERATE_AUDIO',
|
GENERATE_AUDIO: 'GENERATE_AUDIO',
|
||||||
SAVE_TTS_CONFIG: 'SAVE_TTS_CONFIG'
|
SAVE_TTS_CONFIG: 'SAVE_TTS_CONFIG',
|
||||||
|
GENERATE_SRT: "GENERATE_SRT",
|
||||||
|
GET_TTS_HISTORY_DATA: 'GET_TTS_HISTORY_DATA',
|
||||||
|
DELETE_TTS_HISTORY: 'DELETE_TTS_HISTORY',
|
||||||
},
|
},
|
||||||
WRITE: {
|
WRITE: {
|
||||||
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
|
GET_WRITE_CONFIG: 'GET_WRITE_CONFIG',
|
||||||
|
|||||||
5
src/define/enum/tts.ts
Normal file
5
src/define/enum/tts.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
export enum TTSSelectModel {
|
||||||
|
// edge-tts
|
||||||
|
edgeTTS = 'edge-tts',
|
||||||
|
}
|
||||||
@ -275,6 +275,14 @@ export const gptDefine = {
|
|||||||
{
|
{
|
||||||
label: 'gpt-4',
|
label: 'gpt-4',
|
||||||
value: 'gpt-4'
|
value: 'gpt-4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'deepseek-chat',
|
||||||
|
value: 'deepseek-chat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'deepseek-coder',
|
||||||
|
value: 'deepseek-coder'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@ -115,10 +115,9 @@ export class TagDefine {
|
|||||||
let property = value[1]
|
let property = value[1]
|
||||||
value = JSON.parse(value[0])
|
value = JSON.parse(value[0])
|
||||||
let tmp_key = uuidv4()
|
let tmp_key = uuidv4()
|
||||||
|
|
||||||
// 特殊操作。为角色和场景的时候,需要copy图片
|
// 特殊操作。为角色和场景的时候,需要copy图片
|
||||||
if (property == 'character_tags' || property == 'scene_tags' || property == 'style_tags') {
|
if (property == 'character_tags' || property == 'scene_tags' || property == 'style_tags') {
|
||||||
let show_image = value.show_image
|
let show_image = value.show_image ? value.show_image.split('?t')[0] : null
|
||||||
if (show_image && show_image != '') {
|
if (show_image && show_image != '') {
|
||||||
let file_name = `c_s/${value.key ? value.key : tmp_key}.png`
|
let file_name = `c_s/${value.key ? value.key : tmp_key}.png`
|
||||||
let new_image_path = path.join(define.image_path, file_name)
|
let new_image_path = path.join(define.image_path, file_name)
|
||||||
@ -129,7 +128,6 @@ export class TagDefine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取自定义的GPT数据
|
// 获取自定义的GPT数据
|
||||||
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'))
|
let tag_setting = JSON.parse(await fspromises.readFile(define.tag_setting, 'utf-8'))
|
||||||
let tag = get(tag_setting, property, [])
|
let tag = get(tag_setting, property, [])
|
||||||
|
|||||||
@ -1,40 +1,39 @@
|
|||||||
import { ipcMain } from "electron";
|
import { ipcMain } from 'electron'
|
||||||
import { DEFINE_STRING } from '../../define/define_string'
|
import { DEFINE_STRING } from '../../define/define_string'
|
||||||
import { CheckFileOrDirExist } from "../../define/Tools/file";
|
import { CheckFileOrDirExist } from '../../define/Tools/file'
|
||||||
import { errorMessage, successMessage } from "../Public/generalTools";
|
import { errorMessage, successMessage } from '../Public/generalTools'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
const { shell } = require('electron')
|
const { shell } = require('electron')
|
||||||
|
|
||||||
function SystemIpc() {
|
function SystemIpc() {
|
||||||
|
// 打开指定的文件
|
||||||
|
ipcMain.on(DEFINE_STRING.SYSTEM.OPEN_FILE, async (event, value) => {
|
||||||
|
await shell.openPath(value)
|
||||||
|
})
|
||||||
|
|
||||||
// 打开指定的文件
|
// 试用文件资源打开指定的文件夹
|
||||||
ipcMain.on(DEFINE_STRING.SYSTEM.OPEN_FILE, async (event, value) => {
|
ipcMain.handle(DEFINE_STRING.OPEN_FOLDER, async (event, value) => {
|
||||||
await shell.openPath(value);
|
try {
|
||||||
});
|
let openFolder = null
|
||||||
|
if (value.baseProject) {
|
||||||
// 试用文件资源打开指定的文件夹
|
openFolder = path.join(global.config.project_path, value.folderPath)
|
||||||
ipcMain.handle(DEFINE_STRING.OPEN_FOLDER, async (event, value) => {
|
}
|
||||||
try {
|
if (value.dirFloder) {
|
||||||
let openFolder = null
|
openFolder = path.dirname(value.folderPath)
|
||||||
if (value.baseProject) {
|
}
|
||||||
openFolder = path.join(global.config.project_path, value.folderPath)
|
if (!openFolder) {
|
||||||
}
|
openFolder = value.folderPath
|
||||||
else {
|
}
|
||||||
openFolder = value.folderPath
|
// 判断文件夹是不是存在
|
||||||
}
|
let isExist = await CheckFileOrDirExist(openFolder)
|
||||||
// 判断文件夹是不是存在
|
if (!isExist) {
|
||||||
let isExist = await CheckFileOrDirExist(openFolder)
|
throw new Error('文件夹不存在,请检查')
|
||||||
if (!isExist) {
|
}
|
||||||
throw new Error("文件夹不存在,请检查")
|
shell.openPath(openFolder)
|
||||||
}
|
return successMessage(null, '打开成功')
|
||||||
shell.openPath(openFolder)
|
} catch (error) {
|
||||||
return successMessage(null, '打开成功');
|
return errorMessage('打开文件夹错误,错误信息如下:' + error.message, 'SystemIpc_OPEN_FOLDER')
|
||||||
} catch (error) {
|
}
|
||||||
return errorMessage("打开文件夹错误,错误信息如下:" + error.message, "SystemIpc_OPEN_FOLDER")
|
})
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
export {
|
export { SystemIpc }
|
||||||
SystemIpc
|
|
||||||
}
|
|
||||||
|
|||||||
@ -6,11 +6,35 @@ const tts = new TTS()
|
|||||||
|
|
||||||
export function TTSIpc() {
|
export function TTSIpc() {
|
||||||
// 获取当前的TTS配置数据
|
// 获取当前的TTS配置数据
|
||||||
ipcMain.handle(DEFINE_STRING.TTS.GET_TTS_CONFIG, async () => tts.GetTTSCOnfig())
|
ipcMain.handle(DEFINE_STRING.TTS.GET_TTS_CONFIG, async () => await tts.GetTTSCOnfig())
|
||||||
|
|
||||||
// 保存TTS配置
|
// 保存TTS配置
|
||||||
ipcMain.handle(DEFINE_STRING.TTS.SAVE_TTS_CONFIG, async (event, data) => tts.SaveTTSConfig(data))
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.TTS.SAVE_TTS_CONFIG,
|
||||||
|
async (event, data) => await tts.SaveTTSConfig(data)
|
||||||
|
)
|
||||||
|
|
||||||
// 生成音频
|
// 生成音频
|
||||||
ipcMain.handle(DEFINE_STRING.TTS.GENERATE_AUDIO, async (event, text) => tts.GenerateAudio(text))
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.TTS.GENERATE_AUDIO,
|
||||||
|
async (event, text) => await tts.GenerateAudio(text)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 生成SRT字幕文件
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.TTS.GENERATE_SRT,
|
||||||
|
async (event, ttsId) => await tts.GenerateSRT(ttsId)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 删除配音历史记录
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.TTS.DELETE_TTS_HISTORY,
|
||||||
|
async (event, ttsId) => await tts.DeleteTTSHistory(ttsId)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取配音的历史记录
|
||||||
|
ipcMain.handle(
|
||||||
|
DEFINE_STRING.TTS.GET_TTS_HISTORY_DATA,
|
||||||
|
async (event, queryCondition) => await tts.GetTTSHistoryData(queryCondition)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export class ClipDraft {
|
|||||||
this.one_duration_time = 5000000;
|
this.one_duration_time = 5000000;
|
||||||
this.text_end_time = 0;
|
this.text_end_time = 0;
|
||||||
this.iamge_end_time = 0;
|
this.iamge_end_time = 0;
|
||||||
this.dubbing_emd_time = 0;
|
this.TTS_emd_time = 0;
|
||||||
this.draft_duration_time = 0;
|
this.draft_duration_time = 0;
|
||||||
this.global = global;
|
this.global = global;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@ -484,7 +484,7 @@ export class ClipDraft {
|
|||||||
/**
|
/**
|
||||||
* 添加配音
|
* 添加配音
|
||||||
*/
|
*/
|
||||||
async AddDubbingMusic(musicPath) {
|
async AddTTSMusic(musicPath) {
|
||||||
// 添加speeds
|
// 添加speeds
|
||||||
let speeds = await this.AddSpeeds();
|
let speeds = await this.AddSpeeds();
|
||||||
this.draft_json.materials.speeds.push(speeds);
|
this.draft_json.materials.speeds.push(speeds);
|
||||||
@ -820,7 +820,7 @@ export class ClipDraft {
|
|||||||
await this.LoadDraftJson();
|
await this.LoadDraftJson();
|
||||||
await this.AddAllImageToTracks();
|
await this.AddAllImageToTracks();
|
||||||
await this.AddAllTextToTrack();
|
await this.AddAllTextToTrack();
|
||||||
await this.AddDubbingMusic(path.normalize(this.value[1].audio_path));
|
await this.AddTTSMusic(path.normalize(this.value[1].audio_path));
|
||||||
if (this.value[1].background_music != "" && this.value[1].background_music != undefined && this.value[1].background_music != null) {
|
if (this.value[1].background_music != "" && this.value[1].background_music != undefined && this.value[1].background_music != null) {
|
||||||
await this.AddRandomBackfroundMusic(this.value[1].background_music);
|
await this.AddRandomBackfroundMusic(this.value[1].background_music);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,14 +34,16 @@ export class TaskManager {
|
|||||||
this.mjOpt = new MJOpt();
|
this.mjOpt = new MJOpt();
|
||||||
}
|
}
|
||||||
|
|
||||||
async InitService() {
|
async InitService(getMJsetting = false) {
|
||||||
if (!this.softwareService) {
|
if (!this.softwareService) {
|
||||||
this.softwareService = await SoftwareService.getInstance();
|
this.softwareService = await SoftwareService.getInstance();
|
||||||
}
|
}
|
||||||
if (!this.bookBackTaskListService) {
|
if (!this.bookBackTaskListService) {
|
||||||
this.bookBackTaskListService = await BookBackTaskListService.getInstance();
|
this.bookBackTaskListService = await BookBackTaskListService.getInstance();
|
||||||
}
|
}
|
||||||
await this.mjOpt.InitService();
|
if (getMJsetting) {
|
||||||
|
await this.mjOpt.InitService();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetGlobalConfig() {
|
async GetGlobalConfig() {
|
||||||
@ -117,6 +119,7 @@ export class TaskManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.spaceTime = 5000;
|
this.spaceTime = 5000;
|
||||||
|
await this.InitService(true);
|
||||||
//循环添加任务
|
//循环添加任务
|
||||||
for (let index = 0; index < tasks.data.length; index++) {
|
for (let index = 0; index < tasks.data.length; index++) {
|
||||||
const element = tasks.data[index];
|
const element = tasks.data[index];
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
import { errorMessage, successMessage } from '../Public/generalTools'
|
import { errorMessage, successMessage } from '../Public/generalTools'
|
||||||
import { SoftwareService } from '../../define/db/service/SoftWare/softwareService'
|
import { SoftwareService } from '../../define/db/service/SoftWare/softwareService'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
import { define } from '../../define/define'
|
import { define } from '../../define/define'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { ValidateJson } from '../../define/Tools/validate'
|
import { ValidateJson } from '../../define/Tools/validate'
|
||||||
|
import { CheckFileOrDirExist, CheckFolderExistsOrCreate, DeleteFolderAllFile } from '../../define/Tools/file'
|
||||||
|
import { TTSSelectModel } from '../../define/enum/tts'
|
||||||
const { EdgeTTS } = require('node-edge-tts')
|
const { EdgeTTS } = require('node-edge-tts')
|
||||||
|
const { v4: uuidv4 } = require('uuid')
|
||||||
|
import { TTSService } from '../../define/db/tts/ttsService'
|
||||||
|
import { tts } from '../../model/tts'
|
||||||
|
import { GeneralResponse } from '../../model/generalResponse'
|
||||||
|
|
||||||
export class TTS {
|
export class TTS {
|
||||||
softService: SoftwareService
|
softService: SoftwareService
|
||||||
|
ttsService: TTSService
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
@ -18,8 +26,14 @@ export class TTS {
|
|||||||
if (!this.softService) {
|
if (!this.softService) {
|
||||||
this.softService = await SoftwareService.getInstance()
|
this.softService = await SoftwareService.getInstance()
|
||||||
}
|
}
|
||||||
|
if (!this.ttsService) {
|
||||||
|
this.ttsService = await TTSService.getInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region 设置相关
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化TTS设置
|
* 初始化TTS设置
|
||||||
*/
|
*/
|
||||||
@ -80,6 +94,9 @@ export class TTS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 合成音频相关
|
||||||
/**
|
/**
|
||||||
* 生成音频
|
* 生成音频
|
||||||
* @param text 要生成的文本
|
* @param text 要生成的文本
|
||||||
@ -91,18 +108,43 @@ export class TTS {
|
|||||||
if (ttsSetting.code === 0) {
|
if (ttsSetting.code === 0) {
|
||||||
return ttsSetting
|
return ttsSetting
|
||||||
}
|
}
|
||||||
let res
|
let res = undefined
|
||||||
|
|
||||||
let audioPath = path.join(define.project_path, 'audio.mp3')
|
// 生成对应的ID
|
||||||
let selectModel = ttsSetting.data.selectModel
|
let thisId = uuidv4()
|
||||||
|
|
||||||
|
// 讲text写道本地
|
||||||
|
let textPath = path.join(define.tts_path, `${thisId}/${thisId}.txt`)
|
||||||
|
await CheckFolderExistsOrCreate(path.dirname(textPath))
|
||||||
|
await fs.promises.writeFile(textPath, text, 'utf-8')
|
||||||
|
|
||||||
|
let audioPath = path.join(define.tts_path, `${thisId}/${thisId}.mp3`)
|
||||||
|
let selectModel = ttsSetting.data.selectModel as TTSSelectModel
|
||||||
|
|
||||||
|
let hasSrt = true
|
||||||
switch (selectModel) {
|
switch (selectModel) {
|
||||||
case 'edge-tts':
|
case TTSSelectModel.edgeTTS:
|
||||||
res = await this.GenerateAudioByEdgeTTS(text, ttsSetting.data.edgeTTS)
|
hasSrt = ttsSetting.data.edgeTTS.saveSubtitles
|
||||||
|
res = await this.GenerateAudioByEdgeTTS(text, ttsSetting.data.edgeTTS, audioPath)
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('未知的TTS模式')
|
throw new Error('未知的TTS模式')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res == undefined) {
|
||||||
|
throw new Error('生成音频失败,未知错误')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这边返回成功,保存配音历史
|
||||||
|
this.ttsService.AddTTSHistory({
|
||||||
|
name: text.substring(0, 10),
|
||||||
|
ttsPath: res.mp3Path ? path.relative(define.tts_path, res.mp3Path) : null,
|
||||||
|
hasSrt: hasSrt,
|
||||||
|
selectModel: selectModel,
|
||||||
|
srtJsonPath: res.srtJsonPath ? path.relative(define.tts_path, res.srtJsonPath) : null,
|
||||||
|
id: thisId,
|
||||||
|
textPath: textPath ? path.relative(define.tts_path, textPath) : null
|
||||||
|
})
|
||||||
return res
|
return res
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage('生成音频失败,错误信息如下:' + error.toString(), 'TTS_GenerateAudio')
|
return errorMessage('生成音频失败,错误信息如下:' + error.toString(), 'TTS_GenerateAudio')
|
||||||
@ -110,35 +152,175 @@ export class TTS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用EdgeTTS生成音频的方法
|
* 使用EdgeTTS生成音频的方法,生成完成,返回生成的音频路径
|
||||||
* @param text 要生成的文本
|
* @param text 要生成的文本
|
||||||
* @param edgeTTS edgetts的设置
|
* @param edgeTTS edgetts的设置
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
async GenerateAudioByEdgeTTS(text: string, edgeTTS: TTSSettingModel.EdgeTTSSetting, mp3Path: string) {
|
||||||
async GenerateAudioByEdgeTTS(text: string, edgeTTS: TTSSettingModel.EdgeTTSSetting) {
|
|
||||||
try {
|
try {
|
||||||
const tts = new EdgeTTS({
|
const tts = new EdgeTTS({
|
||||||
voice: edgeTTS.value,
|
voice: edgeTTS.value,
|
||||||
lang: edgeTTS.lang,
|
lang: edgeTTS.lang,
|
||||||
outputFormat: 'audio-24khz-96kbitrate-mono-mp3',
|
outputFormat: 'audio-24khz-96kbitrate-mono-mp3',
|
||||||
saveSubtitles: edgeTTS.saveSubtitles,
|
saveSubtitles: true,
|
||||||
pitch: `${edgeTTS.pitch}%`,
|
pitch: `${edgeTTS.pitch}%`,
|
||||||
rate: `${edgeTTS.rate}%`,
|
rate: `${edgeTTS.rate}%`,
|
||||||
volumn: `${edgeTTS.volumn}%`
|
volumn: `${edgeTTS.volumn}%`
|
||||||
})
|
})
|
||||||
let ttsRes = await tts.ttsPromise(text, 'C:\\Users\\27698\\Desktop\\audio.mp3')
|
let ttsRes = await tts.ttsPromise(text, mp3Path)
|
||||||
console.log(ttsRes)
|
console.log(ttsRes)
|
||||||
return successMessage(
|
return {
|
||||||
'C:\\Users\\27698\\Desktop\\audio.mp3',
|
mp3Path: mp3Path,
|
||||||
'生成音频成功',
|
srtJsonPath: mp3Path + '.json'
|
||||||
'TTS_GenerateAudioByEdgeTTS'
|
};
|
||||||
)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorMessage(
|
throw error
|
||||||
'生成音频失败,错误信息如下:' + error.toString(),
|
|
||||||
'TTS_GenerateAudioByEdgeTTS'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 合成字幕
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过配音历史ID生成字幕
|
||||||
|
* @param ttsId 配音历史ID
|
||||||
|
*/
|
||||||
|
async GenerateSRT(ttsId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
// 获取配音历史
|
||||||
|
let ttsHistory = this.ttsService.GetTTSHistoryById(ttsId)
|
||||||
|
let selectModel = ttsHistory.selectModel as TTSSelectModel
|
||||||
|
let res = undefined
|
||||||
|
switch (selectModel) {
|
||||||
|
case TTSSelectModel.edgeTTS:
|
||||||
|
res = await this.GenerateSRTByEdgeTTS(ttsHistory)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error('未知的TTS模式')
|
||||||
|
}
|
||||||
|
// 这边重新请求,返回一个完整的
|
||||||
|
let ttsHistoryData = this.ttsService.GetTTSHistoryById(ttsId)
|
||||||
|
return successMessage(ttsHistoryData, '生成字幕成功', 'TTS_GenerateSRT')
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage('生成字幕失败,错误信息如下:' + error.toString(), 'TTS_GenerateSRT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async GenerateSRTByEdgeTTS(ttsHistory: tts.TTSModel) {
|
||||||
|
try {
|
||||||
|
// 一系列的检查文件是不是存在
|
||||||
|
if (isEmpty(ttsHistory.textPath)) {
|
||||||
|
throw new Error('生成字幕失败,文本文件不存在')
|
||||||
|
}
|
||||||
|
if (isEmpty(ttsHistory.srtJsonPath)) {
|
||||||
|
throw new Error('生成字幕失败,srtJson文件不存在')
|
||||||
|
}
|
||||||
|
let checkFileExist = await CheckFileOrDirExist(ttsHistory.textPath)
|
||||||
|
if (!checkFileExist) {
|
||||||
|
throw new Error('生成字幕失败,文本文件不存在')
|
||||||
|
}
|
||||||
|
checkFileExist = await CheckFileOrDirExist(ttsHistory.srtJsonPath)
|
||||||
|
if (!checkFileExist) {
|
||||||
|
throw new Error('生成字幕失败,srtJson文件不存在')
|
||||||
|
}
|
||||||
|
let text = await fs.promises.readFile(ttsHistory.textPath, 'utf-8');
|
||||||
|
let srtJson = JSON.parse(await fs.promises.readFile(ttsHistory.srtJsonPath, 'utf-8'));
|
||||||
|
|
||||||
|
// 根据标点符号和换行符分割文案
|
||||||
|
// 更新后的正则表达式,匹配所有中文和英文的标点符号以及换行符
|
||||||
|
const parts = text.match(
|
||||||
|
/[^,。!?;:“”()《》,.!?;:"()<>$$$$\n]+[,。!?;:“”()《》,.!?;:"()<>$$$$\n]*/g
|
||||||
|
);
|
||||||
|
// 初始化 SRT 内容
|
||||||
|
let srtContent = "";
|
||||||
|
let index = 1;
|
||||||
|
|
||||||
|
// 函数用于去掉文本末尾的标点符号
|
||||||
|
const removeTrailingPunctuation = (text: string) => {
|
||||||
|
return text.replace(/[\s,。!?;:“”()《》,.!?;:"()<>$$$$]+$/, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 配对时间轴和文案分段
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
const part = parts[i];
|
||||||
|
let startTime =
|
||||||
|
srtJson[i * 2]?.start || srtJson[srtJson.length - 1].start;
|
||||||
|
let endTime =
|
||||||
|
srtJson[i * 2 + 1]?.end || srtJson[srtJson.length - 1].end;
|
||||||
|
|
||||||
|
// 去掉文案末尾的标点符号
|
||||||
|
const cleanedPart = removeTrailingPunctuation(part.trim());
|
||||||
|
|
||||||
|
// 将时间格式化为 SRT 格式
|
||||||
|
const formatTime = (ms) => {
|
||||||
|
const date = new Date(ms);
|
||||||
|
const hours = String(date.getUTCHours()).padStart(2, "0");
|
||||||
|
const minutes = String(date.getUTCMinutes()).padStart(2, "0");
|
||||||
|
const seconds = String(date.getUTCSeconds()).padStart(2, "0");
|
||||||
|
const milliseconds = String(date.getUTCMilliseconds()).padStart(3, "0");
|
||||||
|
return `${hours}:${minutes}:${seconds},${milliseconds}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成 SRT 片段
|
||||||
|
srtContent += `${index}\n${formatTime(startTime)} --> ${formatTime(
|
||||||
|
endTime
|
||||||
|
)}\n${cleanedPart}\n\n`;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(srtContent);
|
||||||
|
// 将数据写入srt文件
|
||||||
|
let srtPath = path.join(define.tts_path, `${ttsHistory.id}/${ttsHistory.id}.srt`)
|
||||||
|
await fs.promises.writeFile(srtPath, srtContent, 'utf-8')
|
||||||
|
// 更新配音历史
|
||||||
|
this.ttsService.UpdetateTTSHistory(ttsHistory.id, { srtPath: path.relative(define.tts_path, srtPath) })
|
||||||
|
// 返回成功
|
||||||
|
return srtPath;
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 配音历史记录相关
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配音的历史记录
|
||||||
|
* @param queryCondition 查询的条件
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async GetTTSHistoryData(queryCondition: tts.TTSHistoryQueryParams): Promise<GeneralResponse.SuccessItem | GeneralResponse.ErrorItem> {
|
||||||
|
try {
|
||||||
|
await this.InitService()
|
||||||
|
let res = this.ttsService.GetTTSHistory(queryCondition);
|
||||||
|
return successMessage(res, "获取配音历史任务成功", 'TTS_GetTTSHistoryData')
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage('查询配音历史失败,错误信息:' + error.message, 'TTS_GetTTSHistoryData')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除配音历史
|
||||||
|
* @param ttsId 要删除的ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async DeleteTTSHistory(ttsId: string): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
|
||||||
|
try {
|
||||||
|
await this.InitService()
|
||||||
|
// 先删除数据库中数据,然后删除文件
|
||||||
|
let ttsHistory = this.ttsService.GetTTSHistoryById(ttsId)
|
||||||
|
|
||||||
|
this.ttsService.DeleteTTSHistory(ttsId);
|
||||||
|
// 删除文件
|
||||||
|
let ttsDir = path.join(define.tts_path, ttsId)
|
||||||
|
await DeleteFolderAllFile(ttsDir, true);
|
||||||
|
return successMessage(ttsId, '删除配音历史成功', 'TTS_DeleteTTSHistory')
|
||||||
|
} catch (error) {
|
||||||
|
return errorMessage('删除配音历史失败,错误信息:' + error.message, 'TTS_DeleteTTSHistory')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/model/tts.d.ts
vendored
Normal file
30
src/model/tts.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { TTSSelectModel } from "../define/enum/tts"
|
||||||
|
|
||||||
|
declare namespace tts {
|
||||||
|
type TTSHistoryQueryParams = {
|
||||||
|
page?: number // 当前页数
|
||||||
|
pageSize?: number // 每页显示的数量
|
||||||
|
name?: string // 配音名称
|
||||||
|
id?: string // 配音ID
|
||||||
|
}
|
||||||
|
|
||||||
|
type TTSModel = {
|
||||||
|
id?: string
|
||||||
|
no?: number
|
||||||
|
textPath?: string // 保存生成文本的地址
|
||||||
|
name?: string // 一把就是配音的前几个字
|
||||||
|
ttsPath?: string // 生成的配置文件地址
|
||||||
|
srtPath?: string // 生成的SRT地址
|
||||||
|
selectModel?: TTSSelectModel // 选择模式
|
||||||
|
hasSrt?: boolean
|
||||||
|
srtJsonPath?: string
|
||||||
|
createTime?: Date
|
||||||
|
updateTime?: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
type TTSModelRes = {
|
||||||
|
ttsList: TTSModel[]
|
||||||
|
ttsCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,6 +9,17 @@ const tts = {
|
|||||||
SaveTTSConfig: async (data) => await ipcRenderer.invoke(DEFINE_STRING.TTS.SAVE_TTS_CONFIG, data),
|
SaveTTSConfig: async (data) => await ipcRenderer.invoke(DEFINE_STRING.TTS.SAVE_TTS_CONFIG, data),
|
||||||
|
|
||||||
// 生成音频
|
// 生成音频
|
||||||
GenerateAudio: async (text) => await ipcRenderer.invoke(DEFINE_STRING.TTS.GENERATE_AUDIO, text)
|
GenerateAudio: async (text) => await ipcRenderer.invoke(DEFINE_STRING.TTS.GENERATE_AUDIO, text),
|
||||||
|
|
||||||
|
// 生成SRT字幕
|
||||||
|
GenerateSrt: async (text) => await ipcRenderer.invoke(DEFINE_STRING.TTS.GENERATE_SRT, text),
|
||||||
|
|
||||||
|
// 删除配音历史记录
|
||||||
|
DeleteTTSHistory: async (ttsId) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.TTS.DELETE_TTS_HISTORY, ttsId),
|
||||||
|
|
||||||
|
// 获取生成音频的历史记录
|
||||||
|
GetTTSHistoryData: async (queryCondition) =>
|
||||||
|
await ipcRenderer.invoke(DEFINE_STRING.TTS.GET_TTS_HISTORY_DATA, queryCondition)
|
||||||
}
|
}
|
||||||
export { tts }
|
export { tts }
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
show-trigger
|
show-trigger
|
||||||
@collapse="collapsed = true"
|
@collapse="collapsed = true"
|
||||||
@expand="collapsed = false"
|
@expand="collapsed = false"
|
||||||
|
style="position: relative"
|
||||||
>
|
>
|
||||||
<n-menu
|
<n-menu
|
||||||
:collapsed="collapsed"
|
:collapsed="collapsed"
|
||||||
@ -18,7 +19,8 @@
|
|||||||
:options="menuOptions"
|
:options="menuOptions"
|
||||||
:render-icon="renderMenuIcon"
|
:render-icon="renderMenuIcon"
|
||||||
:expand-icon="expandIcon"
|
:expand-icon="expandIcon"
|
||||||
/>
|
>
|
||||||
|
</n-menu>
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
<n-layout-content content-style="padding: 20px 5px 5px 20px; height:100%">
|
<n-layout-content content-style="padding: 20px 5px 5px 20px; height:100%">
|
||||||
<!-- <Setting></Setting> -->
|
<!-- <Setting></Setting> -->
|
||||||
@ -52,7 +54,7 @@ import {
|
|||||||
DuplicateOutline,
|
DuplicateOutline,
|
||||||
GridOutline,
|
GridOutline,
|
||||||
RadioOutline,
|
RadioOutline,
|
||||||
BookOutline,
|
BookOutline
|
||||||
} from '@vicons/ionicons5'
|
} from '@vicons/ionicons5'
|
||||||
import CheckMachineId from '../Components/CheckMachineId.vue'
|
import CheckMachineId from '../Components/CheckMachineId.vue'
|
||||||
import { DEFINE_STRING } from '../../../../define/define_string'
|
import { DEFINE_STRING } from '../../../../define/define_string'
|
||||||
@ -242,7 +244,8 @@ export default defineComponent({
|
|||||||
{
|
{
|
||||||
to: {
|
to: {
|
||||||
name: 'gptCopywriting'
|
name: 'gptCopywriting'
|
||||||
}
|
},
|
||||||
|
class: 'router-link-a'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: () => '文案处理'
|
default: () => '文案处理'
|
||||||
@ -382,6 +385,36 @@ export default defineComponent({
|
|||||||
// ]
|
// ]
|
||||||
|
|
||||||
// },
|
// },
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'lai_api'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => 'API服务'
|
||||||
|
}
|
||||||
|
),
|
||||||
|
key: 'lai_api'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'TTS_Services'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '语音服务'
|
||||||
|
}
|
||||||
|
),
|
||||||
|
key: 'TTS_Services'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '设置',
|
label: '设置',
|
||||||
key: 'setting',
|
key: 'setting',
|
||||||
@ -453,39 +486,13 @@ export default defineComponent({
|
|||||||
key: 'mj_setting'
|
key: 'mj_setting'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
to: {
|
|
||||||
name: 'lai_api'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () => 'API服务'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
key: 'lai_api'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: () =>
|
|
||||||
h(
|
|
||||||
RouterLink,
|
|
||||||
{
|
|
||||||
to: {
|
|
||||||
name: 'TTS_Services'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () => '语音服务'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
key: 'TTS_Services'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function renderIcon(icon) {
|
||||||
|
return () => h(NIcon, null, { default: () => h(icon) })
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
renderMenuIcon,
|
renderMenuIcon,
|
||||||
menuOptions,
|
menuOptions,
|
||||||
|
|||||||
@ -185,7 +185,9 @@ export default defineComponent({
|
|||||||
chinese_prompt: characterData.value.chinese_prompt,
|
chinese_prompt: characterData.value.chinese_prompt,
|
||||||
prompt: characterData.value.prompt,
|
prompt: characterData.value.prompt,
|
||||||
image_url: characterData.value.image_url,
|
image_url: characterData.value.image_url,
|
||||||
show_image: characterData.value.show_image,
|
show_image: characterData.value.show_image
|
||||||
|
? characterData.value.show_image.split('?t')[0]
|
||||||
|
: null,
|
||||||
cref_cw: characterData.value.cref_cw,
|
cref_cw: characterData.value.cref_cw,
|
||||||
lora: characterData.value.lora,
|
lora: characterData.value.lora,
|
||||||
lora_weight: characterData.value.lora_weight
|
lora_weight: characterData.value.lora_weight
|
||||||
@ -194,6 +196,9 @@ export default defineComponent({
|
|||||||
characterData.value['children'] = children
|
characterData.value['children'] = children
|
||||||
console.log(characterData.value)
|
console.log(characterData.value)
|
||||||
characterData.value['type'] = 'character_main'
|
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(
|
await window.mj.SaveTagPropertyData(
|
||||||
[JSON.stringify(characterData.value), 'character_tags'],
|
[JSON.stringify(characterData.value), 'character_tags'],
|
||||||
|
|||||||
@ -26,11 +26,6 @@
|
|||||||
<n-form-item label="语调">
|
<n-form-item label="语调">
|
||||||
<n-input-number v-model:value="settingStore.ttsSetting.edgeTTS.pitch" :min="0" :max="100" />
|
<n-input-number v-model:value="settingStore.ttsSetting.edgeTTS.pitch" :min="0" :max="100" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="生成SRT">
|
|
||||||
<n-checkbox v-model:checked="settingStore.ttsSetting.edgeTTS.saveSubtitles">
|
|
||||||
复选框
|
|
||||||
</n-checkbox>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
</n-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
156
src/renderer/src/components/TTS/TTSHistory.vue
Normal file
156
src/renderer/src/components/TTS/TTSHistory.vue
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<div id="tts-history">
|
||||||
|
<n-data-table
|
||||||
|
remote
|
||||||
|
ref="table"
|
||||||
|
:columns="columns"
|
||||||
|
:data="data"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
:row-key="rowKey"
|
||||||
|
@update:page="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, defineComponent, onUnmounted, toRaw, reactive, h } from 'vue'
|
||||||
|
import { useMessage, NDataTable } from 'naive-ui'
|
||||||
|
import TTSHistoryAction from './TTSHistoryAction.vue'
|
||||||
|
import TTSHistoryShowPath from './TTSHistoryShowPath.vue'
|
||||||
|
|
||||||
|
let props = defineProps({
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let height = ref(props.height)
|
||||||
|
let data = ref([])
|
||||||
|
let message = useMessage()
|
||||||
|
let loading = ref(false)
|
||||||
|
let rowKey = (rowData) => {
|
||||||
|
return rowData.id
|
||||||
|
}
|
||||||
|
const pagination = reactive({
|
||||||
|
page: 0,
|
||||||
|
pageCount: 0,
|
||||||
|
pageSize: 20,
|
||||||
|
prefix({ itemCount }) {
|
||||||
|
return `Total is ${itemCount}.`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 加载的时候设置高度和滚动条
|
||||||
|
let div = document.getElementById('tts-history')
|
||||||
|
div.style.height = height.value - 70 + 'px'
|
||||||
|
div.style.overflow = 'auto'
|
||||||
|
await GetTTSHistoryData(pagination.page)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function GetTTSHistoryData(currentPage) {
|
||||||
|
// 这边加载数据
|
||||||
|
if (!loading.value) {
|
||||||
|
let res = await window.tts.GetTTSHistoryData({
|
||||||
|
page: currentPage,
|
||||||
|
pageSize: pagination.pageSize
|
||||||
|
})
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.value = res.data.ttsList
|
||||||
|
pagination.page = currentPage
|
||||||
|
pagination.pageCount = Math.ceil(res.data.ttsCount / pagination.pageSize)
|
||||||
|
pagination.itemCount = res.data.ttsCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handlePageChange(currentPage) {
|
||||||
|
await GetTTSHistoryData(currentPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUpdateRow(row, index) {
|
||||||
|
if (row == null) {
|
||||||
|
debugger
|
||||||
|
// data.value.splice(index, 1)
|
||||||
|
// 直接重新加载吧
|
||||||
|
await GetTTSHistoryData(pagination.page)
|
||||||
|
} else {
|
||||||
|
data.value[index] = row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let columns = ref([
|
||||||
|
{
|
||||||
|
title: 'No.',
|
||||||
|
key: 'no',
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名字',
|
||||||
|
key: 'name',
|
||||||
|
width: 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '配音地址',
|
||||||
|
key: 'ttsPath',
|
||||||
|
render(row, index) {
|
||||||
|
return h(TTSHistoryShowPath, {
|
||||||
|
text: row.ttsPath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '字幕地址',
|
||||||
|
key: 'srtPath',
|
||||||
|
render(row, index) {
|
||||||
|
return h(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
className: 'tts-path',
|
||||||
|
onClick: () => {
|
||||||
|
window.system.OpenFile(row.srtPath)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
row.srtPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 200,
|
||||||
|
render(row, index) {
|
||||||
|
return h('span', row.createTime.toLocaleString())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
fixed: 'right',
|
||||||
|
key: 'action',
|
||||||
|
width: 280,
|
||||||
|
render(row, index) {
|
||||||
|
return h(TTSHistoryAction, {
|
||||||
|
row: row,
|
||||||
|
index: index,
|
||||||
|
onUpdateRow: (data, dataIndex) => handleUpdateRow(data, dataIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.tts-path {
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tts-path:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
74
src/renderer/src/components/TTS/TTSHistoryAction.vue
Normal file
74
src/renderer/src/components/TTS/TTSHistoryAction.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<n-button
|
||||||
|
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||||
|
size="small"
|
||||||
|
style="margin-right: 5px"
|
||||||
|
@click="GenerateSrt"
|
||||||
|
>生成字幕</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||||
|
size="small"
|
||||||
|
style="margin-right: 5px"
|
||||||
|
@click="OpenFolder"
|
||||||
|
>打开文件夹</n-button
|
||||||
|
>
|
||||||
|
<n-button type="error" size="small" style="margin-right: 5px" @click="DeleteTTSHistory"
|
||||||
|
>删除</n-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useMessage, NButton } from 'naive-ui'
|
||||||
|
import { useSoftwareStore } from '../../../../stores/software'
|
||||||
|
let message = useMessage()
|
||||||
|
let softwareStore = useSoftwareStore()
|
||||||
|
let props = defineProps({
|
||||||
|
row: undefined,
|
||||||
|
index: undefined
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update-row'])
|
||||||
|
|
||||||
|
// 调用生成SRT的方法
|
||||||
|
async function GenerateSrt() {
|
||||||
|
let res = await window.tts.GenerateSrt(props.row.id)
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// 这边要处理返回的数据
|
||||||
|
emit('update-row', res.data, props.index)
|
||||||
|
message.success(res.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开对应的文件夹
|
||||||
|
*/
|
||||||
|
async function OpenFolder() {
|
||||||
|
let res = await window.system.OpenFolder({
|
||||||
|
folderPath: props.row.ttsPath,
|
||||||
|
baseProject: false,
|
||||||
|
dirFloder: true
|
||||||
|
})
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用删除数据的方法
|
||||||
|
async function DeleteTTSHistory() {
|
||||||
|
softwareStore.spin.spinning = true
|
||||||
|
softwareStore.spin.tip = '删除中...'
|
||||||
|
let res = await window.tts.DeleteTTSHistory(props.row.id)
|
||||||
|
if (res.code == 0) {
|
||||||
|
message.error(res.message)
|
||||||
|
} else {
|
||||||
|
// 这边要处理返回的数据
|
||||||
|
emit('update-row', null, props.index)
|
||||||
|
message.success(res.message)
|
||||||
|
}
|
||||||
|
softwareStore.spin.spinning = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
35
src/renderer/src/components/TTS/TTSHistoryShowPath.vue
Normal file
35
src/renderer/src/components/TTS/TTSHistoryShowPath.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<div @click="Click" class="show-text-ellipsis">{{ text }}</div>
|
||||||
|
</template>
|
||||||
|
<span>{{ text }}</span>
|
||||||
|
</n-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { NPopover } from 'naive-ui'
|
||||||
|
let props = defineProps({
|
||||||
|
text: undefined
|
||||||
|
})
|
||||||
|
let text = ref(props.text)
|
||||||
|
|
||||||
|
function Click() {
|
||||||
|
// window.open(text.value)
|
||||||
|
window.system.OpenFile(text.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.show-text-ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.show-text-ellipsis:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -103,6 +103,7 @@ import { useSoftwareStore } from '../../../../stores/software'
|
|||||||
import { AddCircleOutline } from '@vicons/ionicons5'
|
import { AddCircleOutline } from '@vicons/ionicons5'
|
||||||
import InputDialogContent from '../Original/Components/InputDialogContent.vue'
|
import InputDialogContent from '../Original/Components/InputDialogContent.vue'
|
||||||
import { useSettingStore } from '../../../../stores/setting'
|
import { useSettingStore } from '../../../../stores/setting'
|
||||||
|
import TTSHistory from './TTSHistory.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -116,7 +117,8 @@ export default defineComponent({
|
|||||||
NPopover,
|
NPopover,
|
||||||
AddCircleOutline,
|
AddCircleOutline,
|
||||||
NIcon,
|
NIcon,
|
||||||
InputDialogContent
|
InputDialogContent,
|
||||||
|
TTSHistory
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
@ -259,6 +261,7 @@ export default defineComponent({
|
|||||||
softwareStore.spin.spinning = true
|
softwareStore.spin.spinning = true
|
||||||
softwareStore.spin.tip = '正在合成音频,请稍等...'
|
softwareStore.spin.tip = '正在合成音频,请稍等...'
|
||||||
|
|
||||||
|
// 保存配置信息
|
||||||
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
|
let saveRes = await window.tts.SaveTTSConfig(toRaw(settingStore.ttsSetting))
|
||||||
if (saveRes.code == 0) {
|
if (saveRes.code == 0) {
|
||||||
softwareStore.spin.spinning = false
|
softwareStore.spin.spinning = false
|
||||||
@ -266,16 +269,32 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开始真正的合成音频
|
||||||
let generateRes = await window.tts.GenerateAudio(text.value)
|
let generateRes = await window.tts.GenerateAudio(text.value)
|
||||||
if (generateRes.code == 0) {
|
if (generateRes.code == 0) {
|
||||||
softwareStore.spin.spinning = false
|
softwareStore.spin.spinning = false
|
||||||
message.error(generateRes.message)
|
message.error(generateRes.message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
audioUrl.value = generateRes.data
|
debugger
|
||||||
|
audioUrl.value = generateRes.mp3Path
|
||||||
softwareStore.spin.spinning = false
|
softwareStore.spin.spinning = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 显示配音的历史记录
|
||||||
|
function ShowHistory() {
|
||||||
|
let dialogWidth = window.innerWidth * 0.8
|
||||||
|
let dialogHeight = window.innerHeight * 0.9
|
||||||
|
dialog.create({
|
||||||
|
title: '配音历史记录',
|
||||||
|
showIcon: false,
|
||||||
|
closeOnEsc: false,
|
||||||
|
content: () => h(TTSHistory, { height: dialogHeight }),
|
||||||
|
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px;matgin-right: 0px`,
|
||||||
|
maskClosable: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
azurettsRef,
|
azurettsRef,
|
||||||
@ -284,6 +303,7 @@ export default defineComponent({
|
|||||||
writeSetting,
|
writeSetting,
|
||||||
softwareStore,
|
softwareStore,
|
||||||
ModifySplitChar,
|
ModifySplitChar,
|
||||||
|
ShowHistory,
|
||||||
SaveTTSConfig,
|
SaveTTSConfig,
|
||||||
FormatWord,
|
FormatWord,
|
||||||
ClearText,
|
ClearText,
|
||||||
|
|||||||
@ -43,6 +43,7 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
async GetComponentSize() {
|
async GetComponentSize() {
|
||||||
debugger
|
debugger
|
||||||
if (this.componentSize.length == 0) {
|
if (this.componentSize.length == 0) {
|
||||||
|
//@ts-ignore
|
||||||
let res = await window.setting.GetComponentSize()
|
let res = await window.setting.GetComponentSize()
|
||||||
this.componentSize = res.data
|
this.componentSize = res.data
|
||||||
}
|
}
|
||||||
@ -54,6 +55,7 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
// 将当前的software数据保存到数据库中
|
// 将当前的software数据保存到数据库中
|
||||||
async SaveSoftware() {
|
async SaveSoftware() {
|
||||||
// 保存数据
|
// 保存数据
|
||||||
|
// @ts-ignore
|
||||||
return await window.setting.SaveSoftWareSetting(JSON.parse(JSON.stringify(this.softWare)))
|
return await window.setting.SaveSoftWareSetting(JSON.parse(JSON.stringify(this.softWare)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user