addes speed config for voice

This commit is contained in:
duffyduck 2026-03-29 18:50:09 +02:00
parent a2c0196e05
commit 1ab8a6a2fe
3 changed files with 28 additions and 3 deletions

View File

@ -38,6 +38,7 @@ import websockets
from faster_whisper import WhisperModel from faster_whisper import WhisperModel
from openwakeword.model import Model as WakeWordModel from openwakeword.model import Model as WakeWordModel
from piper import PiperVoice from piper import PiperVoice
from piper.config import SynthesisConfig
from modes import Mode, detect_mode_switch, should_speak from modes import Mode, detect_mode_switch, should_speak
@ -131,6 +132,7 @@ class VoiceEngine:
self.voices: dict[str, PiperVoice] = {} self.voices: dict[str, PiperVoice] = {}
self.default_voice = "ramona" self.default_voice = "ramona"
self.highlight_voice = "thorsten" self.highlight_voice = "thorsten"
self.speech_speed = 1.0 # 0.5 = langsam, 1.0 = normal, 2.0 = schnell
def initialize(self) -> None: def initialize(self) -> None:
"""Laedt die Piper-Stimmen aus dem Voices-Verzeichnis.""" """Laedt die Piper-Stimmen aus dem Voices-Verzeichnis."""
@ -216,8 +218,9 @@ class VoiceEngine:
continue continue
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp: with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
tmp_path = tmp.name tmp_path = tmp.name
syn_config = SynthesisConfig(length_scale=1.0 / max(0.3, self.speech_speed))
with wave.open(tmp_path, "wb") as wav_file: with wave.open(tmp_path, "wb") as wav_file:
voice.synthesize_wav(sentence, wav_file) voice.synthesize_wav(sentence, wav_file, syn_config=syn_config)
with wave.open(tmp_path, "rb") as wav_file: with wave.open(tmp_path, "rb") as wav_file:
if sample_rate is None: if sample_rate is None:
sample_rate = wav_file.getframerate() sample_rate = wav_file.getframerate()
@ -494,6 +497,7 @@ class ARIABridge:
vc = json.load(f) vc = json.load(f)
self.voice_engine.default_voice = vc.get("defaultVoice", "ramona") self.voice_engine.default_voice = vc.get("defaultVoice", "ramona")
self.voice_engine.highlight_voice = vc.get("highlightVoice", "thorsten") self.voice_engine.highlight_voice = vc.get("highlightVoice", "thorsten")
self.voice_engine.speech_speed = vc.get("speechSpeed", 1.0)
self.tts_enabled = vc.get("ttsEnabled", True) self.tts_enabled = vc.get("ttsEnabled", True)
logger.info("Voice-Config geladen: %s", vc) logger.info("Voice-Config geladen: %s", vc)
except Exception as e: except Exception as e:
@ -1024,6 +1028,10 @@ class ARIABridge:
self.tts_enabled = bool(payload["ttsEnabled"]) self.tts_enabled = bool(payload["ttsEnabled"])
logger.info("[rvs] TTS %s", "aktiviert" if self.tts_enabled else "deaktiviert") logger.info("[rvs] TTS %s", "aktiviert" if self.tts_enabled else "deaktiviert")
changed = True changed = True
if "speechSpeed" in payload:
self.voice_engine.speech_speed = max(0.3, min(2.0, float(payload["speechSpeed"])))
logger.info("[rvs] Sprechgeschwindigkeit: %.1f", self.voice_engine.speech_speed)
changed = True
# Persistent speichern in Shared Volume # Persistent speichern in Shared Volume
if changed: if changed:
try: try:
@ -1032,6 +1040,7 @@ class ARIABridge:
"defaultVoice": self.voice_engine.default_voice, "defaultVoice": self.voice_engine.default_voice,
"highlightVoice": self.voice_engine.highlight_voice, "highlightVoice": self.voice_engine.highlight_voice,
"ttsEnabled": getattr(self, "tts_enabled", True), "ttsEnabled": getattr(self, "tts_enabled", True),
"speechSpeed": self.voice_engine.speech_speed,
} }
with open("/shared/config/voice_config.json", "w") as f: with open("/shared/config/voice_config.json", "w") as f:
json.dump(config_data, f, indent=2) json.dump(config_data, f, indent=2)

