Add kawa-voice-install.sh - Voice interface for KAWA nodes
- Vosk for offline speech recognition (French) - pyttsx3 for text-to-speech - NATS integration for voice commands - Ollama integration for AI responses - Works on Debian/Ubuntu/NixOS
This commit is contained in:
224
kawa-voice-install.sh
Executable file
224
kawa-voice-install.sh
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/bin/bash
|
||||
# KAWA Voice - Installation de l'accès vocal
|
||||
# Pour machines Linux (Debian/Ubuntu/NixOS)
|
||||
|
||||
set -e
|
||||
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " KAWA Voice - Accès Vocal"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# Détection du système
|
||||
if [ -f /etc/NIXOS ]; then
|
||||
echo "Système: NixOS détecté"
|
||||
SYSTEM="nixos"
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
echo "Système: Debian/Ubuntu détecté"
|
||||
SYSTEM="debian"
|
||||
else
|
||||
echo "Système: Linux générique"
|
||||
SYSTEM="linux"
|
||||
fi
|
||||
|
||||
# Installation des dépendances
|
||||
echo ""
|
||||
echo "=== Installation des dépendances ==="
|
||||
|
||||
if [ "$SYSTEM" = "debian" ]; then
|
||||
sudo apt update
|
||||
sudo apt install -y python3 python3-pip python3-venv \
|
||||
portaudio19-dev ffmpeg espeak-ng \
|
||||
libportaudio2 libportaudiocpp0 \
|
||||
pulseaudio alsa-utils
|
||||
elif [ "$SYSTEM" = "nixos" ]; then
|
||||
echo "Pour NixOS, ajoutez à configuration.nix:"
|
||||
echo ' environment.systemPackages = with pkgs; ['
|
||||
echo ' python3 python3Packages.pip'
|
||||
echo ' portaudio ffmpeg espeak-ng'
|
||||
echo ' pulseaudio alsa-utils'
|
||||
echo ' ];'
|
||||
echo ' services.pulseaudio.enable = true;'
|
||||
fi
|
||||
|
||||
# Création de l'environnement Python
|
||||
echo ""
|
||||
echo "=== Environnement Python ==="
|
||||
python3 -m venv ~/.venv/kawa-voice
|
||||
source ~/.venv/kawa-voice/bin/activate
|
||||
|
||||
pip install --upgrade pip
|
||||
pip install vosk pyttsx3 pyaudio requests websocket-client
|
||||
|
||||
# Téléchargement du modèle Vosk (français)
|
||||
echo ""
|
||||
echo "=== Téléchargement du modèle Vosk français ==="
|
||||
mkdir -p ~/.local/share/vosk
|
||||
cd ~/.local/share/vosk
|
||||
|
||||
if [ ! -d "vosk-model-fr" ]; then
|
||||
wget -q https://alphacephei.com/vosk/models/vosk-model-fr-0.6-linto-2.2.0.zip
|
||||
unzip -q vosk-model-fr-0.6-linto-2.2.0.zip
|
||||
mv vosk-model-fr-0.6-linto-2.2.0 vosk-model-fr
|
||||
rm vosk-model-fr-0.6-linto-2.2.0.zip
|
||||
echo "✓ Modèle français téléchargé"
|
||||
else
|
||||
echo "✓ Modèle déjà présent"
|
||||
fi
|
||||
|
||||
# Création du script kawa-voice
|
||||
echo ""
|
||||
echo "=== Création de kawa-voice ==="
|
||||
mkdir -p ~/.local/bin
|
||||
|
||||
cat > ~/.local/bin/kawa-voice << 'KAWA_VOICE'
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
KAWA Voice - Interface vocale pour le réseau KAWA
|
||||
"""
|
||||
|
||||
import json
|
||||
import queue
|
||||
import threading
|
||||
import requests
|
||||
import websocket
|
||||
from vosk import Model, KaldiRecognizer
|
||||
import pyaudio
|
||||
import pyttsx3
|
||||
|
||||
# Configuration
|
||||
NATS_SERVER = "ws://kawa:kawa123@100.64.0.1:4222"
|
||||
OLLAMA_SERVER = "http://100.64.0.7:11434"
|
||||
MODEL_PATH = os.path.expanduser("~/.local/share/vosk/vosk-model-fr")
|
||||
|
||||
class KawaVoice:
|
||||
def __init__(self):
|
||||
self.model = Model(MODEL_PATH)
|
||||
self.recognizer = KaldiRecognizer(self.model, 16000)
|
||||
self.engine = pyttsx3.init()
|
||||
self.engine.setProperty('rate', 150)
|
||||
self.engine.setProperty('voice', 'french')
|
||||
|
||||
# Audio
|
||||
self.p = pyaudio.PyAudio()
|
||||
self.stream = self.p.open(
|
||||
format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=16000,
|
||||
input=True,
|
||||
frames_per_buffer=8000
|
||||
)
|
||||
|
||||
# NATS
|
||||
self.ws = None
|
||||
self.connect_nats()
|
||||
|
||||
def connect_nats(self):
|
||||
"""Connexion au bus NATS KAWA"""
|
||||
try:
|
||||
self.ws = websocket.WebSocket()
|
||||
self.ws.connect("ws://100.64.0.1:4222")
|
||||
# Subscribe aux commandes vocales
|
||||
self.ws.send(json.dumps({
|
||||
"type": "subscribe",
|
||||
"topic": "kawa.voice.command"
|
||||
}))
|
||||
except Exception as e:
|
||||
print(f"Erreur NATS: {e}")
|
||||
|
||||
def listen(self):
|
||||
"""Écoute en continue"""
|
||||
print("🎤 En écoute... (dit 'KAWA' pour activer)")
|
||||
|
||||
while True:
|
||||
data = self.stream.read(4096)
|
||||
if self.recognizer.AcceptWaveform(data):
|
||||
result = json.loads(self.recognizer.Result())
|
||||
text = result.get('text', '').lower()
|
||||
|
||||
if 'kawa' in text:
|
||||
self.engine.say("Oui?")
|
||||
self.engine.runAndWait()
|
||||
self.process_command(text.replace('kawa', '').strip())
|
||||
|
||||
def process_command(self, command):
|
||||
"""Traite une commande vocale"""
|
||||
print(f"Commande: {command}")
|
||||
|
||||
# Commander NATS
|
||||
if 'status' in command:
|
||||
self.ws.send(json.dumps({
|
||||
"type": "publish",
|
||||
"topic": "kawa.voice.command",
|
||||
"message": {"command": "status"}
|
||||
}))
|
||||
response = "Statut envoyé"
|
||||
|
||||
# Interroger Ollama
|
||||
elif any(word in command for word in ['que', 'quoi', 'comment', 'pourquoi']):
|
||||
response = self.query_ollama(command)
|
||||
|
||||
else:
|
||||
response = f"Commande reçue: {command}"
|
||||
|
||||
self.engine.say(response)
|
||||
self.engine.runAndWait()
|
||||
|
||||
def query_ollama(self, question):
|
||||
"""Interroge Ollama pour une réponse"""
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{OLLAMA_SERVER}/api/generate",
|
||||
json={
|
||||
"model": "glm-4.7-flash:q4_K_M",
|
||||
"prompt": question,
|
||||
"stream": False
|
||||
}
|
||||
)
|
||||
return response.json().get('response', 'Je ne sais pas')
|
||||
except Exception as e:
|
||||
return f"Erreur: {str(e)}"
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
voice = KawaVoice()
|
||||
voice.listen()
|
||||
KAWA_VOICE
|
||||
|
||||
chmod +x ~/.local/bin/kawa-voice
|
||||
|
||||
# Création du service systemd
|
||||
echo ""
|
||||
echo "=== Service systemd ==="
|
||||
mkdir -p ~/.config/systemd/user
|
||||
|
||||
cat > ~/.config/systemd/user/kawa-voice.service << 'SERVICE'
|
||||
[Unit]
|
||||
Description=KAWA Voice - Interface vocale
|
||||
After=network.target pulseaudio.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/home/%u/.local/bin/kawa-voice
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
SERVICE
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo "✅ KAWA Voice installé!"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Pour démarrer:"
|
||||
echo " systemctl --user start kawa-voice"
|
||||
echo ""
|
||||
echo "Pour activer au démarrage:"
|
||||
echo " systemctl --user enable kawa-voice"
|
||||
echo ""
|
||||
echo "Commandes vocales:"
|
||||
echo " 'KAWA status' - Statut du réseau"
|
||||
echo " 'KAWA <question>' - Interroger Ollama"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
Reference in New Issue
Block a user