feat: Add ElevenLabs TTS provider and response splitting options

This commit is contained in:
n4ze3m
2024-12-28 20:10:50 +05:30
parent aa49f03f63
commit 3ddb7f1ad8
7 changed files with 454 additions and 57 deletions

View File

@@ -1,9 +1,10 @@
import { SaveButton } from "@/components/Common/SaveButton"
import { getModels, getVoices } from "@/services/elevenlabs"
import { getTTSSettings, setTTSSettings } from "@/services/tts"
import { useWebUI } from "@/store/webui"
import { useForm } from "@mantine/form"
import { useQuery } from "@tanstack/react-query"
import { Select, Skeleton, Switch } from "antd"
import { Input, message, Select, Skeleton, Switch } from "antd"
import { useTranslation } from "react-i18next"
export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
@@ -15,7 +16,11 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
ttsEnabled: false,
ttsProvider: "",
voice: "",
ssmlEnabled: false
ssmlEnabled: false,
elevenLabsApiKey: "",
elevenLabsVoiceId: "",
elevenLabsModel: "",
responseSplitting: ""
}
})
@@ -28,6 +33,27 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
}
})
const { data: elevenLabsData } = useQuery({
queryKey: ["fetchElevenLabsData", form.values.elevenLabsApiKey],
queryFn: async () => {
try {
if (
form.values.ttsProvider === "elevenlabs" &&
form.values.elevenLabsApiKey
) {
const voices = await getVoices(form.values.elevenLabsApiKey)
const models = await getModels(form.values.elevenLabsApiKey)
return { voices, models }
}
} catch (e) {
console.log(e)
message.error("Error fetching ElevenLabs data")
}
return null
},
enabled:
form.values.ttsProvider === "elevenlabs" && !!form.values.elevenLabsApiKey
})
if (status === "pending" || status === "error") {
return <Skeleton active />
}
@@ -72,29 +98,103 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
<Select
placeholder={t("generalSettings.tts.ttsProvider.placeholder")}
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
options={[{ label: "Browser TTS", value: "browser" }]}
options={[
{ label: "Browser TTS", value: "browser" },
{
label: "ElevenLabs",
value: "elevenlabs"
}
]}
{...form.getInputProps("ttsProvider")}
/>
</div>
</div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ttsVoice.label")}
</span>
<div>
<Select
placeholder={t("generalSettings.tts.ttsVoice.placeholder")}
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
options={data?.browserTTSVoices?.map(
(voice) => ({
{form.values.ttsProvider === "browser" && (
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ttsVoice.label")}
</span>
<div>
<Select
placeholder={t("generalSettings.tts.ttsVoice.placeholder")}
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
options={data?.browserTTSVoices?.map((voice) => ({
label: `${voice.voiceName} - ${voice.lang}`.trim(),
value: voice.voiceName
})
)}
{...form.getInputProps("voice")}
/>
}))}
{...form.getInputProps("voice")}
/>
</div>
</div>
</div>
)}
{form.values.ttsProvider === "elevenlabs" && (
<>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50">
API Key
</span>
<Input.Password
placeholder="sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
className=" mt-4 sm:mt-0 !w-[300px] sm:w-[200px]"
required
{...form.getInputProps("elevenLabsApiKey")}
/>
</div>
{elevenLabsData && (
<>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50">
TTS Voice
</span>
<Select
options={elevenLabsData.voices.map((v) => ({
label: v.name,
value: v.voice_id
}))}
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
placeholder="Select a voice"
{...form.getInputProps("elevenLabsVoiceId")}
/>
</div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50">
TTS Model
</span>
<Select
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
placeholder="Select a model"
options={elevenLabsData.models.map((m) => ({
label: m.name,
value: m.model_id
}))}
{...form.getInputProps("elevenLabsModel")}
/>
</div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.responseSplitting.label")}
</span>
<div>
<Select
placeholder={t(
"generalSettings.tts.responseSplitting.placeholder"
)}
className="w-full mt-4 sm:mt-0 sm:w-[200px]"
options={[
{ label: "None", value: "none" },
{ label: "Punctuation", value: "punctuation" },
{ label: "Paragraph", value: "paragraph" }
]}
{...form.getInputProps("responseSplitting")}
/>
</div>
</div>
</>
)}
</>
)}
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ssmlEnabled.label")}