# Init => Orange # Ecoute => Violet # Mute => Rouge # Reflechi(Ally) => Cligno Rose # Repond => Bleu # Erreur cligno rouge # LED from driver_led import APA102 # BOUTON import RPi.GPIO as GPIO import time import queue # AUDIO import sounddevice as sd import numpy as np # STT import json # Ally + TTS import requests, urllib3 # Autres import signal, sys # INIT LED num_leds = 12 led = APA102(num_led=num_leds) def set_couleur(c): couleurs = { 'R': (255, 0, 0), 'V': (0, 255, 0), 'B': (0, 0, 255), 'J': (255, 255, 0), 'VI': (128, 0, 128), 'RO': (255, 105, 180), 'O': (255, 165, 0) } rgb = couleurs.get(c.upper(), (0, 0, 0)) for i in range(num_leds): led.set_pixel(i, *rgb) led.show() def eteindre_led(): set_couleur("") def cleanup_led(): led.cleanup() def animation_balayer(): rgb = (255, 105, 180) for _ in range(2): for i in range(num_leds): led.set_pixel(i, *rgb) led.show() time.sleep(0.05) led.set_pixel(i, 0, 0, 0) led.show() def cligno_rouge(): for _ in range(3): set_couleur('R'); time.sleep(0.3) eteindre_led(); time.sleep(0.3) def cligno_rose(): for _ in range(2): set_couleur('RO'); time.sleep(0.5) eteindre_led(); time.sleep(0.5) # BOUTON MUTE BUTTON = 17 GPIO.setmode(GPIO.BCM) GPIO.setup(BUTTON, GPIO.IN) etat = {'mute': False} def toggle_mute(ch): etat['mute'] = not etat['mute'] set_couleur('R' if etat['mute'] else 'O') #Rouge => Muted GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=toggle_mute, bouncetime=300) # Ally API urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) url_ally = "https://192.168.1.12:8000/mic" def ally(text): try: r = requests.post(url_ally, data={"texto": text}, verify=False) if r.status_code == 200: return r.json().get("ora", "") else: print("HTTP Ally error", r.status_code) return "" except Exception as e: print("Ally exception", e) return "" # Piper TTS def Init(): import vosk model = vosk.Model("vosk-model/vosk-model-small-fr-0.22") rec = vosk.KaldiRecognizer(model, 16000) audio_q = queue.Queue() stream = sd.RawInputStream(samplerate=16000, blocksize=8000,device=None, dtype='int16', channels=1,callback=audio_callback) from piper.voice import PiperVoice voice = PiperVoice.load("/data/piper_model/fr_FR-siwis-low.onnx") sd_stream = sd.OutputStream(samplerate=voice.config.sample_rate, channels=1, dtype='int16') return rec, audio_q, stream, sd_stream, voice def piper_talk(text): for chunk in voice.synthesize_stream_raw(text): sd_stream.write(np.frombuffer(chunk, dtype=np.int16)) # STT : Vosk via sounddevice def audio_callback(indata, frames, time_info, status): if status: print(status) audio_q.put(bytes(indata)) # Cleanup def handle_exit(sig, frame): eteindre_led() cleanup_led() GPIO.cleanup() stream.stop() sd_stream.stop() sys.exit(0) signal.signal(signal.SIGINT, handle_exit) signal.signal(signal.SIGTERM, handle_exit) # MAIN LOOP try: print("Init…") set_couleur('O') rec, audio_q, stream, sd_stream, voice = Init() time.sleep(0.5) sd_stream.start() stream.start() while True: if etat['mute']: time.sleep(0.05) continue set_couleur('VI') #Violet = écoute data = audio_q.get() if rec.AcceptWaveform(data): txt = json.loads(rec.Result()).get("text", "") if txt: print("Q>", txt) cligno_rose() # Rose = réfléchit resp = ally(txt) print("R>", resp) if resp: animation_balayer() set_couleur('B') # Bleu = Répond piper_talk(resp) else: cligno_rouge() time.sleep(0.3) except KeyboardInterrupt: handle_exit(None, None)