feat: add option to remove reasoning tag from TTS output

This commit is contained in:
n4ze3m 2025-02-09 13:00:04 +05:30
parent 023d3c2fb2
commit 084b859e3e
21 changed files with 106 additions and 10 deletions

View File

@ -119,6 +119,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "تمكين SSML (لغة ترميز توليف الكلام)" "label": "تمكين SSML (لغة ترميز توليف الكلام)"
},
"removeReasoningTagTTS": {
"label": "إزالة علامة التفكير من تحويل النص إلى كلام"
} }
} }
}, },

View File

@ -113,6 +113,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Aktiver SSML (Speech Synthesis Markup Language)" "label": "Aktiver SSML (Speech Synthesis Markup Language)"
},
"removeReasoningTagTTS": {
"label": "Fjern Ræsonnement Tag fra TTS"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "SSML (Speech Synthesis Markup Language) aktivieren" "label": "SSML (Speech Synthesis Markup Language) aktivieren"
},
"removeReasoningTagTTS": {
"label": "Reasoning-Tag aus Text-zu-Sprache entfernen"
} }
} }
}, },

View File

@ -122,6 +122,9 @@
}, },
"responseSplitting": { "responseSplitting": {
"label": "Response Splitting" "label": "Response Splitting"
},
"removeReasoningTagTTS": {
"label": "Remove Reasoning Tag from TTS"
} }
} }
}, },

View File

@ -116,8 +116,10 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Habilitar SSML (Speech Synthesis Markup Language)" "label": "Habilitar SSML (Speech Synthesis Markup Language)"
} },
} "removeReasoningTagTTS": {
"label": "Eliminar Etiqueta de Razonamiento del TTS"
} }
}, },
"manageModels": { "manageModels": {
"title": "Administar de Modelos", "title": "Administar de Modelos",

View File

@ -113,6 +113,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "فعال کردن SSML (Speech Synthesis Markup Language)" "label": "فعال کردن SSML (Speech Synthesis Markup Language)"
},
"removeReasoningTagTTS": {
"label": "حذف برچسب استدلال از تبدیل متن به گفتار"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Activer SSML (langage de balisage de synthèse vocale)" "label": "Activer SSML (langage de balisage de synthèse vocale)"
},
"removeReasoningTagTTS": {
"label": "Supprimer la balise de raisonnement de la synthèse vocale"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Abilita SSML (Speech Synthesis Markup Language)" "label": "Abilita SSML (Speech Synthesis Markup Language)"
},
"removeReasoningTagTTS": {
"label": "Rimuovi Tag di Ragionamento dal TTS"
} }
} }
}, },

View File

@ -119,6 +119,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "SSML (Speech Synthesis Markup Language) を有効にする" "label": "SSML (Speech Synthesis Markup Language) を有効にする"
},
"removeReasoningTagTTS": {
"label": "テキスト読み上げから推論タグを削除"
} }
} }
}, },

View File

@ -119,6 +119,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "SSML (Speech Synthesis Markup Language) 활성화" "label": "SSML (Speech Synthesis Markup Language) 활성화"
},
"removeReasoningTagTTS": {
"label": "TTS에서 추론 태그 제거"
} }
} }
}, },

View File

@ -119,6 +119,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "SSML (സ്പീച്ച് സിന്തസിസ് മാർക്കപ്പ് ലാംഗ്വേജ്) പ്രവർത്തനക്ഷമമാക്കുക" "label": "SSML (സ്പീച്ച് സിന്തസിസ് മാർക്കപ്പ് ലാംഗ്വേജ്) പ്രവർത്തനക്ഷമമാക്കുക"
},
"removeReasoningTagTTS": {
"label": "ടിടിഎസിൽ നിന്ന് റീസണിംഗ് ടാഗ് നീക്കം ചെയ്യുക"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Aktiver SSML (Speech Synthesis Markup Language)" "label": "Aktiver SSML (Speech Synthesis Markup Language)"
},
"removeReasoningTagTTS": {
"label": "Fjern Resonneringsmerke fra TTS"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Ativar SSML (Linguagem de Marcação de Síntese de Fala)" "label": "Ativar SSML (Linguagem de Marcação de Síntese de Fala)"
},
"removeReasoningTagTTS": {
"label": "Remover Tag de Raciocínio do TTS"
} }
} }
}, },

View File

