Commit 245f50d5 authored by Dazzle Wu's avatar Dazzle Wu

fix: 视频数字人位置、声音配置

parent 7c1f5846
<script setup lang="ts"> <script setup lang="ts">
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { TimbreItem } from '@/store/types/creation' import { TimbreItem } from '@/store/types/creation'
import { computed, ref } from 'vue' import { computed } from 'vue'
interface Props { interface Props {
value?: TimbreItem value?: TimbreItem
...@@ -11,19 +11,15 @@ interface Props { ...@@ -11,19 +11,15 @@ interface Props {
interface Emits { interface Emits {
(e: 'click', value: TimbreItem): void (e: 'click', value: TimbreItem): void
(e: 'toggle', value: boolean): void (e: 'toggle', value: boolean): void
(e: 'play', value: string): void
} }
defineProps<Props>() defineProps<Props>()
const emit = defineEmits<Emits>() const emit = defineEmits<Emits>()
const digitalCreationStore = useDigitalCreationStore() const digitalCreationStore = useDigitalCreationStore()
const digitalAudio = ref<HTMLAudioElement>()
const person = computed(() => digitalCreationStore.person) const person = computed(() => digitalCreationStore.person)
function playAudio() {
digitalAudio.value?.play()
}
</script> </script>
<template> <template>
...@@ -39,7 +35,11 @@ function playAudio() { ...@@ -39,7 +35,11 @@ function playAudio() {
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<div class="mb-2 flex items-center gap-2"> <div class="mb-2 flex items-center gap-2">
<div class="max-w-32 truncate">{{ value?.name }}</div> <div class="max-w-32 truncate">{{ value?.name }}</div>
<CustomIcon class="cursor-pointer text-lg" icon="mingcute:volume-line" @click.stop.prevent="playAudio" /> <CustomIcon
class="cursor-pointer text-lg"
icon="mingcute:volume-line"
@click.stop.prevent="emit('play', value!.audioUrl)"
/>
</div> </div>
<div class="flex gap-1"> <div class="flex gap-1">
<n-tag v-for="(style, index) in value?.style" :key="index" type="warning" size="tiny" round>{{ style }}</n-tag> <n-tag v-for="(style, index) in value?.style" :key="index" type="warning" size="tiny" round>{{ style }}</n-tag>
...@@ -49,6 +49,4 @@ function playAudio() { ...@@ -49,6 +49,4 @@ function playAudio() {
<CustomIcon class="cursor-pointer text-lg" icon="ant-design:swap-outlined" @click="emit('toggle', true)" /> <CustomIcon class="cursor-pointer text-lg" icon="ant-design:swap-outlined" @click="emit('toggle', true)" />
</div> </div>
</div> </div>
<audio ref="digitalAudio" :src="value?.audioUrl"></audio>
</template> </template>
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
import { fetchDigitalHumanTimbreList, fetchTimbreByExample } from '@/apis/digital-creation' import { fetchDigitalHumanTimbreList, fetchTimbreByExample } from '@/apis/digital-creation'
import { useAudioSettingStore } from '@/store/modules/audio-setting' import { useAudioSettingStore } from '@/store/modules/audio-setting'
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { LangType, TimbreItem, VoiceType } from '@/store/types/creation' import { LangType, TimbreItem, VoiceType } from '@/store/types/creation'
import { computed, onMounted, ref, watch } from 'vue' import { computed, nextTick, onMounted, ref, watch } from 'vue'
import DigitalAudioCard from './digital-audio-card.vue' import DigitalAudioCard from './digital-audio-card.vue'
const audioSettingStore = useAudioSettingStore() const audioSettingStore = useAudioSettingStore()
...@@ -36,8 +35,10 @@ const digitalTimbreValue = ref<TimbreItem>() ...@@ -36,8 +35,10 @@ const digitalTimbreValue = ref<TimbreItem>()
const digitalTimbreList = ref<TimbreItem[]>([]) const digitalTimbreList = ref<TimbreItem[]>([])
const digitalTimbreFemaleList = ref<TimbreItem[]>([]) const digitalTimbreFemaleList = ref<TimbreItem[]>([])
const digitalTimbreMaleList = ref<TimbreItem[]>([]) const digitalTimbreMaleList = ref<TimbreItem[]>([])
const showAll = ref(false) const digitalAudio = ref<HTMLAudioElement>()
const audioSrc = ref('')
const searchName = ref('') const searchName = ref('')
const showAll = ref(false)
const langType = computed({ const langType = computed({
get() { get() {
...@@ -84,6 +85,7 @@ watch( ...@@ -84,6 +85,7 @@ watch(
langType.value = LangType.MANDARIN langType.value = LangType.MANDARIN
} else { } else {
digitalTimbreValue.value = digitalTimbreList.value[0] digitalTimbreValue.value = digitalTimbreList.value[0]
langType.value = LangType.CANTONESE
} }
} }
}, },
...@@ -93,13 +95,13 @@ watch( ...@@ -93,13 +95,13 @@ watch(
() => langType.value, () => langType.value,
(newVal) => { (newVal) => {
if (newVal === LangType.CANTONESE) { if (newVal === LangType.CANTONESE) {
digitalCreationStore.setPerson('')
audioSettingStore.setVoiceType(VoiceType.CANTONESE_FEMALE) audioSettingStore.setVoiceType(VoiceType.CANTONESE_FEMALE)
} else { } else {
if (digitalTimbreValue.value?.sex === '男') { digitalCreationStore.setPerson(digitalTimbreValue.value?.timebreId || '')
audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE) audioSettingStore.setVoiceType(
} else { digitalTimbreValue.value?.sex === '男' ? VoiceType.MANDARIN_MALE : VoiceType.MANDARIN_FEMALE,
audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE) )
}
} }
}, },
) )
...@@ -133,6 +135,14 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -133,6 +135,14 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
? audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE) ? audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE)
: audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE) : audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE)
} }
function playAudio(audioUrl: string) {
audioSrc.value && digitalAudio.value?.pause()
audioSrc.value = audioUrl
nextTick(() => {
digitalAudio.value?.play()
})
}
</script> </script>
<template> <template>
...@@ -153,6 +163,7 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -153,6 +163,7 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
:value="digitalTimbreValue" :value="digitalTimbreValue"
show-toggle show-toggle
@toggle="showAll = true" @toggle="showAll = true"
@play="playAudio"
/> />
<div class="mt-4 text-lg">聲音</div> <div class="mt-4 text-lg">聲音</div>
...@@ -198,8 +209,11 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -198,8 +209,11 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
:key="index" :key="index"
:value="timbre" :value="timbre"
@click="handleClickAudioCard" @click="handleClickAudioCard"
@play="playAudio"
/> />
</div> </div>
</div> </div>
<audio ref="digitalAudio" :src="audioSrc"></audio>
</div> </div>
</template> </template>
...@@ -43,18 +43,8 @@ const resizeObserver = new ResizeObserver((entries) => { ...@@ -43,18 +43,8 @@ const resizeObserver = new ResizeObserver((entries) => {
const isLandscape = computed(() => digitalCreationStore.width > digitalCreationStore.height) const isLandscape = computed(() => digitalCreationStore.width > digitalCreationStore.height)
const digitalHumanWidth = ref(0)
// const digitalHumanWidth = computed(
// () => (digitalCreationStore.w * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080),
// )
const digitalHumanHeight = computed(
() => (digitalCreationStore.h * previewContentHeight.value) / (isLandscape.value ? 1080 : 1920),
)
const digitalHumanLeft = computed( const digitalHumanLeft = computed(
() => () => (digitalCreationStore.x * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080),
(digitalCreationStore.x * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080) +
previewContentWidth.value / 2 -
digitalHumanWidth.value / 2,
) )
const digitalHumanTop = computed( const digitalHumanTop = computed(
() => (digitalCreationStore.y * previewContentHeight.value) / (isLandscape.value ? 1080 : 1920), () => (digitalCreationStore.y * previewContentHeight.value) / (isLandscape.value ? 1080 : 1920),
...@@ -77,10 +67,6 @@ onUnmounted(() => { ...@@ -77,10 +67,6 @@ onUnmounted(() => {
previewContent.value && resizeObserver.unobserve(previewContent.value) previewContent.value && resizeObserver.unobserve(previewContent.value)
}) })
function getDigitalHumanWidth() {
digitalHumanWidth.value = digitalHumanImage.value?.width || 0
}
function connectWebSocket() { function connectWebSocket() {
websocket = new WebSocket(url) websocket = new WebSocket(url)
websocket.onopen = () => { websocket.onopen = () => {
...@@ -167,14 +153,11 @@ function controlAudio() { ...@@ -167,14 +153,11 @@ function controlAudio() {
v-if="digitalCreationStore.inputImageUrl" v-if="digitalCreationStore.inputImageUrl"
ref="digitalHumanImage" ref="digitalHumanImage"
:src="digitalCreationStore.inputImageUrl" :src="digitalCreationStore.inputImageUrl"
class="absolute max-w-none object-cover" class="absolute h-full max-w-none -translate-x-1/2 object-cover"
:style="{ :style="{
// width: `${digitalHumanWidth}px`, left: `calc(50% + ${digitalHumanLeft}px)`,
height: `${digitalHumanHeight}px`,
left: `${digitalHumanLeft}px`,
top: `${digitalHumanTop}px`, top: `${digitalHumanTop}px`,
}" }"
@load="getDigitalHumanWidth"
/> />
</div> </div>
</div> </div>
......
...@@ -106,7 +106,7 @@ async function saveDraft(autoSave: boolean = true) { ...@@ -106,7 +106,7 @@ async function saveDraft(autoSave: boolean = true) {
const res = await saveDraftConfig<DraftConfig>(payload) const res = await saveDraftConfig<DraftConfig>(payload)
if (res.code === 0) { if (res.code === 0) {
autoSave ? (autoSaveSuccess.value = true) : window.$message.success('保存成功') autoSave ? (autoSaveSuccess.value = true) : window.$message.success('保存成功')
digitalCreationStore.updateDigitalCreation(res.data) // digitalCreationStore.updateDigitalCreation(res.data)
const temp: DraftConfig = { ...res.data, modifiedTime: '' } const temp: DraftConfig = { ...res.data, modifiedTime: '' }
savedConfig.value = temp savedConfig.value = temp
} }
...@@ -125,7 +125,7 @@ function confirmExport() { ...@@ -125,7 +125,7 @@ function confirmExport() {
window.$message.error('請輸入視頻名稱') window.$message.error('請輸入視頻名稱')
return false return false
} }
if (!userCurrency.value) { if (userCurrency.value < consumption.value) {
window.$message.error('餘額不足') window.$message.error('餘額不足')
return false return false
} }
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
import { fetchDraftConfigById } from '@/apis/digital-creation' import { fetchDraftConfigById } from '@/apis/digital-creation'
import { fetchGetTaskConfig } from '@/apis/opus' import { fetchGetTaskConfig } from '@/apis/opus'
import { fetchDigitalHumanTemplateStatus } from '@/apis/template' import { fetchDigitalHumanTemplateStatus } from '@/apis/template'
import { useAudioSettingStore } from '@/store/modules/audio-setting'
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { DraftConfig, ScreenType } from '@/store/types/creation' import { DraftConfig, LangType, ScreenType, VoiceType } from '@/store/types/creation'
import { DigitalTemplate } from '@/store/types/template' import { DigitalTemplate } from '@/store/types/template'
import { formatDateTime } from '@/utils/date-formatter' import { formatDateTime } from '@/utils/date-formatter'
import { onMounted } from 'vue' import { onMounted } from 'vue'
...@@ -19,6 +20,7 @@ interface Props { ...@@ -19,6 +20,7 @@ interface Props {
const props = defineProps<Props>() const props = defineProps<Props>()
const audioSettingStore = useAudioSettingStore()
const digitalCreationStore = useDigitalCreationStore() const digitalCreationStore = useDigitalCreationStore()
onMounted(() => { onMounted(() => {
...@@ -77,6 +79,8 @@ async function getDigitalTemplate(id: string) { ...@@ -77,6 +79,8 @@ async function getDigitalTemplate(id: string) {
pronunciationLanguage: digitalCreationStore.pronunciationLanguage, pronunciationLanguage: digitalCreationStore.pronunciationLanguage,
} }
digitalCreationStore.updateDigitalCreation(draftConfig) digitalCreationStore.updateDigitalCreation(draftConfig)
audioSettingStore.setLanType(draftConfig.person ? LangType.MANDARIN : LangType.CANTONESE)
audioSettingStore.setVoiceType(draftConfig.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
...@@ -84,6 +88,8 @@ async function getDraft(id: string) { ...@@ -84,6 +88,8 @@ async function getDraft(id: string) {
const res = await fetchDraftConfigById<DraftConfig>(id) const res = await fetchDraftConfigById<DraftConfig>(id)
if (res.code === 0) { if (res.code === 0) {
digitalCreationStore.updateDigitalCreation(res.data) digitalCreationStore.updateDigitalCreation(res.data)
audioSettingStore.setLanType(res.data.person ? LangType.MANDARIN : LangType.CANTONESE)
audioSettingStore.setVoiceType(res.data.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
...@@ -124,6 +130,8 @@ async function getTaskConfig(id: string) { ...@@ -124,6 +130,8 @@ async function getTaskConfig(id: string) {
pronunciationLanguage: res.data.pronunciationLanguage || digitalCreationStore.pronunciationLanguage, pronunciationLanguage: res.data.pronunciationLanguage || digitalCreationStore.pronunciationLanguage,
} }
digitalCreationStore.updateDigitalCreation(draftConfig) digitalCreationStore.updateDigitalCreation(draftConfig)
audioSettingStore.setLanType(draftConfig.person ? LangType.MANDARIN : LangType.CANTONESE)
audioSettingStore.setVoiceType(draftConfig.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment