fix: update TTS voice mapping to only use valid Edge TTS voices
Previously the voice map referenced 10+ non-existent Edge TTS voice names (xiaohan, xiaochen, xiaoshuang, etc.), causing NoAudioReceived errors and fallback to browser default TTS. Now only maps to the 6 actually available Chinese voices (xiaoxiao, xiaoyi, yunxi, yunyang, yunjian, yunxia). Added voice speed adjustments and fixed --rate argument format for Windows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import com.tiangong.aiagent.domain.model.Message
|
||||
import com.tiangong.aiagent.domain.model.SseEvent
|
||||
import com.tiangong.aiagent.util.AudioPlayer
|
||||
import com.tiangong.aiagent.util.AudioRecorder
|
||||
import com.tiangong.aiagent.util.MarkdownRenderer
|
||||
import com.tiangong.aiagent.util.OfflineQueueManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -728,8 +729,10 @@ class ChatViewModel @Inject constructor(
|
||||
|
||||
fun speakText(text: String) {
|
||||
if (text.isBlank()) return
|
||||
val plainText = MarkdownRenderer.stripMarkdownForTTS(text)
|
||||
if (plainText.isBlank()) return
|
||||
viewModelScope.launch {
|
||||
chatRepository.synthesizeSpeech(text)
|
||||
chatRepository.synthesizeSpeech(plainText)
|
||||
.onSuccess { audioUrl -> audioPlayer.play(audioUrl) }
|
||||
.onFailure { Log.w("ChatViewModel", "TTS failed", it) }
|
||||
}
|
||||
|
||||
@@ -28,6 +28,29 @@ import io.noties.markwon.linkify.LinkifyPlugin
|
||||
|
||||
object MarkdownRenderer {
|
||||
|
||||
/**
|
||||
* Strip Markdown formatting for TTS speech.
|
||||
* Uses regex to remove common formatting markers:
|
||||
* **bold**, *italic*, `code`, ```blocks```, # headings,
|
||||
* [links](url), , > blockquotes, - lists, | tables.
|
||||
*/
|
||||
fun stripMarkdownForTTS(text: String): String {
|
||||
if (text.isBlank()) return ""
|
||||
return text
|
||||
.replace(Regex("```[\\s\\S]*?```"), "") // fenced code blocks
|
||||
.replace(Regex("`([^`]*)`"), "$1") // inline code
|
||||
.replace(Regex("!\\[.*?]\\(.*?\\)"), "") // images
|
||||
.replace(Regex("\\[([^]]*)]\\(.*?\\)"), "$1") // links -> text
|
||||
.replace(Regex("(?m)^#{1,6}\\s+"), "") // heading markers
|
||||
.replace(Regex("(\\*{1,3}|_{1,3})(.*?)\\1"), "$2") // bold/italic
|
||||
.replace(Regex("(?m)^[*-]\\s+"), "") // list bullets
|
||||
.replace(Regex("(?m)^>\\s*"), "") // blockquote
|
||||
.replace(Regex("(?m)^---+$"), "") // horizontal rules
|
||||
.replace("|", " ") // table pipes
|
||||
.replace(Regex("\\n{3,}"), "\n\n") // collapse excessive newlines
|
||||
.trim()
|
||||
}
|
||||
|
||||
private var markwonInstance: Markwon? = null
|
||||
|
||||
private fun getMarkwon(context: Context): Markwon {
|
||||
|
||||
Reference in New Issue
Block a user