@ -117,6 +117,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Включить SSML (язык разметки синтеза речи)" "label": "Включить SSML (язык разметки синтеза речи)"
},
"removeReasoningTagTTS": {
"label": "Удалить тег рассуждения из TTS"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Aktivera SSML (Speech Synthesis Markup Language)" "label": "Aktivera SSML (Speech Synthesis Markup Language)"
},
"removeReasoningTagTTS": {
"label": "Ta bort resonemangstagg från Text till Tal"
} }
} }
}, },

View File

@ -116,6 +116,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "Ввімкнути SSML (Мова Розмітки для Синтезу Голосу)" "label": "Ввімкнути SSML (Мова Розмітки для Синтезу Голосу)"
},
"removeReasoningTagTTS": {
"label": "Видалити тег міркування з TTS"
} }
} }
}, },

View File

@ -119,6 +119,9 @@
}, },
"ssmlEnabled": { "ssmlEnabled": {
"label": "启用SSML(语音合成标记语言)" "label": "启用SSML(语音合成标记语言)"
},
"removeReasoningTagTTS": {
"label": "从语音合成中移除推理标签"
} }
} }
}, },

View File

@ -18,7 +18,7 @@ import { useTTS } from "@/hooks/useTTS"
import { tagColors } from "@/utils/color" import { tagColors } from "@/utils/color"
import { removeModelSuffix } from "@/db/models" import { removeModelSuffix } from "@/db/models"
import { GenerationInfo } from "./GenerationInfo" import { GenerationInfo } from "./GenerationInfo"
import { parseReasoning, removeReasoning } from "@/libs/reasoning" import { parseReasoning, } from "@/libs/reasoning"
import { humanizeMilliseconds } from "@/utils/humanize-milliseconds" import { humanizeMilliseconds } from "@/utils/humanize-milliseconds"
type Props = { type Props = {
message: string message: string
@ -213,7 +213,7 @@ export const PlaygroundMessage = (props: Props) => {
cancel() cancel()
} else { } else {
speak({ speak({
utterance: removeReasoning(props.message) utterance: props.message
}) })
} }
}} }}

View File

@ -17,6 +17,7 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
ttsProvider: "", ttsProvider: "",
voice: "", voice: "",
ssmlEnabled: false, ssmlEnabled: false,
removeReasoningTagTTS: true,
elevenLabsApiKey: "", elevenLabsApiKey: "",
elevenLabsVoiceId: "", elevenLabsVoiceId: "",
elevenLabsModel: "", elevenLabsModel: "",
@ -209,6 +210,20 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
</div> </div>
</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.removeReasoningTagTTS.label")}
</span>
<div>
<Switch
className="mt-4 sm:mt-0"
{...form.getInputProps("removeReasoningTagTTS", {
type: "checkbox"
})}
/>
</div>
</div>
<div className="flex justify-end"> <div className="flex justify-end">
<SaveButton btnType="submit" /> <SaveButton btnType="submit" />
</div> </div>

View File

