Capturer le Microphone avec PyAudio
Du fichier au microphone
Dans la leçon précédente, vous avez transcrit un fichier audio en streaming. L’étape suivante est naturelle : capturer l’audio directement depuis le microphone de votre machine et le transcrire en temps réel.
Pour cela, vous utiliserez PyAudio, la bibliothèque Python de référence pour l’accès aux périphériques audio.
Installation de PyAudio
# Linux (Debian/Ubuntu)
sudo apt-get install portaudio19-dev
pip install pyaudio
# macOS
brew install portaudio
pip install pyaudio
# Windows
pip install pyaudio
Le générateur de microphone
Voici le générateur asynchrone qui capture l’audio du microphone et produit des chunks PCM compatibles avec Voxtral Realtime :
import asyncio
import pyaudio
async def iter_microphone(
sample_rate: int = 16000,
chunk_duration_ms: int = 480
):
"""Capture le microphone et produit des chunks PCM.
Args:
sample_rate: Taux d'échantillonnage (16000 Hz pour Voxtral)
chunk_duration_ms: Durée de chaque chunk en millisecondes
Yields:
bytes: Chunks d'audio PCM 16-bit mono
"""
p = pyaudio.PyAudio()
# Nombre d'échantillons par chunk
chunk_samples = int(sample_rate * chunk_duration_ms / 1000)
# Ouvrir le flux microphone
stream = p.open(
format=pyaudio.paInt16, # PCM 16-bit
channels=1, # Mono
rate=sample_rate, # 16 kHz
input=True, # Mode capture
frames_per_buffer=chunk_samples
)
loop = asyncio.get_running_loop()
try:
print("Microphone actif — parlez...")
while True:
# Lire le chunk de manière non-bloquante
data = await loop.run_in_executor(
None,
stream.read,
chunk_samples,
False # exception_on_overflow
)
yield data
finally:
stream.stop_stream()
stream.close()
p.terminate()
print("Microphone fermé")
Comprendre les paramètres
sample_rate=16000— Voxtral attend du 16 kHz. Ne changez pas cette valeur.chunk_duration_ms=480— Chaque chunk fait 480 ms. C’est un bon compromis entre latence et efficacité réseau. Un chunk plus court (par exemple 100 ms) augmente la réactivité mais aussi le nombre de requêtes réseau.pyaudio.paInt16— Format PCM 16 bits signé, compatible avecpcm_s16le.channels=1— Audio mono, requis par Voxtral.
Calcul de la taille des chunks
Pour sample_rate=16000 et chunk_duration_ms=480 :
chunk_samples = 16000 × 480 / 1000 = 7680 échantillons
taille_octets = 7680 × 2 octets = 15360 octets par chunk
Programme complet : micro vers transcription
import asyncio
import os
import signal
from mistralai import Mistral
from mistralai.models import (
AudioFormat,
TranscriptionStreamTextDelta,
TranscriptionStreamDone
)
import pyaudio
# Flag pour arrêter proprement
en_cours = True
def signal_handler(sig, frame):
global en_cours
print("\n\nArrêt en cours...")
en_cours = False
signal.signal(signal.SIGINT, signal_handler)
async def iter_microphone(sample_rate=16000, chunk_duration_ms=480):
"""Capture le microphone jusqu'à interruption (Ctrl+C)."""
p = pyaudio.PyAudio()
chunk_samples = int(sample_rate * chunk_duration_ms / 1000)
stream = p.open(
format=pyaudio.paInt16,
channels=1,
rate=sample_rate,
input=True,
frames_per_buffer=chunk_samples
)
loop = asyncio.get_running_loop()
try:
while en_cours:
data = await loop.run_in_executor(
None, stream.read, chunk_samples, False
)
yield data
finally:
stream.stop_stream()
stream.close()
p.terminate()
async def main():
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
audio_format = AudioFormat(encoding="pcm_s16le", sample_rate=16000)
print("=" * 50)
print("TRANSCRIPTION EN DIRECT")
print("Parlez dans le microphone (Ctrl+C pour arrêter)")
print("=" * 50)
print()
texte_complet = []
async for event in client.audio.realtime.transcribe_stream(
audio_stream=iter_microphone(),
model="voxtral-mini-transcribe-realtime-2602",
audio_format=audio_format,
):
if isinstance(event, TranscriptionStreamTextDelta):
print(event.text, end="", flush=True)
texte_complet.append(event.text)
elif isinstance(event, TranscriptionStreamDone):
break
# Sauvegarder
texte_final = "".join(texte_complet)
if texte_final.strip():
with open("dictee.txt", "w", encoding="utf-8") as f:
f.write(texte_final)
print(f"\n\nTranscription sauvegardée dans dictee.txt")
print(f"Longueur : {len(texte_final)} caractères")
else:
print("\n\nAucun texte transcrit.")
asyncio.run(main())
Utilisation
python dictee_vocale.py
# Parlez dans votre microphone
# Le texte s'affiche en temps réel
# Ctrl+C pour arrêter
Choisir le bon périphérique audio
Si vous avez plusieurs microphones, vous pouvez lister les périphériques et en sélectionner un :
def lister_microphones():
"""Liste tous les périphériques d'entrée audio disponibles."""
p = pyaudio.PyAudio()
print("Périphériques d'entrée disponibles :")
for i in range(p.get_device_count()):
info = p.get_device_info_by_index(i)
if info["maxInputChannels"] > 0:
print(f" [{i}] {info['name']} "
f"(canaux: {info['maxInputChannels']}, "
f"taux: {int(info['defaultSampleRate'])} Hz)")
p.terminate()
lister_microphones()
Pour utiliser un périphérique spécifique, ajoutez input_device_index dans p.open() :
stream = p.open(
format=pyaudio.paInt16,
channels=1,
rate=sample_rate,
input=True,
input_device_index=2, # Index du périphérique
frames_per_buffer=chunk_samples
)
Mise en pratique
- Installez PyAudio sur votre machine
- Lancez le script de dictée vocale
- Parlez pendant 30 secondes en français
- Observez la transcription apparaître en temps réel
- Arrêtez avec Ctrl+C et vérifiez le fichier
dictee.txt
Points clés à retenir
- PyAudio capture le microphone en PCM 16-bit mono 16 kHz, exactement ce que Voxtral attend
- Le générateur
iter_microphoneproduit des chunks de 480 ms par défaut loop.run_in_executorrend la lecture du microphone non bloquante dans asyncio- Ctrl+C arrête proprement la capture via un signal handler
- Listez les périphériques avec
get_device_count()pour choisir le bon microphone