two speed
This commit is contained in:
parent
1ab8a6a2fe
commit
63560e290b
|
|
@ -74,7 +74,8 @@ const SettingsScreen: React.FC = () => {
|
|||
const [ttsEnabled, setTtsEnabled] = useState(true);
|
||||
const [defaultVoice, setDefaultVoice] = useState('ramona');
|
||||
const [highlightVoice, setHighlightVoice] = useState('thorsten');
|
||||
const [speechSpeed, setSpeechSpeed] = useState(1.0);
|
||||
const [speedRamona, setSpeedRamona] = useState(1.0);
|
||||
const [speedThorsten, setSpeedThorsten] = useState(1.0);
|
||||
const [editingPath, setEditingPath] = useState(false);
|
||||
const [tempPath, setTempPath] = useState('');
|
||||
|
||||
|
|
@ -104,8 +105,11 @@ const SettingsScreen: React.FC = () => {
|
|||
AsyncStorage.getItem('aria_highlight_voice').then(saved => {
|
||||
if (saved) setHighlightVoice(saved);
|
||||
});
|
||||
AsyncStorage.getItem('aria_speech_speed').then(saved => {
|
||||
if (saved) setSpeechSpeed(parseFloat(saved));
|
||||
AsyncStorage.getItem('aria_speed_ramona').then(saved => {
|
||||
if (saved) setSpeedRamona(parseFloat(saved));
|
||||
});
|
||||
AsyncStorage.getItem('aria_speed_thorsten').then(saved => {
|
||||
if (saved) setSpeedThorsten(parseFloat(saved));
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
|
@ -525,41 +529,49 @@ const SettingsScreen: React.FC = () => {
|
|||
</View>
|
||||
</View>
|
||||
|
||||
{/* Sprechgeschwindigkeit */}
|
||||
{/* Sprechgeschwindigkeit Ramona */}
|
||||
<View style={{marginTop: 16}}>
|
||||
<Text style={styles.toggleLabel}>Sprechgeschwindigkeit: {speechSpeed.toFixed(1)}x</Text>
|
||||
<View style={{flexDirection: 'row', alignItems: 'center', gap: 8, marginTop: 8}}>
|
||||
<Text style={{color: '#555570', fontSize: 11}}>0.5x</Text>
|
||||
<View style={{flex: 1}}>
|
||||
<TouchableOpacity
|
||||
style={{height: 30, justifyContent: 'center'}}
|
||||
onPress={(e) => {
|
||||
const layout = e.nativeEvent;
|
||||
// Einfacher Tap-basierter Slider
|
||||
}}
|
||||
>
|
||||
<View style={{height: 4, backgroundColor: '#2A2A3E', borderRadius: 2}}>
|
||||
<View style={{height: 4, backgroundColor: '#0096FF', borderRadius: 2, width: `${((speechSpeed - 0.5) / 1.5) * 100}%`}} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Text style={{color: '#555570', fontSize: 11}}>2.0x</Text>
|
||||
</View>
|
||||
<Text style={styles.toggleLabel}>Ramona Speed: {speedRamona.toFixed(1)}x</Text>
|
||||
<View style={{flexDirection: 'row', justifyContent: 'space-around', marginTop: 8}}>
|
||||
{[0.5, 0.75, 1.0, 1.25, 1.5, 2.0].map(speed => (
|
||||
<TouchableOpacity
|
||||
key={speed}
|
||||
onPress={() => {
|
||||
setSpeechSpeed(speed);
|
||||
AsyncStorage.setItem('aria_speech_speed', String(speed));
|
||||
rvs.send('config' as any, { speechSpeed: speed });
|
||||
setSpeedRamona(speed);
|
||||
AsyncStorage.setItem('aria_speed_ramona', String(speed));
|
||||
rvs.send('config' as any, { speedRamona: speed });
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 10, paddingVertical: 6, borderRadius: 6,
|
||||
backgroundColor: speechSpeed === speed ? '#0096FF' : '#1E1E2E',
|
||||
backgroundColor: speedRamona === speed ? '#0096FF' : '#1E1E2E',
|
||||
}}
|
||||
>
|
||||
<Text style={{color: speechSpeed === speed ? '#fff' : '#8888AA', fontSize: 12, fontWeight: '600'}}>
|
||||
<Text style={{color: speedRamona === speed ? '#fff' : '#8888AA', fontSize: 12, fontWeight: '600'}}>
|
||||
{speed}x
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Sprechgeschwindigkeit Thorsten */}
|
||||
<View style={{marginTop: 16}}>
|
||||
<Text style={styles.toggleLabel}>Thorsten Speed: {speedThorsten.toFixed(1)}x</Text>
|
||||
<View style={{flexDirection: 'row', justifyContent: 'space-around', marginTop: 8}}>
|
||||
{[0.5, 0.75, 1.0, 1.25, 1.5, 2.0].map(speed => (
|
||||
<TouchableOpacity
|
||||
key={speed}
|
||||
onPress={() => {
|
||||
setSpeedThorsten(speed);
|
||||
AsyncStorage.setItem('aria_speed_thorsten', String(speed));
|
||||
rvs.send('config' as any, { speedThorsten: speed });
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 10, paddingVertical: 6, borderRadius: 6,
|
||||
backgroundColor: speedThorsten === speed ? '#0096FF' : '#1E1E2E',
|
||||
}}
|
||||
>
|
||||
<Text style={{color: speedThorsten === speed ? '#fff' : '#8888AA', fontSize: 12, fontWeight: '600'}}>
|
||||
{speed}x
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class VoiceEngine:
|
|||
self.voices: dict[str, PiperVoice] = {}
|
||||
self.default_voice = "ramona"
|
||||
self.highlight_voice = "thorsten"
|
||||
self.speech_speed = 1.0 # 0.5 = langsam, 1.0 = normal, 2.0 = schnell
|
||||
self.speech_speed = {"ramona": 1.0, "thorsten": 1.0}
|
||||
|
||||
def initialize(self) -> None:
|
||||
"""Laedt die Piper-Stimmen aus dem Voices-Verzeichnis."""
|
||||
|
|
@ -218,7 +218,8 @@ class VoiceEngine:
|
|||
continue
|
||||
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
|
||||
tmp_path = tmp.name
|
||||
syn_config = SynthesisConfig(length_scale=1.0 / max(0.3, self.speech_speed))
|
||||
speed = self.speech_speed.get(voice_name, 1.0)
|
||||
syn_config = SynthesisConfig(length_scale=1.0 / max(0.3, speed))
|
||||
with wave.open(tmp_path, "wb") as wav_file:
|
||||
voice.synthesize_wav(sentence, wav_file, syn_config=syn_config)
|
||||
with wave.open(tmp_path, "rb") as wav_file:
|
||||
|
|
@ -497,7 +498,10 @@ class ARIABridge:
|
|||
vc = json.load(f)
|
||||
self.voice_engine.default_voice = vc.get("defaultVoice", "ramona")
|
||||
self.voice_engine.highlight_voice = vc.get("highlightVoice", "thorsten")
|
||||
self.voice_engine.speech_speed = vc.get("speechSpeed", 1.0)
|
||||
self.voice_engine.speech_speed = {
|
||||
"ramona": vc.get("speedRamona", 1.0),
|
||||
"thorsten": vc.get("speedThorsten", 1.0),
|
||||
}
|
||||
self.tts_enabled = vc.get("ttsEnabled", True)
|
||||
logger.info("Voice-Config geladen: %s", vc)
|
||||
except Exception as e:
|
||||
|
|
@ -1028,9 +1032,13 @@ class ARIABridge:
|
|||
self.tts_enabled = bool(payload["ttsEnabled"])
|
||||
logger.info("[rvs] TTS %s", "aktiviert" if self.tts_enabled else "deaktiviert")
|
||||
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)
|
||||
if "speedRamona" in payload:
|
||||
self.voice_engine.speech_speed["ramona"] = max(0.3, min(2.0, float(payload["speedRamona"])))
|
||||
logger.info("[rvs] Speed Ramona: %.1f", self.voice_engine.speech_speed["ramona"])
|
||||
changed = True
|
||||
if "speedThorsten" in payload:
|
||||
self.voice_engine.speech_speed["thorsten"] = max(0.3, min(2.0, float(payload["speedThorsten"])))
|
||||
logger.info("[rvs] Speed Thorsten: %.1f", self.voice_engine.speech_speed["thorsten"])
|
||||
changed = True
|
||||
# Persistent speichern in Shared Volume
|
||||
if changed:
|
||||
|
|
@ -1040,7 +1048,8 @@ class ARIABridge:
|
|||
"defaultVoice": self.voice_engine.default_voice,
|
||||
"highlightVoice": self.voice_engine.highlight_voice,
|
||||
"ttsEnabled": getattr(self, "tts_enabled", True),
|
||||
"speechSpeed": self.voice_engine.speech_speed,
|
||||
"speedRamona": self.voice_engine.speech_speed.get("ramona", 1.0),
|
||||
"speedThorsten": self.voice_engine.speech_speed.get("thorsten", 1.0),
|
||||
}
|
||||
with open("/shared/config/voice_config.json", "w") as f:
|
||||
json.dump(config_data, f, indent=2)
|
||||
|
|
|
|||
|
|
@ -419,12 +419,23 @@
|
|||
<label class="toggle"><input type="checkbox" id="diag-tts-enabled" checked onchange="sendVoiceConfig()"><span class="slider"></span></label>
|
||||
</div>
|
||||
<div style="margin-bottom:4px;">
|
||||
<label style="color:#8888AA;font-size:12px;">Sprechgeschwindigkeit: <span id="speed-label">1.0x</span></label>
|
||||
<label style="color:#8888AA;font-size:12px;">Ramona Speed: <span id="speed-ramona-label">1.0x</span></label>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
|
||||
<span style="color:#555570;font-size:11px;">0.5x</span>
|
||||
<input type="range" id="diag-speed-ramona" min="0.5" max="2.0" step="0.1" value="1.0"
|
||||
oninput="document.getElementById('speed-ramona-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 style="margin-bottom:4px;">
|
||||
<label style="color:#8888AA;font-size:12px;">Thorsten Speed: <span id="speed-thorsten-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'"
|
||||
<input type="range" id="diag-speed-thorsten" min="0.5" max="2.0" step="0.1" value="1.0"
|
||||
oninput="document.getElementById('speed-thorsten-label').textContent=this.value+'x'"
|
||||
onchange="sendVoiceConfig()"
|
||||
style="flex:1;accent-color:#0096FF;">
|
||||
<span style="color:#555570;font-size:11px;">2.0x</span>
|
||||
|
|
@ -657,9 +668,12 @@
|
|||
document.getElementById('diag-default-voice').value = msg.defaultVoice || 'ramona';
|
||||
document.getElementById('diag-highlight-voice').value = msg.highlightVoice || 'thorsten';
|
||||
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';
|
||||
const sr = msg.speedRamona || 1.0;
|
||||
const st = msg.speedThorsten || 1.0;
|
||||
document.getElementById('diag-speed-ramona').value = sr;
|
||||
document.getElementById('speed-ramona-label').textContent = sr + 'x';
|
||||
document.getElementById('diag-speed-thorsten').value = st;
|
||||
document.getElementById('speed-thorsten-label').textContent = st + 'x';
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1157,8 +1171,9 @@
|
|||
const defaultVoice = document.getElementById('diag-default-voice').value;
|
||||
const highlightVoice = document.getElementById('diag-highlight-voice').value;
|
||||
const ttsEnabled = document.getElementById('diag-tts-enabled').checked;
|
||||
const speechSpeed = parseFloat(document.getElementById('diag-speech-speed').value);
|
||||
send({ action: 'send_voice_config', defaultVoice, highlightVoice, ttsEnabled, speechSpeed });
|
||||
const speedRamona = parseFloat(document.getElementById('diag-speed-ramona').value);
|
||||
const speedThorsten = parseFloat(document.getElementById('diag-speed-thorsten').value);
|
||||
send({ action: 'send_voice_config', defaultVoice, highlightVoice, ttsEnabled, speedRamona, speedThorsten });
|
||||
}
|
||||
|
||||
// ── Highlight-Trigger ────────────────────────
|
||||
|
|
|
|||
|
|
@ -1135,7 +1135,8 @@ wss.on("connection", (ws) => {
|
|||
defaultVoice: msg.defaultVoice || "ramona",
|
||||
highlightVoice: msg.highlightVoice || "thorsten",
|
||||
ttsEnabled: msg.ttsEnabled !== false,
|
||||
speechSpeed: msg.speechSpeed || 1.0,
|
||||
speedRamona: msg.speedRamona || 1.0,
|
||||
speedThorsten: msg.speedThorsten || 1.0,
|
||||
};
|
||||
try {
|
||||
fs.mkdirSync("/shared/config", { recursive: true });
|
||||
|
|
|
|||
Loading…
Reference in New Issue