V1
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user