添加文案处理的功能
This commit is contained in:
@@ -6,7 +6,10 @@
|
||||
<n-message-provider>
|
||||
<n-dialog-provider>
|
||||
<n-notification-provider>
|
||||
<RouterView></RouterView>
|
||||
<n-spin :show="softwareStore.spin.spinning">
|
||||
<RouterView></RouterView>
|
||||
<template #description> {{ softwareStore.spin.tip }} </template>
|
||||
</n-spin>
|
||||
</n-notification-provider>
|
||||
</n-dialog-provider>
|
||||
</n-message-provider>
|
||||
@@ -22,9 +25,11 @@ import {
|
||||
NDialogProvider,
|
||||
NConfigProvider,
|
||||
darkTheme,
|
||||
NNotificationProvider
|
||||
NNotificationProvider,
|
||||
NSpin
|
||||
} from 'naive-ui'
|
||||
import { useSoftwareStore } from '../../stores/software'
|
||||
import { SoftColor } from '../../define/enum/softwareEnum'
|
||||
|
||||
hljs.registerLanguage('javascript', javascript)
|
||||
export default defineComponent({
|
||||
@@ -32,12 +37,14 @@ export default defineComponent({
|
||||
NConfigProvider,
|
||||
NDialogProvider,
|
||||
NMessageProvider,
|
||||
NNotificationProvider
|
||||
NNotificationProvider,
|
||||
NSpin
|
||||
},
|
||||
setup() {
|
||||
let softwareStore = useSoftwareStore()
|
||||
|
||||
onMounted(async () => {
|
||||
softwareStore.SoftColor = SoftColor
|
||||
window.api.getSettingDafultData(async (value) => {
|
||||
await window.darkMode.toggle(value.theme)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div style="min-width: 800px; overflow: auto">
|
||||
<div style="width: 100%">
|
||||
<n-form ref="formRef" :model="formValue" inline label-placement="left">
|
||||
<n-form-item label="选择类型" path="gptType">
|
||||
<n-select
|
||||
style="width: 160px"
|
||||
v-model:value="formValue.gptType"
|
||||
:options="gptTypeOptions"
|
||||
placeholder="请选择提示词类型"
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item label="选择预设" path="gptData">
|
||||
<n-select
|
||||
style="width: 160px"
|
||||
v-model:value="formValue.gptData"
|
||||
:options="gptDataOptions"
|
||||
placeholder="请选择提示词数据"
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item label="选择请求AI" path="gptAI">
|
||||
<n-select
|
||||
style="width: 160px"
|
||||
v-model:value="formValue.gptAI"
|
||||
:options="gptOptions"
|
||||
placeholder="请选择AI"
|
||||
>
|
||||
</n-select>
|
||||
<n-button type="text" style="font-size: 20px" @click="AISetting">
|
||||
<n-icon> <SettingsOutline /> </n-icon
|
||||
></n-button>
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button type="primary" @click="ActionStart">开始生成</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
<div style="display: flex; width: 100%">
|
||||
<div style="flex: 1; margin-right: 10px">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 30, maxRows: 30 }"
|
||||
v-model:value="oldWord"
|
||||
placeholder="请输入内容"
|
||||
/>
|
||||
</div>
|
||||
<div style="flex: 1">
|
||||
<n-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 30, maxRows: 30 }"
|
||||
v-model:value="newWord"
|
||||
placeholder="请输入内容"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
|
||||
import { useMessage, useDialog, NForm, NFormItem, NInput, NSelect, NButton, NIcon } from 'naive-ui'
|
||||
import { SettingsOutline } from '@vicons/ionicons5'
|
||||
import ManageAISetting from './ManageAISetting.vue'
|
||||
import { useSoftwareStore } from '../../../../stores/software'
|
||||
import { isEmpty } from 'lodash'
|
||||
|
||||
export default defineComponent({
|
||||
components: { NForm, NFormItem, NInput, NSelect, NButton, NIcon, SettingsOutline },
|
||||
setup() {
|
||||
let message = useMessage()
|
||||
let dialog = useDialog()
|
||||
let formValue = ref({
|
||||
gptType: undefined,
|
||||
gptData: undefined,
|
||||
gptAI: undefined
|
||||
})
|
||||
let oldWord = ref(undefined)
|
||||
let newWord = ref(undefined)
|
||||
let gptTypeOptions = ref([])
|
||||
let gptDataOptions = ref([])
|
||||
let gptAllData = undefined
|
||||
let formRef = ref(null)
|
||||
let gptOptions = ref([
|
||||
{ label: 'LAI API', value: 'laiapi' },
|
||||
{ label: 'KIMI', value: 'kimi' },
|
||||
{ label: 'DouBao', value: 'doubao' }
|
||||
])
|
||||
let softwareStore = useSoftwareStore()
|
||||
|
||||
// 加载服务端数据
|
||||
async function InitServerGptOptions() {
|
||||
let gptRes = await window.gpt.InitServerGptOptions()
|
||||
if (gptRes.code == 0) {
|
||||
message.error(gptRes.message)
|
||||
return
|
||||
}
|
||||
gptAllData = gptRes.data
|
||||
// 处理数据
|
||||
gptTypeOptions.value = gptRes.data.promptType.map((item) => {
|
||||
return { label: item.name, value: item.id }
|
||||
})
|
||||
|
||||
gptDataOptions.value = gptRes.data.promptData.map((item) => {
|
||||
return { label: item.name, value: item.id }
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await InitServerGptOptions()
|
||||
})
|
||||
|
||||
let ruleObj = (errorMessage) => {
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
validator(rule, value) {
|
||||
if (value == null || value == '') return new Error(errorMessage)
|
||||
return true
|
||||
},
|
||||
trigger: ['input', 'blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
let rules = {
|
||||
gptAI: ruleObj('必选提示词类型'),
|
||||
gptData: ruleObj('必选提示词预设'),
|
||||
gptType: ruleObj('必填提示词AI')
|
||||
}
|
||||
|
||||
/**
|
||||
* AI设置相关
|
||||
*/
|
||||
async function AISetting() {
|
||||
debugger
|
||||
// 判断当前数据是不是存在
|
||||
// 处理数据。获取当前的所有的数据
|
||||
let dialogWidth = 800
|
||||
let dialogHeight = 600
|
||||
dialog.create({
|
||||
title: 'AI设置',
|
||||
showIcon: false,
|
||||
closeOnEsc: false,
|
||||
content: () => h(ManageAISetting, { type: formValue.value.gptAI }),
|
||||
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
||||
maskClosable: false,
|
||||
onClose: async () => {}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始执行GPT
|
||||
*/
|
||||
async function ActionStart() {
|
||||
// 检查是不是有数据
|
||||
if (
|
||||
isEmpty(formValue.value.gptType) ||
|
||||
isEmpty(formValue.value.gptData) ||
|
||||
isEmpty(formValue.value.gptAI)
|
||||
) {
|
||||
message.error('请选择完整的数据')
|
||||
return
|
||||
}
|
||||
softwareStore.spin.spinning = true
|
||||
softwareStore.spin.tip = '生成中......'
|
||||
let res = await window.write.ActionStart(toRaw(formValue.value), oldWord.value)
|
||||
softwareStore.spin.spinning = false
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
softwareStore.spin.spinning = false
|
||||
return
|
||||
}
|
||||
|
||||
newWord.value = res.data
|
||||
}
|
||||
|
||||
return {
|
||||
formValue,
|
||||
gptTypeOptions,
|
||||
gptDataOptions,
|
||||
oldWord,
|
||||
newWord,
|
||||
rules,
|
||||
formRef,
|
||||
AISetting,
|
||||
gptOptions,
|
||||
softwareStore,
|
||||
ActionStart
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-card title="LAI API 设置">
|
||||
<div style="display: flex">
|
||||
<n-input
|
||||
v-model:value="aiSetting.laiapi.gpt_url"
|
||||
style="margin-right: 10px"
|
||||
type="text"
|
||||
placeholder="请输入GPT URL"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="aiSetting.laiapi.api_key"
|
||||
style="margin-right: 10px"
|
||||
type="text"
|
||||
placeholder="请输入API KEY"
|
||||
/>
|
||||
<n-input v-model:value="aiSetting.laiapi.model" type="text" placeholder="请输入Model" />
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card title="豆包设置">
|
||||
<div style="display: flex">
|
||||
<n-input
|
||||
v-model:value="aiSetting.doubao.gpt_url"
|
||||
type="text"
|
||||
style="margin-right: 10px"
|
||||
placeholder="请输入豆包的调用网址"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="aiSetting.doubao.api_key"
|
||||
type="text"
|
||||
style="margin-right: 10px"
|
||||
placeholder="请输入豆包的APIKEY"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="aiSetting.doubao.model"
|
||||
type="text"
|
||||
placeholder="请输入豆包的模型"
|
||||
/>
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card title="KIMI设置">
|
||||
<div style="display: flex">
|
||||
<n-input
|
||||
v-model:value="aiSetting.kimi.gpt_url"
|
||||
type="text"
|
||||
style="margin-right: 10px"
|
||||
placeholder="请输入KIMI的网址"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="aiSetting.kimi.api_key"
|
||||
type="text"
|
||||
style="margin-right: 10px"
|
||||
placeholder="请输入KIMI的APIKEY"
|
||||
/>
|
||||
<n-input v-model:value="aiSetting.kimi.model" type="text" placeholder="请输入KIMI的模型" />
|
||||
</div>
|
||||
</n-card>
|
||||
<div style="display: flex; justify-content: flex-end; margin: 20px">
|
||||
<n-button type="primary" @click="SaveAISetting">保存</n-button>
|
||||
</div>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
|
||||
import { useMessage, NCard, NSpace, NInput, NSelect, NButton } from 'naive-ui'
|
||||
import { isEmpty } from 'lodash'
|
||||
|
||||
export default defineComponent({
|
||||
components: { NCard, NSpace, NInput, NSelect, NButton },
|
||||
props: ['type'],
|
||||
setup(props) {
|
||||
let message = useMessage()
|
||||
let aiSetting = ref({
|
||||
laiapi: {
|
||||
gpt_url: undefined,
|
||||
api_key: undefined,
|
||||
model: undefined
|
||||
},
|
||||
kimi: {
|
||||
gpt_url: undefined,
|
||||
api_key: undefined,
|
||||
model: undefined
|
||||
},
|
||||
doubao: { gpt_url: undefined, api_key: undefined, model: undefined }
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
debugger
|
||||
// 获取AIsetting
|
||||
let res = await window.gpt.GetAISetting()
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
return
|
||||
}
|
||||
aiSetting.value = res.data
|
||||
})
|
||||
|
||||
function checkValue(obj) {
|
||||
for (const d in obj) {
|
||||
if (isEmpty(d)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function SaveAISetting() {
|
||||
// 判断当前是选择是哪个AI,判断是不是有填写
|
||||
let checkRes = true
|
||||
if (props.type == 'laiapi') {
|
||||
checkRes = checkValue(Object.values(aiSetting.value.laiapi))
|
||||
} else if (props.type == 'kimi') {
|
||||
checkRes = checkValue(Object.values(aiSetting.value.kimi))
|
||||
} else if (props.type == 'doubao') {
|
||||
checkRes = checkValue(Object.values(aiSetting.value.doubao))
|
||||
}
|
||||
|
||||
if (!checkRes) {
|
||||
message.error('请填写完整选择的AI相关的设置')
|
||||
return
|
||||
}
|
||||
|
||||
let res = await window.gpt.SaveAISetting(toRaw(aiSetting.value))
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
return
|
||||
}
|
||||
message.success('保存成功')
|
||||
}
|
||||
|
||||
return { aiSetting, SaveAISetting }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -50,7 +50,9 @@ import {
|
||||
PaperPlaneOutline,
|
||||
SettingsOutline,
|
||||
DuplicateOutline,
|
||||
GridOutline
|
||||
GridOutline,
|
||||
RadioOutline,
|
||||
BookOutline
|
||||
} from '@vicons/ionicons5'
|
||||
import CheckMachineId from '../Components/CheckMachineId.vue'
|
||||
import axios from 'axios'
|
||||
@@ -85,10 +87,12 @@ export default defineComponent({
|
||||
if (option.key === 'food') return null
|
||||
if (option.key == 'sdoriginal') return h(NIcon, null, { default: () => h(PaperPlaneOutline) })
|
||||
if (option.key == 'setting') return h(NIcon, null, { default: () => h(SettingsOutline) })
|
||||
if (option.key == 'gptCopywriting') return h(NIcon, null, { default: () => h(BookOutline) })
|
||||
if (option.key == 'reverse_management')
|
||||
return h(NIcon, null, { default: () => h(GridOutline) })
|
||||
if (option.key == 'backward_matrix')
|
||||
return h(NIcon, null, { default: () => h(DuplicateOutline) })
|
||||
if (option.key == 'TTS_Services') return h(NIcon, null, { default: () => h(RadioOutline) })
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -230,6 +234,21 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: 'gptCopywriting'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => '文案处理'
|
||||
}
|
||||
),
|
||||
key: 'gptCopywriting'
|
||||
},
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
@@ -434,6 +453,36 @@ export default defineComponent({
|
||||
}
|
||||
]
|
||||
}
|
||||
// {
|
||||
// label: () =>
|
||||
// h(
|
||||
// RouterLink,
|
||||
// {
|
||||
// to: {
|
||||
// name: 'test_options'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// default: () => '测试操作'
|
||||
// }
|
||||
// ),
|
||||
// key: 'test_options'
|
||||
// },
|
||||
// {
|
||||
// label: () =>
|
||||
// h(
|
||||
// RouterLink,
|
||||
// {
|
||||
// to: {
|
||||
// name: 'TTS_Services'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// default: () => '语音服务'
|
||||
// }
|
||||
// ),
|
||||
// key: 'TTS_Services'
|
||||
// }
|
||||
]
|
||||
|
||||
return {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<n-button color="#ee7959" style="margin-left: 10px" @click="GetCharacter" size="small"
|
||||
>角色分析(标签集)</n-button
|
||||
>
|
||||
<n-button color="#ee7959" style="margin-left: 10px" @click="ImportPrompt" size="small"
|
||||
>导入提示词</n-button
|
||||
>
|
||||
<n-dropdown trigger="hover" :options="GptButtonOptions" @select="ButtonSelect">
|
||||
<n-button color="#ee7959" style="margin-left: 10px" @click="GPTPrompt" size="small"
|
||||
>一键推理提示词</n-button
|
||||
@@ -338,11 +341,60 @@ export default defineComponent({
|
||||
await ResetImage()
|
||||
}
|
||||
|
||||
// 导入提示词
|
||||
async function ImportPrompt() {
|
||||
// 弹窗选择文件
|
||||
window.api.SelectFile(['txt'], async (value) => {
|
||||
if (value.code == 0) {
|
||||
message.error(value.message)
|
||||
return
|
||||
}
|
||||
debugger
|
||||
console.log(value.value)
|
||||
// 拿到提示词文件地址,然后还是获取
|
||||
await window.pmpt.OpenPromptFileTxt(value.value, (res) => {
|
||||
debugger
|
||||
console.log(res)
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
return
|
||||
}
|
||||
// 修改数据
|
||||
// 判断获取的数据是不是小于当前的data的行
|
||||
if (res.data.length > data.value.length) {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '导入的数据行数大于当前的数据行数,多余的数据会被删除,是否继续导入?',
|
||||
positiveText: '继续',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
debugger
|
||||
// 开始导入
|
||||
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
|
||||
const element = res.data[i]
|
||||
// 开始修改
|
||||
data.value[i].gpt_prompt = element
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 开始导入
|
||||
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
|
||||
const element = res.data[i]
|
||||
// 开始修改
|
||||
data.value[i].gpt_prompt = element
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
ImportWord,
|
||||
data,
|
||||
GetCharacter,
|
||||
tagTreeData,
|
||||
ImportPrompt,
|
||||
GPTPrompt,
|
||||
OpenPromptSetting,
|
||||
GenerateImageAll,
|
||||
|
||||
@@ -34,7 +34,7 @@ export default defineComponent({
|
||||
// 自动开始
|
||||
async function AutoAction() {
|
||||
// 开始自动执行。先分镜,后面在添加任务中
|
||||
let res_frame = await window.book.GetFrameData(reverseManageStore.selectBook.id)
|
||||
let res_frame = await window.book.AutoAction(reverseManageStore.selectBook.id)
|
||||
}
|
||||
|
||||
// 选择自动开始的操作(停止或者是继续)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>AzureTTS</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
|
||||
import { useMessage } from 'naive-ui'
|
||||
|
||||
export default defineComponent({
|
||||
components: {},
|
||||
|
||||
setup() {
|
||||
onMounted(async () => {})
|
||||
|
||||
return {}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-form
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging"
|
||||
:model="edgeTTs"
|
||||
>
|
||||
<n-form-item label="合成角色">
|
||||
<n-select v-model:value="edgeTTs.value" :options="roleOptions" />
|
||||
</n-form-item>
|
||||
<n-form-item label="音量">
|
||||
<n-input-number v-model:value="edgeTTs.volumn" :min="0" :max="100" />
|
||||
</n-form-item>
|
||||
<n-form-item label="语速">
|
||||
<n-input-number v-model:value="edgeTTs.rate" :min="0" :max="100" />
|
||||
</n-form-item>
|
||||
<n-form-item label="语调">
|
||||
<n-input-number v-model:value="edgeTTs.pitch" :min="0" :max="100" />
|
||||
</n-form-item>
|
||||
<n-form-item label="生成SRT">
|
||||
<n-checkbox v-model:checked="edgeTTs.saveSubtitles"> 复选框 </n-checkbox>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, watch } from 'vue'
|
||||
import {
|
||||
useMessage,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NInputNumber,
|
||||
NSelect,
|
||||
NButton,
|
||||
NIcon,
|
||||
NPopover,
|
||||
NCheckbox
|
||||
} from 'naive-ui'
|
||||
import { GetEdgeTTSRole } from '../../../../define/tts/ttsDefine'
|
||||
import { ReaderOutline } from '@vicons/ionicons5'
|
||||
import { useSoftwareStore } from '../../../../stores/software'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
NForm,
|
||||
NCheckbox,
|
||||
NFormItem,
|
||||
NInputNumber,
|
||||
NSelect,
|
||||
NButton,
|
||||
NIcon,
|
||||
ReaderOutline,
|
||||
NPopover
|
||||
},
|
||||
props: ['edgeTTs'],
|
||||
setup(props) {
|
||||
let edgeTTs = ref(props.edgeTTs)
|
||||
let message = useMessage()
|
||||
let softwareStore = useSoftwareStore()
|
||||
|
||||
watch(
|
||||
() => props.edgeTTs,
|
||||
(val) => {
|
||||
edgeTTs.value = val
|
||||
}
|
||||
)
|
||||
|
||||
let roleOptions = ref([])
|
||||
onMounted(async () => {
|
||||
// 获取配音角色列表
|
||||
roleOptions.value = GetEdgeTTSRole()
|
||||
})
|
||||
|
||||
return { edgeTTs, roleOptions, softwareStore }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,320 @@
|
||||
<template>
|
||||
<div style="display: flex; min-width: 900px; overflow: auto">
|
||||
<div class="text-input">
|
||||
<n-input
|
||||
v-model:value="text"
|
||||
type="textarea"
|
||||
placeholder="请输入配音的文本内容"
|
||||
:autosize="{
|
||||
minRows: 30,
|
||||
maxRows: 30
|
||||
}"
|
||||
show-count
|
||||
></n-input>
|
||||
<div class="tts-options">
|
||||
<n-button :color="softwareStore.SoftColor.BROWN_YELLOW" size="small" @click="FormatWord">
|
||||
格式化文档
|
||||
</n-button>
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-button quaternary circle color="#b6a014" @click="ModifySplitChar">
|
||||
<template #icon>
|
||||
<n-icon size="25"> <AddCircleOutline /> </n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</template>
|
||||
<span>添加分割标识符</span>
|
||||
</n-popover>
|
||||
<n-button
|
||||
style="margin-right: 10px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
size="small"
|
||||
@click="ClearText"
|
||||
>
|
||||
清空内容
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="audio-setting">
|
||||
<div class="param-setting">
|
||||
<n-form label-placement="left">
|
||||
<n-form-item label="选择配音渠道">
|
||||
<n-select
|
||||
placeholder="请选择配音渠道"
|
||||
v-model:value="ttsConfig.selectModel"
|
||||
:options="ttsOptions"
|
||||
></n-select>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<EdgeTTS
|
||||
:edgeTTs="ttsConfig.edgeTTS"
|
||||
ref="edgettsRef"
|
||||
v-if="ttsConfig.selectModel == 'edge-tts'"
|
||||
/>
|
||||
<AzureTTS
|
||||
:azureTTS="ttsConfig.azureTTS"
|
||||
ref="azurettsRef"
|
||||
v-else-if="ttsConfig.selectModel == 'azure-tts'"
|
||||
/>
|
||||
</div>
|
||||
<div class="autio-button">
|
||||
<n-button
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
style="margin-right: 10px"
|
||||
@click="SaveTTSConfig"
|
||||
>
|
||||
保存配置信息
|
||||
</n-button>
|
||||
<n-button
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
@click="GenerateAudio"
|
||||
style="margin-right: 10px"
|
||||
>
|
||||
开始合成
|
||||
</n-button>
|
||||
<n-button
|
||||
style="margin-right: 10px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
@click="ShowHistory"
|
||||
>
|
||||
查看配音历史
|
||||
</n-button>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<audio
|
||||
ref="audio"
|
||||
src="D:\\3.大力\\1\\1719165587206_6cd74afd-ff56-4ba7-abc9-9021a70ac9c7.wav"
|
||||
controls
|
||||
style="width: 100%"
|
||||
></audio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
|
||||
import {
|
||||
useMessage,
|
||||
NInput,
|
||||
NSelect,
|
||||
NFormItem,
|
||||
NForm,
|
||||
NButton,
|
||||
NPopover,
|
||||
NIcon,
|
||||
useDialog
|
||||
} from 'naive-ui'
|
||||
import EdgeTTS from './EdgeTTS.vue'
|
||||
import AzureTTS from './AzureTTS.vue'
|
||||
import { GetTTSSelect } from '../../../../define/tts/ttsDefine'
|
||||
import { useSoftwareStore } from '../../../../stores/software'
|
||||
import { AddCircleOutline } from '@vicons/ionicons5'
|
||||
import InputDialogContent from '../Original/Components/InputDialogContent.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
NInput,
|
||||
NSelect,
|
||||
NFormItem,
|
||||
NForm,
|
||||
EdgeTTS,
|
||||
AzureTTS,
|
||||
NButton,
|
||||
NPopover,
|
||||
AddCircleOutline,
|
||||
NIcon,
|
||||
InputDialogContent
|
||||
},
|
||||
|
||||
setup() {
|
||||
let message = useMessage()
|
||||
let dialog = useDialog()
|
||||
let softwareStore = useSoftwareStore()
|
||||
let text = ref('你好,我是你的智能语音助手')
|
||||
let ttsOptions = ref([])
|
||||
let edgettsRef = ref(null)
|
||||
let azurettsRef = ref(null)
|
||||
let splitRef = ref(null)
|
||||
let ttsConfig = ref({
|
||||
selectModel: 'edge-tts',
|
||||
edgeTTS: {
|
||||
name: 'zh-CN-XiaoxiaoNeural',
|
||||
gender: 'Female',
|
||||
label: '晓晓',
|
||||
lang: 'zh-CN',
|
||||
pitch: '0', // 语调
|
||||
rate: '10', // 倍速
|
||||
volumn: '0' // 音量
|
||||
}
|
||||
})
|
||||
let writeSetting = ref({
|
||||
split_char: '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;',
|
||||
merge_count: 3,
|
||||
merge_char: ',',
|
||||
end_char: '。'
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
ttsOptions.value = GetTTSSelect()
|
||||
|
||||
// 加载服务端的TTS配置(目前的TTS配置是全局的)
|
||||
let res = await window.tts.GetTTSCOnfig()
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
} else {
|
||||
ttsConfig.value = res.data
|
||||
}
|
||||
|
||||
// 加载文字设置
|
||||
let writeSettingRes = await window.write.GetWriteCOnfig()
|
||||
if (writeSettingRes.code == 0) {
|
||||
message.error(writeSettingRes.message)
|
||||
} else {
|
||||
writeSetting.value = writeSettingRes.data
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 修改分割符
|
||||
*/
|
||||
async function ModifySplitChar() {
|
||||
// 判断当前数据是不是存在
|
||||
// 处理数据。获取当前的所有的数据
|
||||
let dialogWidth = 400
|
||||
let dialogHeight = 150
|
||||
dialog.create({
|
||||
title: '添加分割符',
|
||||
showIcon: false,
|
||||
closeOnEsc: false,
|
||||
content: () =>
|
||||
h(InputDialogContent, {
|
||||
ref: splitRef,
|
||||
initData: writeSetting.value.split_char,
|
||||
placeholder: '请输入分割符'
|
||||
}),
|
||||
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
|
||||
maskClosable: false,
|
||||
onClose: async () => {
|
||||
writeSetting.value.split_char = splitRef.value.data
|
||||
// 保存数据
|
||||
let saveRes = await window.write.SaveWriteConfig(toRaw(writeSetting.value))
|
||||
if (saveRes.code == 0) {
|
||||
message.error(saveRes.message)
|
||||
return
|
||||
}
|
||||
message.success('分隔符保存成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析/格式化文档
|
||||
*/
|
||||
async function FormatWord() {
|
||||
let split_arr = Array.from(writeSetting.value.split_char)
|
||||
split_arr.forEach((item) => {
|
||||
let specialCharacters = [
|
||||
'.',
|
||||
'*',
|
||||
'?',
|
||||
'+',
|
||||
'^',
|
||||
'$',
|
||||
'[',
|
||||
']',
|
||||
'(',
|
||||
')',
|
||||
'{',
|
||||
'}',
|
||||
'|',
|
||||
'\\'
|
||||
]
|
||||
let regex
|
||||
|
||||
if (specialCharacters.includes(item)) {
|
||||
regex = new RegExp('\\' + item, 'g')
|
||||
} else {
|
||||
regex = new RegExp(item, 'g')
|
||||
}
|
||||
text.value = text.value.replace(regex, '\n')
|
||||
})
|
||||
// 删除空行
|
||||
let word_arr = text.value.split('\n')
|
||||
word_arr = word_arr.filter((item) => item != '' && item != null)
|
||||
text.value = word_arr.join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文本内容
|
||||
*/
|
||||
async function ClearText() {
|
||||
text.value = ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存TTS配置信息
|
||||
*/
|
||||
async function SaveTTSConfig() {}
|
||||
|
||||
/**
|
||||
* 开始合成音频
|
||||
*/
|
||||
async function GenerateAudio() {
|
||||
if (text.value == '') {
|
||||
message.error('文本内容不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
if (ttsConfig.value.selectModel == 'edge-tts') {
|
||||
// let res =
|
||||
} else if (ttsConfig.value.selectModel == 'azure-tts') {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置信息
|
||||
*/
|
||||
async function SaveTTSConfig() {}
|
||||
|
||||
return {
|
||||
text,
|
||||
azurettsRef,
|
||||
edgettsRef,
|
||||
ttsConfig,
|
||||
writeSetting,
|
||||
softwareStore,
|
||||
ModifySplitChar,
|
||||
SaveTTSConfig,
|
||||
FormatWord,
|
||||
ClearText,
|
||||
splitRef,
|
||||
GenerateAudio,
|
||||
ttsOptions: [{ label: 'Edge TTS(免费)', value: 'edge-tts' }]
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.autio-button {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
}
|
||||
.text-input {
|
||||
flex: 4;
|
||||
height: 100%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.audio-setting {
|
||||
flex: 2;
|
||||
margin: 0 20px;
|
||||
}
|
||||
.tts-options {
|
||||
margin-top: 10px;
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,423 @@
|
||||
<template>
|
||||
<div id="video-canvas" style="position: relative">
|
||||
<video ref="videoRef" muted style="width: 100%" :src="videoSrc" id="video" autoplay></video>
|
||||
<canvas
|
||||
ref="canvasRef"
|
||||
@mousemove="handleMouseMove"
|
||||
@mousedown="handleMouseDown"
|
||||
@mouseup="handleMouseUp"
|
||||
style="position: absolute; top: 0; left: 0; pointer-events: auto"
|
||||
/>
|
||||
<n-divider />
|
||||
<div class="option-button">
|
||||
<n-button @click="SetVideoMuted" :color="buttonColor">{{
|
||||
isMuted ? '取消静音' : '开启静音'
|
||||
}}</n-button>
|
||||
<n-button
|
||||
@click="SaveSelectPosition"
|
||||
style="margin-left: 5px"
|
||||
:loading="SaveSelectPositionLodding"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
>保存位置</n-button
|
||||
>
|
||||
<n-button
|
||||
@click="OpenBookSubtitlePositionScreenshot"
|
||||
style="margin-left: 5px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
>查看截图</n-button
|
||||
>
|
||||
<n-button
|
||||
@click="GetCurrentFrameText"
|
||||
style="margin-left: 5px; width: 150px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
:loading="GetCurrentFrameTextLodding"
|
||||
>
|
||||
{{ GetCurrentFrameTextLodding ? '提取文本中' : '提取保存帧' }}</n-button
|
||||
>
|
||||
|
||||
<n-button
|
||||
@click="GetVideoFrameText"
|
||||
style="margin-left: 5px; width: 150px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
:loading="GetVideoFrameTextLodding"
|
||||
>
|
||||
{{ GetVideoFrameTextLodding ? '视频文案提取中' : '提示视频文案' }}</n-button
|
||||
>
|
||||
<n-button
|
||||
v-if="type == 'storyboard_video'"
|
||||
@click="GetAllImageText"
|
||||
style="margin-left: 5px"
|
||||
:color="softwareStore.SoftColor.BROWN_YELLOW"
|
||||
>提取所有</n-button
|
||||
>
|
||||
</div>
|
||||
<div class="output-text" style="margin-top: 10px">
|
||||
<n-input
|
||||
type="textarea"
|
||||
placeholder="识别到的字幕文本(可能有错,需要手动看一下)"
|
||||
:autosize="{
|
||||
minRows: 5,
|
||||
maxRows: 7
|
||||
}"
|
||||
v-model:value="frameText"
|
||||
>
|
||||
</n-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, defineComponent, onUnmounted, computed, toRaw } from 'vue'
|
||||
import { NDivider, NButton, useMessage, NInput, useDialog } from 'naive-ui'
|
||||
import { useSoftwareStore } from '../../../../stores/software'
|
||||
import { useReverseManageStore } from '../../../../stores/reverseManage'
|
||||
import { SubtitleSavePositionType } from '../../../../define/enum/waterMarkAndSubtitle'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
NDivider,
|
||||
NButton,
|
||||
NInput
|
||||
},
|
||||
props: ['videoSrc', 'mark', 'videoWidth', 'type', 'height'],
|
||||
setup(props) {
|
||||
let message = useMessage()
|
||||
let dialog = useDialog()
|
||||
let softwareStore = useSoftwareStore()
|
||||
let reverseManageStore = useReverseManageStore()
|
||||
let videoRef = ref(null)
|
||||
let canvasRef = ref(null)
|
||||
let videoSrc = ref(
|
||||
props.videoSrc ||
|
||||
'D:\\文\\物价暴跌百万倍,我成了神豪-七猫\\1\\价暴跌百万倍,我成了神豪1_output_crop_00001.mp4'
|
||||
)
|
||||
let type = ref(props.type ? props.type : SubtitleSavePositionType.MAIN_VIDEO)
|
||||
let mark = ref(props.mark)
|
||||
let videoWidth = ref(props.videoWidth == null ? 800 : props.videoWidth)
|
||||
let drawing = ref(false)
|
||||
let moving = ref(false)
|
||||
let startPos = ref(null)
|
||||
let rectPos = ref(null)
|
||||
let offset = ref({ x: 0, y: 0 })
|
||||
let isPlaying = ref(false)
|
||||
let buttonColor = ref(softwareStore.SoftColor.BROWN_YELLOW)
|
||||
let isMuted = ref(false)
|
||||
let frameText = ref('')
|
||||
let GetCurrentFrameTextLodding = ref(false)
|
||||
let SaveSelectPositionLodding = ref(false)
|
||||
let GetVideoFrameTextLodding = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', updateVideoPosition)
|
||||
updateVideoPosition() // 初始更新
|
||||
// resizeObserver.observe(videoRef.value)
|
||||
const video = videoRef.value
|
||||
video.onloadedmetadata = () => {
|
||||
let { width, height } = video.getBoundingClientRect()
|
||||
canvasRef.value.width = width
|
||||
canvasRef.value.height = height
|
||||
canvasRef.value.style.width = `${width}px`
|
||||
canvasRef.value.style.height = `${height}px`
|
||||
}
|
||||
|
||||
let videoCanvas = document.getElementById('video-canvas')
|
||||
videoCanvas.style.width = `${videoWidth.value}px`
|
||||
videoCanvas.style.height = `${props.height}px`
|
||||
videoCanvas.style.overflow = 'scroll'
|
||||
buttonColor.value = videoRef.value.muted
|
||||
? softwareStore.SoftColor.ERROR_RED
|
||||
: softwareStore.SoftColor.ERROR_RED
|
||||
isMuted.value = videoRef.value.muted
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', updateVideoPosition)
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取当前鼠标在canvas中的相对位置
|
||||
* @param e
|
||||
*/
|
||||
function getCanvasRelativePosition(e) {
|
||||
const rect = canvasRef.value.getBoundingClientRect()
|
||||
return {
|
||||
x: e.clientX - rect.left,
|
||||
y: e.clientY - rect.top
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* canvas绘制矩形
|
||||
* @param rect
|
||||
*/
|
||||
const drawRectangle = (rect) => {
|
||||
const ctx = canvasRef.value.getContext('2d')
|
||||
ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height) // 清除之前的绘制
|
||||
ctx.strokeStyle = 'red' // 设置矩形颜色
|
||||
ctx.lineWidth = 2 // 设置线宽
|
||||
ctx.strokeRect(rect.startX, rect.startY, rect.width, rect.height)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标再canvas中移动事件
|
||||
* @param e
|
||||
*/
|
||||
function handleMouseMove(e) {
|
||||
if (drawing.value && startPos.value) {
|
||||
videoRef.value.pause()
|
||||
isPlaying.value = false
|
||||
const currentPos = getCanvasRelativePosition(e)
|
||||
|
||||
const rect = {
|
||||
startX: Math.min(startPos.value.x, currentPos.x),
|
||||
startY: Math.min(startPos.value.y, currentPos.y),
|
||||
width: Math.abs(startPos.value.x - currentPos.x),
|
||||
height: Math.abs(startPos.value.y - currentPos.y)
|
||||
}
|
||||
drawRectangle(rect)
|
||||
} else if (moving.value && rectPos.value) {
|
||||
videoRef.value.pause()
|
||||
isPlaying.value = false
|
||||
const currentPos = getCanvasRelativePosition(e)
|
||||
const newRectPos = {
|
||||
startX: currentPos.x - offset.value.x,
|
||||
startY: currentPos.y - offset.value.y,
|
||||
width: rectPos.value.width,
|
||||
height: rectPos.value.height,
|
||||
videoWidth: canvasRef.value.width,
|
||||
videoHeight: canvasRef.value.height
|
||||
}
|
||||
rectPos.value = newRectPos
|
||||
drawRectangle(newRectPos)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标再canvas中按下事件
|
||||
* @param e
|
||||
*/
|
||||
function handleMouseDown(e) {
|
||||
const pos = getCanvasRelativePosition(e)
|
||||
if (
|
||||
rectPos.value &&
|
||||
pos.x >= rectPos.value.startX &&
|
||||
pos.x <= rectPos.value.startX + rectPos.value.width &&
|
||||
pos.y >= rectPos.value.startY &&
|
||||
pos.y <= rectPos.value.startY + rectPos.value.height
|
||||
) {
|
||||
moving.value = true
|
||||
offset.value = { x: pos.x - rectPos.value.startX, y: pos.y - rectPos.value.startY }
|
||||
} else {
|
||||
startPos.value = pos
|
||||
drawing.value = true
|
||||
}
|
||||
|
||||
if (videoRef.value.paused) {
|
||||
videoRef.value.play()
|
||||
isPlaying.value = true
|
||||
} else {
|
||||
videoRef.value.pause()
|
||||
isPlaying.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标再canvas中抬起事件
|
||||
* @param e
|
||||
*/
|
||||
function handleMouseUp(e) {
|
||||
if (drawing.value) {
|
||||
const pos = getCanvasRelativePosition(e)
|
||||
rectPos.value = {
|
||||
startX: Math.min(startPos.value.x, pos.x),
|
||||
startY: Math.min(startPos.value.y, pos.y),
|
||||
width: Math.abs(startPos.value.x - pos.x),
|
||||
height: Math.abs(startPos.value.y - pos.y),
|
||||
videoWidth: canvasRef.value.width,
|
||||
videoHeight: canvasRef.value.height
|
||||
}
|
||||
drawRectangle(rectPos.value)
|
||||
startPos.value = null
|
||||
drawing.value = false
|
||||
}
|
||||
if (moving.value) {
|
||||
moving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听video的resize事件
|
||||
*/
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
const { width, height } = entry.contentRect
|
||||
if (canvasRef.value) {
|
||||
canvasRef.value.width = width
|
||||
canvasRef.value.height = height
|
||||
canvasRef.value.style.width = `${width}px`
|
||||
canvasRef.value.style.height = `${height}px`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 更新canvas的位置
|
||||
*/
|
||||
const updateVideoPosition = () => {
|
||||
if (videoRef.value && videoRef.value.parentElement) {
|
||||
const videoRect = videoRef.value.getBoundingClientRect()
|
||||
const parentRect = videoRef.value.parentElement.getBoundingClientRect()
|
||||
const relativeTop = videoRect.top - parentRect.top
|
||||
const relativeLeft = videoRect.left - parentRect.left
|
||||
const { width, height } = videoRect
|
||||
if (canvasRef.value) {
|
||||
canvasRef.value.style.top = `${relativeTop}px`
|
||||
canvasRef.value.style.left = `${relativeLeft}px`
|
||||
canvasRef.value.style.width = `${width}px`
|
||||
canvasRef.value.style.height = `${height}px`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置静音
|
||||
*/
|
||||
function SetVideoMuted() {
|
||||
videoRef.value.muted = !videoRef.value.muted
|
||||
isMuted.value = videoRef.value.muted
|
||||
if (videoRef.value.muted) {
|
||||
buttonColor.value = softwareStore.SoftColor.ERROR_RED
|
||||
} else {
|
||||
buttonColor.value = softwareStore.SoftColor.BROWN_YELLOW
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存当前选中的所有的位置(目前只支持单个)
|
||||
*/
|
||||
async function SaveSelectPosition() {
|
||||
if (rectPos.value == null) {
|
||||
message.error('请先选择一个区域')
|
||||
return
|
||||
}
|
||||
SaveSelectPositionLodding.value = true
|
||||
message.success(JSON.stringify(rectPos.value))
|
||||
// 调用保存
|
||||
let saveRes = await window.book.SaveBookSubtitlePosition({
|
||||
id: reverseManageStore.selectBook.id
|
||||
? reverseManageStore.selectBook.id
|
||||
: '58053f68-da54-4a48-92fc-8a5c3cb75043',
|
||||
bookSubtitlePosition: [toRaw(rectPos.value)],
|
||||
currentTime: videoRef.value.currentTime,
|
||||
type: type.value
|
||||
})
|
||||
if (saveRes.code == 0) {
|
||||
message.error('保存字幕位置并截取示例图片失败')
|
||||
SaveSelectPositionLodding.value = false
|
||||
return
|
||||
}
|
||||
message.success('保存字幕位置并截取示例图片成功')
|
||||
SaveSelectPositionLodding.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看字幕位置示例截图
|
||||
*/
|
||||
async function OpenBookSubtitlePositionScreenshot() {
|
||||
if (rectPos.value == null) {
|
||||
message.error('请先选择一个区域')
|
||||
return
|
||||
}
|
||||
let res = await window.book.OpenBookSubtitlePositionScreenshot({
|
||||
id: reverseManageStore.selectBook.id
|
||||
? reverseManageStore.selectBook.id
|
||||
: '58053f68-da54-4a48-92fc-8a5c3cb75043',
|
||||
type: type.value
|
||||
})
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
return
|
||||
}
|
||||
message.success(res.message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的字幕
|
||||
*/
|
||||
async function GetCurrentFrameText() {
|
||||
GetCurrentFrameTextLodding.value = true
|
||||
if (type.value == SubtitleSavePositionType.MAIN_VIDEO) {
|
||||
let res = await window.book.GetCurrentFrameText({
|
||||
id: reverseManageStore.selectBook.id
|
||||
? reverseManageStore.selectBook.id
|
||||
: '58053f68-da54-4a48-92fc-8a5c3cb75043',
|
||||
currentTime: videoRef.value.currentTime,
|
||||
type: type.value
|
||||
})
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
GetCurrentFrameTextLodding.value = false
|
||||
return
|
||||
}
|
||||
message.success(res.data)
|
||||
frameText.value = res.data
|
||||
}
|
||||
GetCurrentFrameTextLodding.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取整个视频的文案信息,保存到和视频的同级目录中
|
||||
*/
|
||||
async function GetVideoFrameText() {
|
||||
GetVideoFrameTextLodding.value = true
|
||||
if (type.value == SubtitleSavePositionType.MAIN_VIDEO) {
|
||||
let res = await window.book.GetVideoFrameText({
|
||||
id: reverseManageStore.selectBook.id
|
||||
? reverseManageStore.selectBook.id
|
||||
: '58053f68-da54-4a48-92fc-8a5c3cb75043',
|
||||
type: type.value
|
||||
})
|
||||
if (res.code == 0) {
|
||||
message.error(res.message)
|
||||
GetVideoFrameTextLodding.value = false
|
||||
return
|
||||
}
|
||||
message.success(res.message)
|
||||
frameText.value = res.data
|
||||
GetVideoFrameTextLodding.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
videoRef,
|
||||
canvasRef,
|
||||
handleMouseMove,
|
||||
handleMouseDown,
|
||||
handleMouseUp,
|
||||
GetCurrentFrameTextLodding,
|
||||
SaveSelectPositionLodding,
|
||||
GetVideoFrameTextLodding,
|
||||
videoSrc,
|
||||
mark,
|
||||
videoWidth,
|
||||
drawing,
|
||||
moving,
|
||||
startPos,
|
||||
rectPos,
|
||||
offset,
|
||||
isPlaying,
|
||||
SetVideoMuted,
|
||||
buttonColor,
|
||||
isMuted,
|
||||
softwareStore,
|
||||
SaveSelectPosition,
|
||||
reverseManageStore,
|
||||
type,
|
||||
OpenBookSubtitlePositionScreenshot,
|
||||
GetCurrentFrameText,
|
||||
frameText,
|
||||
GetVideoFrameText
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
+108
-30
@@ -1,42 +1,120 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import App from './App.vue'
|
||||
import { Home } from '@vicons/ionicons5';
|
||||
const app = createApp(App);
|
||||
import { Home } from '@vicons/ionicons5'
|
||||
const app = createApp(App)
|
||||
import { createPinia } from 'pinia'
|
||||
const pinia = createPinia()
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
component: () => import('./components/Home/Home.vue'),
|
||||
children: [
|
||||
|
||||
{ path: "/global_setting", name: "global_setting", component: () => import('./components/Setting/Setting.vue') },
|
||||
{ path: "/clip_setting", name: "clip_setting", component: () => import('./components/Setting/ClipSetting.vue') },
|
||||
{ path: "/getframe", name: "getframe", component: () => import('./components/Backstep/GetFrame.vue') },
|
||||
{ path: "/pushBackPrompt", name: "pushBackPrompt", component: () => import('./components/Backstep/PushBackPrompt.vue') },
|
||||
{ path: "/regenerate", name: "regenerate", component: () => import('./components/Backstep/ReGenerate.vue') },
|
||||
{ path: "/align_draft", name: "align_draft", component: () => import('./components/Clip/AlignDraft.vue') },
|
||||
{ path: "/add_draft", name: "add_draft", component: () => import('./components/Clip/AddDraft.vue') },
|
||||
{ path: "/VideoGenerate", name: "VideoGenerate", component: () => import('./components/Backstep/VideoGenerate.vue') },
|
||||
{ path: "/sd_setting", name: "sd_setting", component: () => import('./components/Setting/SDSetting.vue') },
|
||||
{ path: "/copywriting", name: "copywriting", component: () => import('./components/Backstep/CopyWriting.vue') },
|
||||
{ path: "/videogeneratesetting", name: "videogeneratesetting", component: () => import('./components/Setting/VideoGenerateSetting.vue') },
|
||||
{ path: "/ShowMessage", name: "ShowMessage", component: () => import('./components/Home/ShowMessage.vue') },
|
||||
{ path: "/sdoriginal", name: "sdoriginal", component: () => import('./components/Original/MainPage.vue') },
|
||||
{ path: "/mj_setting", name: "mj_setting", component: () => import('./components/Setting/MJSetting.vue') },
|
||||
{ path: '/reverse_management', name: "reverse_management", component: () => import('./components/ReverseManage/ReverseManage.vue') },
|
||||
{ path: '/manage_book/:id', name: "manage_book", component: () => import('./components/ReverseManage/ManageBookDetail.vue') },
|
||||
]
|
||||
},
|
||||
{ path: "/ReDrawImage", component: () => import('./components/Home/ReDrawImageWD.vue'), },
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('./components/Home/Home.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/gptCopywriting',
|
||||
name: 'gptCopywriting',
|
||||
component: () => import('./components/CopyWriting/CopyWriting.vue')
|
||||
},
|
||||
{
|
||||
path: '/global_setting',
|
||||
name: 'global_setting',
|
||||
component: () => import('./components/Setting/Setting.vue')
|
||||
},
|
||||
{
|
||||
path: '/clip_setting',
|
||||
name: 'clip_setting',
|
||||
component: () => import('./components/Setting/ClipSetting.vue')
|
||||
},
|
||||
{
|
||||
path: '/getframe',
|
||||
name: 'getframe',
|
||||
component: () => import('./components/Backstep/GetFrame.vue')
|
||||
},
|
||||
{
|
||||
path: '/pushBackPrompt',
|
||||
name: 'pushBackPrompt',
|
||||
component: () => import('./components/Backstep/PushBackPrompt.vue')
|
||||
},
|
||||
{
|
||||
path: '/regenerate',
|
||||
name: 'regenerate',
|
||||
component: () => import('./components/Backstep/ReGenerate.vue')
|
||||
},
|
||||
{
|
||||
path: '/align_draft',
|
||||
name: 'align_draft',
|
||||
component: () => import('./components/Clip/AlignDraft.vue')
|
||||
},
|
||||
{
|
||||
path: '/add_draft',
|
||||
name: 'add_draft',
|
||||
component: () => import('./components/Clip/AddDraft.vue')
|
||||
},
|
||||
{
|
||||
path: '/VideoGenerate',
|
||||
name: 'VideoGenerate',
|
||||
component: () => import('./components/Backstep/VideoGenerate.vue')
|
||||
},
|
||||
{
|
||||
path: '/sd_setting',
|
||||
name: 'sd_setting',
|
||||
component: () => import('./components/Setting/SDSetting.vue')
|
||||
},
|
||||
{
|
||||
path: '/copywriting',
|
||||
name: 'copywriting',
|
||||
component: () => import('./components/Backstep/CopyWriting.vue')
|
||||
},
|
||||
{
|
||||
path: '/videogeneratesetting',
|
||||
name: 'videogeneratesetting',
|
||||
component: () => import('./components/Setting/VideoGenerateSetting.vue')
|
||||
},
|
||||
{
|
||||
path: '/ShowMessage',
|
||||
name: 'ShowMessage',
|
||||
component: () => import('./components/Home/ShowMessage.vue')
|
||||
},
|
||||
{
|
||||
path: '/sdoriginal',
|
||||
name: 'sdoriginal',
|
||||
component: () => import('./components/Original/MainPage.vue')
|
||||
},
|
||||
{
|
||||
path: '/mj_setting',
|
||||
name: 'mj_setting',
|
||||
component: () => import('./components/Setting/MJSetting.vue')
|
||||
},
|
||||
{
|
||||
path: '/reverse_management',
|
||||
name: 'reverse_management',
|
||||
component: () => import('./components/ReverseManage/ReverseManage.vue')
|
||||
},
|
||||
{
|
||||
path: '/manage_book/:id',
|
||||
name: 'manage_book',
|
||||
component: () => import('./components/ReverseManage/ManageBookDetail.vue')
|
||||
},
|
||||
{
|
||||
path: '/test_options',
|
||||
name: 'test_options',
|
||||
component: () => import('./components/VideoSubtitle/VideoCanvas.vue')
|
||||
},
|
||||
{
|
||||
path : "/TTS_Services",
|
||||
name : "TTS_Services",
|
||||
component : () => import('./components/TTS/TTSHome.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: '/ReDrawImage', component: () => import('./components/Home/ReDrawImageWD.vue') }
|
||||
]
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
})
|
||||
app.use(router);
|
||||
app.use(router)
|
||||
app.use(pinia)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
Reference in New Issue
Block a user