LaiTool V3.0.1-preview.5

This commit is contained in:
lq1405 2024-08-12 16:26:08 +08:00
parent f64c7ad677
commit e85b0a986d
37 changed files with 979 additions and 1399 deletions

1
.gitignore vendored
View File

@ -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
View File

@ -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"

View File

@ -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.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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'

View File

@ -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')

View File

@ -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'

View File

@ -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
View 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'
}
}

View 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
}
}
}

View 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
}
}
}

View File

@ -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 }

View File

@ -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
View File

@ -0,0 +1,5 @@
export enum TTSSelectModel {
// edge-tts
edgeTTS = 'edge-tts',
}

View File

@ -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'
} }
], ],

View File

@ -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, [])

View File

@ -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
}

View File

@ -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)
)
} }

View File

@ -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);
} }

View File

@ -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];

View File

@ -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
View 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
}
}

View File

@ -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 }

View File

@ -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,

View File

@ -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'],

View File

@ -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>

View 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>

View 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>

View 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>

View File

@ -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,

View File

@ -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)))
} }