This commit is contained in:
pporcheret
2026-10-26 00:06:24 +01:00
parent c9c3d5f223
commit cd37ac3c0a
207 changed files with 19205 additions and 54 deletions
@@ -0,0 +1,109 @@
import asyncio
import os
import subprocess
import tempfile
import time
import wave
from wyoming.audio import AudioChunk, AudioStart, AudioStop
from wyoming.client import AsyncTcpClient
from wyoming.tts import Synthesize, SynthesizeVoice
PIPER_HOST = os.getenv("PIPER_HOST", "127.0.0.1")
PIPER_PORT = int(os.getenv("PIPER_PORT", "10200"))
AUDIO_DEVICE = os.getenv("AUDIO_OUTPUT_DEVICE", "plughw:1,0")
async def synthesize(text, wav_path):
client = AsyncTcpClient(PIPER_HOST, PIPER_PORT)
await client.connect()
try:
await client.write_event(
Synthesize(
text=text,
voice=SynthesizeVoice(
name=os.getenv("PIPER_VOICE", "fr_FR-tom-medium")
)).event()
)
wav_file = None
try:
while True:
event = await asyncio.wait_for(
client.read_event(),
timeout=30
)
if event is None:
raise RuntimeError("Connexion Piper interrompue")
if AudioStart.is_type(event.type):
start = AudioStart.from_event(event)
wav_file = wave.open(wav_path, "wb")
wav_file.setnchannels(start.channels)
wav_file.setsampwidth(start.width)
wav_file.setframerate(start.rate)
elif AudioChunk.is_type(event.type):
chunk = AudioChunk.from_event(event)
if wav_file is None:
wav_file = wave.open(wav_path, "wb")
wav_file.setnchannels(chunk.channels)
wav_file.setsampwidth(chunk.width)
wav_file.setframerate(chunk.rate)
wav_file.writeframes(chunk.audio)
elif AudioStop.is_type(event.type):
break
finally:
if wav_file is not None:
wav_file.close()
finally:
await client.disconnect()
def speak(text):
if not text or not text.strip():
return
fd, wav_path = tempfile.mkstemp(
prefix="alfred_piper_",
suffix=".wav"
)
os.close(fd)
start = time.monotonic()
try:
print("[ALFRED PIPER] Synthèse...", flush=True)
asyncio.run(synthesize(text, wav_path))
print("[ALFRED PIPER] Lecture...", flush=True)
subprocess.run(
["aplay", "-q", "-D", AUDIO_DEVICE, wav_path],
check=True,
timeout=120
)
print(
f"[ALFRED PIPER] Terminé en {time.monotonic() - start:.2f}s",
flush=True
)
except Exception as e:
print(f"[ALFRED PIPER] Erreur : {e}", flush=True)
raise
finally:
if os.path.exists(wav_path):
os.remove(wav_path)