fix/feat: XTTS-Voice korrekt persistiert, Loeschen + Voice-per-Request
Bug-Fix: Voice-Auswahl verschwand nach Page-Load - xtts_voices_list Handler rebuildet das Dropdown — vorheriger select.value ging dabei verloren. Jetzt wird der Wert gemerkt und nach Rebuild wiederhergestellt (falls die Stimme noch existiert). Feature: Stimmen loeschen (Diagnostic) - XTTS-Bridge: neuer handleDeleteVoice — entfernt /voices/<name>.wav und schickt aktualisierte Liste per xtts_voices_list - RVS: xtts_delete_voice in ALLOWED_TYPES - Diagnostic Server: Action xtts_delete_voice forwarded via RVS - Diagnostic UI: renderVoiceList zeigt alle Custom-Voices mit X-Button Bei Loeschen der gerade aktiven Stimme: auf Default zuruecksetzen Feature: Voice-per-Request in Bridge - App kann mit jedem Chat ein voice-Feld mitschicken - Bridge merkt sich _next_voice_override, nutzt es fuer die NAECHSTE ARIA-Antwort (einmalig, dann reset) - tts_request (Play-Button) akzeptiert voice im Payload als Override - Fallback: globale xtts_voice aus voice_config.json - So kann jedes Geraet seine eigene Stimme haben ohne den globalen Default zu aendern Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-3
@@ -498,6 +498,10 @@ class ARIABridge:
|
||||
self._last_chat_final_at: float = 0.0
|
||||
# requestId → messageId Map fuer XTTS-Audio-Cache (App-seitige Zuordnung)
|
||||
self._xtts_request_to_message: dict[str, str] = {}
|
||||
# Voice-Override aus letzter Chat-Nachricht einer App.
|
||||
# Wird fuer die direkt folgende ARIA-Antwort genutzt und dann zurueckgesetzt.
|
||||
# So kann jedes Geraet seine bevorzugte Stimme bekommen (pro Request).
|
||||
self._next_voice_override: Optional[str] = None
|
||||
|
||||
def initialize(self) -> None:
|
||||
"""Initialisiert alle Komponenten.
|
||||
@@ -856,14 +860,19 @@ class ARIABridge:
|
||||
logger.info("[core] TTS unterdrueckt (Modus: %s)", self.current_mode.config.name)
|
||||
return
|
||||
|
||||
xtts_voice = getattr(self, 'xtts_voice', '')
|
||||
# Voice bestimmen: App-Override fuer diesen Request > globale Default-Voice
|
||||
xtts_voice = self._next_voice_override or getattr(self, 'xtts_voice', '')
|
||||
# Override verbrauchen (gilt nur fuer genau diese naechste Antwort)
|
||||
if self._next_voice_override:
|
||||
logger.info("[core] Nutze Voice-Override: %s", self._next_voice_override)
|
||||
self._next_voice_override = None
|
||||
|
||||
tts_text = tts_text_preview or text
|
||||
if not tts_text:
|
||||
logger.info("[core] TTS-Text leer nach Cleanup — uebersprungen")
|
||||
return
|
||||
try:
|
||||
xtts_request_id = str(uuid.uuid4())
|
||||
# Map fuer audio_pcm/xtts_response → App-Cache Zuordnung
|
||||
self._xtts_request_to_message[xtts_request_id] = message_id
|
||||
if len(self._xtts_request_to_message) > 100:
|
||||
oldest = next(iter(self._xtts_request_to_message))
|
||||
@@ -1031,6 +1040,11 @@ class ARIABridge:
|
||||
if sender in ("aria", "stt"):
|
||||
return
|
||||
text = payload.get("text", "")
|
||||
# Voice-Override fuer die naechste ARIA-Antwort merken
|
||||
voice_override = payload.get("voice", "")
|
||||
if voice_override:
|
||||
self._next_voice_override = voice_override
|
||||
logger.info("[rvs] Voice-Override fuer naechste Antwort: %s", voice_override)
|
||||
if text:
|
||||
logger.info("[rvs] App-Chat: '%s'", text[:80])
|
||||
await self.send_to_core(text, source="app")
|
||||
@@ -1096,7 +1110,8 @@ class ARIABridge:
|
||||
if not text:
|
||||
return
|
||||
tts_text = clean_text_for_tts(text) or text
|
||||
xtts_voice = getattr(self, 'xtts_voice', '')
|
||||
# Voice aus App-Payload gewinnt, sonst global
|
||||
xtts_voice = payload.get("voice", "") or getattr(self, 'xtts_voice', '')
|
||||
try:
|
||||
xtts_request_id = str(uuid.uuid4())
|
||||
if message_id:
|
||||
|
||||
Reference in New Issue
Block a user