mirror of
https://github.com/deunix-educ/voice-assistant.git
synced 2026-10-13 00:11:57 +02:00
149 lines
8.3 KiB
YAML
149 lines
8.3 KiB
YAML
# Configuration du serveur vocal.
|
|
# Les valeurs sensibles (mots de passe, jetons) vont dans .env, jamais ici.
|
|
# Les sections marquées « étape N » ne sont lues qu'à partir de cette étape.
|
|
|
|
audio:
|
|
sample_rate: 16000 # Hz, identique dans tout le système
|
|
bits: 16
|
|
channels: 1
|
|
codec: pcm_s16le
|
|
chunk_ms: 50 # 800 échantillons = 1600 octets
|
|
|
|
# étape 4 : broker MQTT. Le serveur écoute TOUTES les cartes : voice/+/...
|
|
mqtt:
|
|
host: 10.42.0.1 # broker du Raspberry Pi 5 (comptes exigés : server/.env) ; relu par le Makefile
|
|
port: 1883
|
|
keepalive: 30
|
|
client_id: voice-server # unique sur le broker
|
|
topic_prefix: voice
|
|
|
|
# étape 4 : sessions de parole reçues des ESP32
|
|
sessions:
|
|
max_seconds: 30 # au-delà, on arrête d'accumuler (garde-fou mémoire)
|
|
idle_timeout_s: 5 # plus rien reçu depuis 5 s et pas de END : on clôt
|
|
end_grace_s: 0.5 # après le END, attente des derniers chunks en vol
|
|
|
|
# chemins relatifs à ce fichier
|
|
storage:
|
|
recordings_dir: recordings
|
|
models_dir: models
|
|
|
|
logging:
|
|
level: INFO
|
|
format: "%(asctime)s %(levelname)-7s %(name)s | %(message)s"
|
|
# étape 15 : copie du journal dans un fichier tournant (3 x 1 Mo), pour
|
|
# retrouver ce qui s'est passé sur un Raspberry Pi sans écran. Vide : écran seul.
|
|
file: logs/voice-server.log
|
|
|
|
# étape 6 : transcription (modèle dans models/whisper/<model>, « make models »)
|
|
stt:
|
|
model: small # « base » sur Raspberry Pi 4, « small » sur Pi 5 / PC
|
|
language: fr
|
|
compute_type: int8
|
|
beam_size: 5 # 1 = plus rapide, 5 = plus précis
|
|
no_speech_threshold: 0.6 # segment écarté au-delà : Whisper invente du texte sur le silence
|
|
|
|
# étape 6 : synthèse vocale (modèle dans models/piper/<voice>.onnx, « make models »)
|
|
# Piper produit du 22 050 Hz : le serveur rééchantillonne en audio.sample_rate.
|
|
tts:
|
|
voice: fr_FR-siwis-medium
|
|
length_scale: 1.0 # > 1 : débit plus lent
|
|
|
|
# étape 7 : détection d'activité vocale (Silero, fenêtres de 512 échantillons = 32 ms,
|
|
# imposées à 16 kHz). Une session sans parole n'est pas transcrite.
|
|
vad:
|
|
threshold: 0.5 # probabilité de parole ; on en sort sous 0,35 (hystérésis)
|
|
min_silence_ms: 500 # pause plus courte : la phrase continue
|
|
min_speech_ms: 250 # parole plus courte : bruit (clic du bouton), ignorée
|
|
speech_pad_ms: 150 # marge autour de chaque segment : attaques et fins de mots
|
|
|
|
# étape 8 : diarisation (qui parle quand), sur la seule parole trouvée par la VAD.
|
|
# Modèle soumis à conditions : les accepter sur huggingface.co, HF_TOKEN dans .env,
|
|
# puis « make models ». Ensuite, tout fonctionne hors ligne ; télémétrie pyannote coupée.
|
|
diarization:
|
|
enabled: true # false sur Raspberry Pi 4 (trop lourd) ou sans l'extra « diarization »
|
|
model: pyannote/speaker-diarization-community-1
|
|
max_speakers: 3 # borne haute : un assistant de salon, pas une réunion
|
|
|
|
# étape 9 : identification du locuteur (probabiliste, jamais une sécurité).
|
|
# Profils créés par « make enroll NAME=... », un fichier par personne (donnée biométrique).
|
|
# Nécessite la diarisation : les empreintes viennent de son modèle (WeSpeaker ResNet34).
|
|
speaker:
|
|
profiles_dir: profiles
|
|
similarity_threshold: 0.45 # mesuré : vous 0,52 à 0,83 contre votre profil, Piper -0,08 à 0,11
|
|
|
|
# étape 11 : domotique. Commandes publiées sur <topic_prefix>/<pièce>/<appareil>/set ;
|
|
# la carte exécute en plus celles de sa propre pièce (LED de démonstration).
|
|
home:
|
|
topic_prefix: home
|
|
rooms: # nom tel qu'on le dit → complément dans les réponses
|
|
salon: du salon
|
|
cuisine: de la cuisine
|
|
chambre: de la chambre
|
|
salle de bain: de la salle de bain
|
|
bureau: du bureau
|
|
garage: du garage
|
|
entrée: de l'entrée
|
|
boards: # pièce de chaque carte : « allume la lumière » sans pièce = ici
|
|
esp32-01: salon
|
|
|
|
# étape 13 : mot de réveil, mains libres. Le serveur demande à chaque carte de lui envoyer
|
|
# son micro en continu (voice/<carte>/audio/stream) et guette le mot. Rien n'est écrit
|
|
# sur disque avant le mot : seules les dernières preroll_ms restent en mémoire.
|
|
# Prononciation à l'anglaise : « Alexa », « Hé Maïcrofte », « Hey Djâr-viss ».
|
|
wake:
|
|
enabled: true
|
|
words: [alexa, hey_jarvis, hey_mycroft] # models/openwakeword/<mot>_v0.1.onnx
|
|
threshold: 0.5 # mesuré : 90 enregistrements sans le mot, score max 0,07
|
|
# Seuil propre à un mot, si le journal montre des « mot presque reconnu » répétés.
|
|
# Plus bas = plus sensible, mais plus de déclenchements intempestifs. Ex. : {hey_jarvis: 0.35}
|
|
thresholds: {}
|
|
preroll_ms: 500 # la commande suit souvent le mot sans pause
|
|
end_silence_ms: 800 # silence qui clôt la commande
|
|
no_speech_timeout_s: 4 # mot entendu mais rien dit ensuite : on abandonne
|
|
max_command_s: 10
|
|
cooldown_s: 20 # écoute suspendue pendant la réponse (jusqu'au bilan « played »)
|
|
|
|
# étape 14 : droits par profil. La voix n'est JAMAIS une preuve d'identité : une
|
|
# imitation ou un enregistrement peut tromper. Niveaux : complet > standard > limite.
|
|
access:
|
|
unknown: limite # voix non reconnue : conversation seulement
|
|
default: standard # profil enrôlé absent de users
|
|
users: # noms des profils (make profiles)
|
|
Denis: complet
|
|
full_min_score: 0.6 # « complet » seulement si la voix est reconnue nettement
|
|
rules: # niveau minimal par appareil et action ; absent = complet
|
|
light: {"on": standard, "off": standard} # guillemets : on/off nus = booléens en YAML
|
|
shutter: {open: standard, close: standard}
|
|
door: {open: complet, close: standard}
|
|
machine: {wake: standard, lock: standard, shutdown: complet, reboot: complet} # étape 15b
|
|
confirm: [door.open, machine.shutdown, machine.reboot] # « Confirmez-vous ? » puis « oui »
|
|
confirm_timeout_s: 15
|
|
# Un « oui » seul dure ~0,7 s : trop court pour atteindre speaker.similarity_threshold
|
|
# (mesuré : Denis 0,29 à 0,47 ; les autres profils face à Denis : 0,12 au plus).
|
|
# La confirmation est donc acceptée si le demandeur reste le profil le PLUS PROCHE,
|
|
# avec au moins ce score. Une voix reconnue comme quelqu'un d'autre est refusée.
|
|
confirm_min_score: 0.25
|
|
|
|
# étape 15b : machines Linux du réseau. Chacune fait tourner un agent (agent/voice_agent.py)
|
|
# qui n'exécute QUE les actions de SA liste (/etc/voice-assistant/agent.yaml) ; ici, on dit
|
|
# seulement comment on les appelle. « allume » = Wake-on-LAN, envoyé par le serveur
|
|
# (la machine éteinte n'a pas d'agent). Nouvelle action : l'ajouter à l'agent, ici
|
|
# (mots et phrases), puis dans access.rules.machine (sinon : niveau complet exigé).
|
|
machines:
|
|
topic_prefix: agent # agent/<machine>/state (retenu), command, result
|
|
broadcast: 255.255.255.255 # Wake-on-LAN : diffusion sur le réseau local
|
|
actions: # mots sans accents ; « does » et « verb » : phrases dites
|
|
# Un mot par entrée, tel que Whisper l'écrit : « lock » devient souvent « Locke »,
|
|
# « shutdown » devient « Shut down » (d'où « shut »).
|
|
wake: {words: [allume, allumer, allumez, demarre, demarrer, reveille, reveiller], does: "J'allume", verb: allumer}
|
|
shutdown: {words: [eteins, eteint, eteindre, eteignez, arrete, arreter, arretez, shutdown, shut], does: "J'éteins", verb: éteindre}
|
|
reboot: {words: [redemarre, redemarrer, redemarrez, relance, relancer, reboot, reboote, rebooter], does: "Je redémarre", verb: redémarrer}
|
|
lock: {words: [verrouille, verrouiller, verrouillez, lock, locke, locker, loque], does: "Je verrouille", verb: verrouiller}
|
|
list: # identifiant de l'agent → comment on l'appelle
|
|
pc-bureau:
|
|
# Plusieurs mots : « bureau » seul est une pièce. « p c » : Whisper écrit parfois « P.C. ».
|
|
names: [pc du bureau, p c du bureau, ordinateur du bureau]
|
|
name: le PC du bureau
|
|
mac: "" # ex. "aa:bb:cc:dd:ee:ff" (ip link) pour « allume le PC du bureau »
|