Assistant vocal IA
Source: showcase/ai_voice_assistant See in Playground
Cet exemple combine plusieurs capacités ml de la bibliothèque en une seule démonstration, sans s’arrêter pour expliquer chaque concept sous-jacent ; ceux-ci sont couverts individuellement dans le parcours tutoriel. Deux points d’entrée : chat, un serveur HTTP qui transmet la réponse d’un LLM distant token par token, et voice, une boucle complète du microphone jusqu’à la réponse parlée.
Nécessite de véritables clés API (un fournisseur LLM pour les deux points d’entrée, plus ElevenLabs pour voice) et, pour voice, un microphone fonctionnel. voice télécharge également un petit modèle Whisper depuis le HuggingFace Hub au premier lancement et le met en cache localement.
Exécution
chat, un serveur HTTP transmettant la réponse d’un LLM distant token par token :
cd showcase/ai_voice_assistant
melodium run Compo.toml chat --api_key sk-...
curl -X POST http://127.0.0.1:8080/chat -d "What is Mélodium?"voice, du microphone vers Whisper local (reconnaissance vocale) vers un LLM distant (réponse en flux) vers une synthèse vocale distante vers answer.mp3 :
cd showcase/ai_voice_assistant
melodium run Compo.toml voice --llm_api_key sk-... --tts_api_key el-...La reconnaissance vocale s’exécute localement (un petit modèle Whisper, récupéré une fois depuis le HuggingFace Hub et mis en cache), donc l’audio brut ne quitte jamais la machine locale : seul le texte transcrit est envoyé au LLM, et seul le texte de la réponse du LLM est envoyé au fournisseur de synthèse vocale.
Optionnel : ajoutez --api-report et un jeton d’API (MELODIUM_API_TOKEN) pour voir la trace complète de cette exécution sur Cadence.CI .
Fonctionnement
chat : transmettre en flux la réponse d’un LLM via HTTP
chat démarre un HttpServer et, exactement comme établi dans l’étape du tutoriel sur le serveur HTTP, conditionne la réponse à connection.started plutôt qu’au démarrage du flux du corps de requête :
treatment respond[llm: RemoteLlm]()
input data: Stream<byte>
output data: Stream<byte>
{
decoded: decode()
reply: stream[llm=llm]()
encoded: encode()
Self.data -> decoded.data,text -> reply.prompt,token -> encoded.text,data -> Self.data
llmErrors: logErrors(label="llm")
reply.error -> llmErrors.messages
}voice : du microphone à la réponse parlée
voice récupère et charge d’abord un modèle Whisper depuis un dépôt HfHub, puis enregistre depuis le microphone avec recordMono et transcrit localement :
model WhisperHub() : HfHub { repo_id = "openai/whisper-tiny" }
model Asr() : Whisper {}fetchAsr: fetch[hub=whisperHub]()
loadAsr: load[whisper=asr]()
startup.trigger -> fetchAsr.trigger
fetchAsr.safetensors -> loadAsr.safetensors
fetchAsr.tokenizer -> loadAsr.tokenizer
record: recordMono(device=_, sample_rate=_)
asrDecode: whisperDecode[whisper=asr]()
loadAsr.loaded -> record.trigger
loadAsr.loaded -> asrDecode.ready
record.signal -> asrDecode.audioLe texte transcrit alimente un appel stream sur un RemoteLlm, et chaque token est à la fois journalisé et envoyé vers un appel synthesize sur un RemoteTts configuré pour ElevenLabs, dont l’audio est écrit localement :
model Voice(const tts_api_key: string, const voice_id: string) : RemoteTts {
backend = "elevenlabs"
api_key = |wrap<string>(tts_api_key)
model = "eleven_multilingual_v2"
voice = voice_id
}reply: stream[llm=llm]()
asrDecode.transcribed -> reply.prompt
speak: synthesize[tts=tts]()
reply.token -> speak.text
write: writeLocal(path=output)
speak.audio -> write.dataDépendances
[dependencies]
std = "0.10.3" # flux de base, journalisation, structures de données
http = "0.10.3" # client et serveur HTTP
net = "0.10.3" # aides pour adresses IP
encoding = "0.10.3" # encodage / décodage UTF-8
fs = "0.10.3" # lecture/écriture de fichiers locaux
record = "0.10.3" # enregistrement au microphone
ml = "0.10.3" # LLM, STT, TTS et inférence de modèles locaux