mirror of
https://github.com/deunix-educ/voice-assistant.git
synced 2026-10-13 00:11:57 +02:00
step-16
This commit is contained in:
@@ -17,6 +17,8 @@ if TYPE_CHECKING: # import réel dans __init__ : le mode écho se passe de l'ex
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CACHE_PHRASES = 64 # réponses gardées en mémoire : ~100 Ko chacune, 6 Mo au plus
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Speech:
|
||||
@@ -32,6 +34,10 @@ class TextToSpeech:
|
||||
|
||||
Piper produit du 22 050 Hz en flottants ; AudioResampler le ramène au
|
||||
format du système (16 kHz, s16le) et fixe sa crête à -3 dBFS.
|
||||
|
||||
Les réponses déjà synthétisées sont gardées en mémoire (étape 16) : « J'allume
|
||||
la lumière du salon. » ou « Confirmez-vous… » reviennent souvent, et leur
|
||||
synthèse coûte 30 à 140 ms à chaque fois.
|
||||
"""
|
||||
|
||||
def __init__(self, tts: TtsSettings, resampler: AudioResampler, sample_rate: int) -> None:
|
||||
@@ -53,12 +59,16 @@ class TextToSpeech:
|
||||
self._config: SynthesisConfig = SynthesisConfig(length_scale=tts.length_scale)
|
||||
self._resampler = resampler
|
||||
self._sample_rate = sample_rate
|
||||
self._cache: dict[str, Speech] = {} # texte → parole ; un dict garde l'ordre d'insertion
|
||||
logger.info("voix piper %s chargee en %.1f s (%d Hz)", tts.voice,
|
||||
time.monotonic() - began, self._voice.config.sample_rate)
|
||||
|
||||
def synthesize(self, text: str) -> Speech:
|
||||
"""Synthétise le texte ; Piper le découpe en phrases, qu'on remet bout à bout."""
|
||||
began = time.monotonic()
|
||||
cached = self._cache.get(text)
|
||||
if cached is not None:
|
||||
return Speech(pcm=cached.pcm, audio_s=cached.audio_s, elapsed_s=time.monotonic() - began)
|
||||
parts: list[np.ndarray] = []
|
||||
rate = self._voice.config.sample_rate
|
||||
for chunk in self._voice.synthesize(text, syn_config=self._config):
|
||||
@@ -66,8 +76,12 @@ class TextToSpeech:
|
||||
rate = chunk.sample_rate
|
||||
signal = np.concatenate(parts) if parts else np.zeros(0, dtype=np.float32)
|
||||
pcm = self._resampler.convert(signal, rate)
|
||||
return Speech(
|
||||
speech = Speech(
|
||||
pcm=pcm,
|
||||
audio_s=len(pcm) / 2 / self._sample_rate,
|
||||
elapsed_s=time.monotonic() - began,
|
||||
)
|
||||
if len(self._cache) >= CACHE_PHRASES:
|
||||
del self._cache[next(iter(self._cache))] # la plus ancienne sort
|
||||
self._cache[text] = speech
|
||||
return speech
|
||||
|
||||
Reference in New Issue
Block a user