90 lines
1.8 KiB
Vue
90 lines
1.8 KiB
Vue
<template>
|
|
<span>
|
|
<span ref="main" :class="class" :lang="lang">
|
|
<slot />
|
|
</span>
|
|
<audio
|
|
style="display: none"
|
|
ref="audio"
|
|
@error="playAudioTTSPlugin()"
|
|
></audio>
|
|
<span>
|
|
<button type="button" @click="playAudio()" :class="$style.speak">
|
|
🗣️
|
|
</button>
|
|
</span>
|
|
</span>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useTemplateRef } from "vue";
|
|
import { speak, getVoices } from "tauri-plugin-tts-api";
|
|
|
|
defineExpose({
|
|
playAudio,
|
|
});
|
|
|
|
const { lang = "ko-KR" } = defineProps<{
|
|
class?: string;
|
|
lang?: string;
|
|
}>();
|
|
|
|
const mainEl = useTemplateRef("main");
|
|
const audioEl = useTemplateRef("audio");
|
|
|
|
function getMainText() {
|
|
if (!mainEl.value) return "";
|
|
|
|
return mainEl.value.innerText
|
|
.replace(/[*]/gu, " ")
|
|
.replace(/[\p{Ps}\p{Pe}]/gu, "");
|
|
}
|
|
|
|
async function playAudio() {
|
|
if (!mainEl.value) return;
|
|
|
|
if (navigator.platform === "Win32" || !(await playAudioTTSPlugin())) {
|
|
if (!audioEl.value) return;
|
|
|
|
const url = new URL("/api/tts", location.origin);
|
|
url.searchParams.set("voice", "glow-speak:ko_kss");
|
|
url.searchParams.set("text", getMainText());
|
|
|
|
audioEl.value.src = url.href;
|
|
audioEl.value.currentTime = 0;
|
|
audioEl.value.play();
|
|
}
|
|
}
|
|
|
|
async function playAudioTTSPlugin(): Promise<boolean> {
|
|
if (!mainEl.value) return false;
|
|
|
|
const voices = await getVoices(lang);
|
|
if (!voices.length) return false;
|
|
|
|
document.querySelectorAll("audio").forEach((el) => {
|
|
el.pause();
|
|
});
|
|
|
|
const v = voices[Math.floor(Math.random() * voices.length)];
|
|
console.log(JSON.stringify(v));
|
|
await speak({
|
|
text: getMainText(),
|
|
language: null,
|
|
rate: null,
|
|
volume: null,
|
|
pitch: null,
|
|
queueMode: null,
|
|
voiceId: v.id,
|
|
});
|
|
|
|
return true;
|
|
}
|
|
</script>
|
|
|
|
<style module>
|
|
.speak {
|
|
margin-inline-start: 0.2em;
|
|
}
|
|
</style>
|