@ -4,6 +4,7 @@ import {
getElevenLabsApiKey, getElevenLabsApiKey,
getElevenLabsModel, getElevenLabsModel,
getElevenLabsVoiceId, getElevenLabsVoiceId,
getRemoveReasoningTagTTS,
getTTSProvider, getTTSProvider,
getVoice, getVoice,
isSSMLEnabled isSSMLEnabled
@ -11,6 +12,7 @@ import {
import { markdownToSSML } from "@/utils/markdown-to-ssml" import { markdownToSSML } from "@/utils/markdown-to-ssml"
import { generateSpeech } from "@/services/elevenlabs" import { generateSpeech } from "@/services/elevenlabs"
import { splitMessageContent } from "@/utils/tts" import { splitMessageContent } from "@/utils/tts"
import { removeReasoning } from "@/libs/reasoning"
export interface VoiceOptions { export interface VoiceOptions {
utterance: string utterance: string
@ -26,6 +28,11 @@ export const useTTS = () => {
try { try {
const voice = await getVoice() const voice = await getVoice()
const provider = await getTTSProvider() const provider = await getTTSProvider()
const isRemoveReasoning = await getRemoveReasoningTagTTS()
if (isRemoveReasoning) {
utterance = removeReasoning(utterance)
}
if (provider === "browser") { if (provider === "browser") {
const isSSML = await isSSMLEnabled() const isSSML = await isSSMLEnabled()
@ -115,7 +122,10 @@ export const useTTS = () => {
return return
} }
if (import.meta.env.BROWSER === "chrome" || import.meta.env.BROWSER === "edge") { if (
import.meta.env.BROWSER === "chrome" ||
import.meta.env.BROWSER === "edge"
) {
chrome.tts.stop() chrome.tts.stop()
} else { } else {
window.speechSynthesis.cancel() window.speechSynthesis.cancel()

View File

@ -1,6 +1,9 @@
import { Storage } from "@plasmohq/storage" import { Storage } from "@plasmohq/storage"
const storage = new Storage() const storage = new Storage()
const storage2 = new Storage({
area: "local"
})
const DEFAULT_TTS_PROVIDER = "browser" const DEFAULT_TTS_PROVIDER = "browser"
@ -98,10 +101,22 @@ export const getResponseSplitting = async () => {
return data return data
} }
export const getRemoveReasoningTagTTS = async () => {
const data = await storage2.get("removeReasoningTagTTS")
if (!data || data.length === 0 || data === "") {
return true
}
return data === "true"
}
export const setResponseSplitting = async (responseSplitting: string) => { export const setResponseSplitting = async (responseSplitting: string) => {
await storage.set("ttsResponseSplitting", responseSplitting) await storage.set("ttsResponseSplitting", responseSplitting)
} }
export const setRemoveReasoningTagTTS = async (removeReasoningTagTTS: boolean) => {
await storage2.set("removeReasoningTagTTS", removeReasoningTagTTS.toString())
}
export const getTTSSettings = async () => { export const getTTSSettings = async () => {
const [ const [
ttsEnabled, ttsEnabled,
@ -112,7 +127,8 @@ export const getTTSSettings = async () => {
elevenLabsApiKey, elevenLabsApiKey,
elevenLabsVoiceId, elevenLabsVoiceId,
elevenLabsModel, elevenLabsModel,
responseSplitting responseSplitting,
removeReasoningTagTTS
] = await Promise.all([ ] = await Promise.all([
isTTSEnabled(), isTTSEnabled(),
getTTSProvider(), getTTSProvider(),
@ -122,7 +138,8 @@ export const getTTSSettings = async () => {
getElevenLabsApiKey(), getElevenLabsApiKey(),
getElevenLabsVoiceId(), getElevenLabsVoiceId(),
getElevenLabsModel(), getElevenLabsModel(),
getResponseSplitting() getResponseSplitting(),
getRemoveReasoningTagTTS()
]) ])
return { return {
@ -134,7 +151,8 @@ export const getTTSSettings = async () => {
elevenLabsApiKey, elevenLabsApiKey,
elevenLabsVoiceId, elevenLabsVoiceId,
elevenLabsModel, elevenLabsModel,
responseSplitting responseSplitting,
removeReasoningTagTTS
} }
} }
@ -146,7 +164,8 @@ export const setTTSSettings = async ({
elevenLabsApiKey, elevenLabsApiKey,
elevenLabsVoiceId, elevenLabsVoiceId,
elevenLabsModel, elevenLabsModel,
responseSplitting responseSplitting,
removeReasoningTagTTS
}: { }: {
ttsEnabled: boolean ttsEnabled: boolean
ttsProvider: string ttsProvider: string
@ -156,6 +175,7 @@ export const setTTSSettings = async ({
elevenLabsVoiceId: string elevenLabsVoiceId: string
elevenLabsModel: string elevenLabsModel: string
responseSplitting: string responseSplitting: string
removeReasoningTagTTS: boolean
}) => { }) => {
await Promise.all([ await Promise.all([
setTTSEnabled(ttsEnabled), setTTSEnabled(ttsEnabled),
@ -165,6 +185,7 @@ export const setTTSSettings = async ({
setElevenLabsApiKey(elevenLabsApiKey), setElevenLabsApiKey(elevenLabsApiKey),
setElevenLabsVoiceId(elevenLabsVoiceId), setElevenLabsVoiceId(elevenLabsVoiceId),
setElevenLabsModel(elevenLabsModel), setElevenLabsModel(elevenLabsModel),
setResponseSplitting(responseSplitting) setResponseSplitting(responseSplitting),
setRemoveReasoningTagTTS(removeReasoningTagTTS)
]) ])
} }