feat: wakeword — OpenWakeWord subprocess with hey_jarvis model

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
boksbc 2026-05-11 22:04:01 +02:00
parent 71f7341974
commit 0a2154ddbd
2 changed files with 87 additions and 0 deletions

44
electron/wakeword.js Normal file
View File

@ -0,0 +1,44 @@
const { spawn } = require('child_process');
const path = require('path');
let wakewordProcess = null;
let running = false;
function startWakeword({ onWake }) {
if (running) return;
running = true;
const scriptPath = path.join(__dirname, '../python/wakeword.py');
wakewordProcess = spawn('python3', [scriptPath], {
stdio: ['pipe', 'pipe', 'pipe'],
});
wakewordProcess.stdout.on('data', (data) => {
if (data.toString().trim() === 'WAKE') {
onWake();
}
});
wakewordProcess.stderr.on('data', (data) => {
console.error('[Wakeword]', data.toString().trim());
});
wakewordProcess.on('close', (code) => {
running = false;
wakewordProcess = null;
if (code !== 0) {
setTimeout(() => startWakeword({ onWake }), 2000);
}
});
}
function stopWakeword() {
if (wakewordProcess) {
wakewordProcess.kill();
wakewordProcess = null;
running = false;
}
}
module.exports = { startWakeword, stopWakeword };

43
python/wakeword.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
import sys
import numpy as np
import pyaudio
from openwakeword.model import Model
CHUNK = 1280 # 80ms bei 16kHz — von openwakeword erwartet
RATE = 16000
THRESHOLD = 0.5
def main():
model = Model(wakeword_models=["hey_jarvis"])
pa = pyaudio.PyAudio()
stream = pa.open(
rate=RATE,
channels=1,
format=pyaudio.paInt16,
input=True,
frames_per_buffer=CHUNK,
)
print("Wakeword aktiv", flush=True)
try:
while True:
data = stream.read(CHUNK, exception_on_overflow=False)
audio = np.frombuffer(data, dtype=np.int16)
prediction = model.predict(audio)
for mdl, score in prediction.items():
if score > THRESHOLD:
print("WAKE", flush=True)
model.reset()
break
except KeyboardInterrupt:
pass
finally:
stream.stop_stream()
stream.close()
pa.terminate()
if __name__ == "__main__":
main()