Aller au contenu principal

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 avec pcm_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

  1. Installez PyAudio sur votre machine
  2. Lancez le script de dictée vocale
  3. Parlez pendant 30 secondes en français
  4. Observez la transcription apparaître en temps réel
  5. 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_microphone produit des chunks de 480 ms par défaut
  • loop.run_in_executor rend 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