View File

@ -414,10 +414,21 @@
<option value="ramona">Ramona (weiblich)</option> <option value="ramona">Ramona (weiblich)</option>
</select> </select>
</div> </div>
<div style="display:flex;align-items:center;gap:12px;"> <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
<label style="color:#8888AA;font-size:12px;">TTS aktiv:</label> <label style="color:#8888AA;font-size:12px;">TTS aktiv:</label>
<label class="toggle"><input type="checkbox" id="diag-tts-enabled" checked onchange="sendVoiceConfig()"><span class="slider"></span></label> <label class="toggle"><input type="checkbox" id="diag-tts-enabled" checked onchange="sendVoiceConfig()"><span class="slider"></span></label>
</div> </div>
<div style="margin-bottom:4px;">
<label style="color:#8888AA;font-size:12px;">Sprechgeschwindigkeit: <span id="speed-label">1.0x</span></label>
</div>
<div style="display:flex;align-items:center;gap:8px;">
<span style="color:#555570;font-size:11px;">0.5x</span>
<input type="range" id="diag-speech-speed" min="0.5" max="2.0" step="0.1" value="1.0"
oninput="document.getElementById('speed-label').textContent=this.value+'x'"
onchange="sendVoiceConfig()"
style="flex:1;accent-color:#0096FF;">
<span style="color:#555570;font-size:11px;">2.0x</span>
</div>
</div> </div>
</div> </div>
@ -646,6 +657,9 @@
document.getElementById('diag-default-voice').value = msg.defaultVoice || 'ramona'; document.getElementById('diag-default-voice').value = msg.defaultVoice || 'ramona';
document.getElementById('diag-highlight-voice').value = msg.highlightVoice || 'thorsten'; document.getElementById('diag-highlight-voice').value = msg.highlightVoice || 'thorsten';
document.getElementById('diag-tts-enabled').checked = msg.ttsEnabled !== false; document.getElementById('diag-tts-enabled').checked = msg.ttsEnabled !== false;
const speed = msg.speechSpeed || 1.0;
document.getElementById('diag-speech-speed').value = speed;
document.getElementById('speed-label').textContent = speed + 'x';
return; return;
} }
@ -1143,7 +1157,8 @@
const defaultVoice = document.getElementById('diag-default-voice').value; const defaultVoice = document.getElementById('diag-default-voice').value;
const highlightVoice = document.getElementById('diag-highlight-voice').value; const highlightVoice = document.getElementById('diag-highlight-voice').value;
const ttsEnabled = document.getElementById('diag-tts-enabled').checked; const ttsEnabled = document.getElementById('diag-tts-enabled').checked;
send({ action: 'send_voice_config', defaultVoice, highlightVoice, ttsEnabled }); const speechSpeed = parseFloat(document.getElementById('diag-speech-speed').value);
send({ action: 'send_voice_config', defaultVoice, highlightVoice, ttsEnabled, speechSpeed });
} }
// ── Highlight-Trigger ──────────────────────── // ── Highlight-Trigger ────────────────────────

View File

@ -1135,6 +1135,7 @@ wss.on("connection", (ws) => {
defaultVoice: msg.defaultVoice || "ramona", defaultVoice: msg.defaultVoice || "ramona",
highlightVoice: msg.highlightVoice || "thorsten", highlightVoice: msg.highlightVoice || "thorsten",
ttsEnabled: msg.ttsEnabled !== false, ttsEnabled: msg.ttsEnabled !== false,
speechSpeed: msg.speechSpeed || 1.0,
}; };
try { try {
fs.mkdirSync("/shared/config", { recursive: true }); fs.mkdirSync("/shared/config", { recursive: true });