Wiki IA
LLM et IA Générative

Audio et Speech

Reconnaissance vocale, synthèse vocale et traitement audio par IA

L'IA audio transforme la façon dont nous interagissons avec les machines : reconnaissance vocale (Speech-to-Text), synthèse vocale (Text-to-Speech), clonage de voix, et génération de musique.

Vue d'ensemble

TECHNOLOGIES AUDIO IA :

┌─────────────────────────────────────────────────────────────┐
│                      AUDIO IA                                │
├──────────────────┬──────────────────┬───────────────────────┤
│   RECONNAISSANCE │    SYNTHÈSE      │     GÉNÉRATION        │
│   (Input)        │    (Output)      │     (Création)        │
├──────────────────┼──────────────────┼───────────────────────┤
│ • Speech-to-Text │ • Text-to-Speech │ • Musique             │
│ • Transcription  │ • Clonage voix   │ • Effets sonores      │
│ • Diarisation    │ • Voix émotive   │ • Séparation sources  │
│ • Détection lang │ • Multilingue    │ • Transformation      │
└──────────────────┴──────────────────┴───────────────────────┘

Speech-to-Text (STT)

Whisper (OpenAI)

Whisper est le modèle de référence pour la transcription audio, capable de gérer plus de 100 langues.

import whisper

# Charger le modèle (tiny, base, small, medium, large, large-v3)
model = whisper.load_model("large-v3")

def transcribe_audio(audio_path: str, language: str = None) -> dict:
    """Transcrit un fichier audio."""
    result = model.transcribe(
        audio_path,
        language=language,  # None = détection auto
        task="transcribe",  # ou "translate" pour traduire en anglais
        verbose=False
    )

    return {
        "text": result["text"],
        "language": result["language"],
        "segments": result["segments"]  # Avec timestamps
    }

# Exemple
result = transcribe_audio("interview.mp3", language="fr")
print(result["text"])

# Avec timestamps
for segment in result["segments"]:
    print(f"[{segment['start']:.1f}s - {segment['end']:.1f}s] {segment['text']}")

Whisper via API OpenAI

from openai import OpenAI

client = OpenAI()

def transcribe_with_api(audio_path: str) -> str:
    """Transcription via API OpenAI."""
    with open(audio_path, "rb") as audio_file:
        transcript = client.audio.transcriptions.create(
            model="whisper-1",
            file=audio_file,
            language="fr",
            response_format="verbose_json",  # Inclut les timestamps
            timestamp_granularities=["word", "segment"]
        )

    return transcript

# Traduction automatique vers l'anglais
def translate_audio(audio_path: str) -> str:
    with open(audio_path, "rb") as audio_file:
        translation = client.audio.translations.create(
            model="whisper-1",
            file=audio_file
        )

    return translation.text

Faster Whisper (optimisé)

from faster_whisper import WhisperModel

# 4x plus rapide que Whisper original
model = WhisperModel("large-v3", device="cuda", compute_type="float16")

def fast_transcribe(audio_path: str) -> str:
    """Transcription rapide avec faster-whisper."""
    segments, info = model.transcribe(
        audio_path,
        language="fr",
        beam_size=5,
        vad_filter=True,  # Filtre les silences
        vad_parameters=dict(min_silence_duration_ms=500)
    )

    text = " ".join([segment.text for segment in segments])

    return {
        "text": text,
        "language": info.language,
        "language_probability": info.language_probability,
        "duration": info.duration
    }

Transcription en temps réel

import pyaudio
import numpy as np
from faster_whisper import WhisperModel
import queue
import threading

class RealtimeTranscriber:
    def __init__(self, model_size: str = "base"):
        self.model = WhisperModel(model_size, device="cuda")
        self.audio_queue = queue.Queue()
        self.sample_rate = 16000
        self.chunk_duration = 3  # secondes

    def audio_callback(self, in_data, frame_count, time_info, status):
        audio_data = np.frombuffer(in_data, dtype=np.float32)
        self.audio_queue.put(audio_data)
        return (in_data, pyaudio.paContinue)

    def process_audio(self):
        """Thread de traitement audio."""
        buffer = np.array([], dtype=np.float32)

        while True:
            # Récupérer l'audio du buffer
            while not self.audio_queue.empty():
                buffer = np.concatenate([buffer, self.audio_queue.get()])

            # Transcrire si assez de données
            if len(buffer) >= self.sample_rate * self.chunk_duration:
                segments, _ = self.model.transcribe(buffer)
                for segment in segments:
                    print(f">> {segment.text}")
                buffer = np.array([], dtype=np.float32)

    def start(self):
        p = pyaudio.PyAudio()

        stream = p.open(
            format=pyaudio.paFloat32,
            channels=1,
            rate=self.sample_rate,
            input=True,
            frames_per_buffer=int(self.sample_rate * 0.1),
            stream_callback=self.audio_callback
        )

        # Lancer le thread de traitement
        process_thread = threading.Thread(target=self.process_audio)
        process_thread.start()

        stream.start_stream()
        print("Transcription en cours... (Ctrl+C pour arrêter)")

        try:
            while stream.is_active():
                pass
        except KeyboardInterrupt:
            stream.stop_stream()

        stream.close()
        p.terminate()

Diarisation (identification des locuteurs)

from pyannote.audio import Pipeline
import torch

# Nécessite un token Hugging Face acceptant les conditions d'utilisation
pipeline = Pipeline.from_pretrained(
    "pyannote/speaker-diarization-3.1",
    use_auth_token="YOUR_HF_TOKEN"
)
pipeline = pipeline.to(torch.device("cuda"))

def diarize_audio(audio_path: str) -> list:
    """Identifie les locuteurs dans un fichier audio."""
    diarization = pipeline(audio_path)

    segments = []
    for turn, _, speaker in diarization.itertracks(yield_label=True):
        segments.append({
            "start": turn.start,
            "end": turn.end,
            "speaker": speaker
        })

    return segments

# Combiner avec transcription
def transcribe_with_speakers(audio_path: str) -> list:
    """Transcription avec identification des locuteurs."""
    # Diarisation
    speaker_segments = diarize_audio(audio_path)

    # Transcription
    model = WhisperModel("large-v3", device="cuda")
    transcription_segments, _ = model.transcribe(audio_path)

    # Associer chaque segment de texte à un locuteur
    result = []
    for t_seg in transcription_segments:
        # Trouver le locuteur actif à ce moment
        speaker = "Unknown"
        for s_seg in speaker_segments:
            if s_seg["start"] <= t_seg.start <= s_seg["end"]:
                speaker = s_seg["speaker"]
                break

        result.append({
            "start": t_seg.start,
            "end": t_seg.end,
            "speaker": speaker,
            "text": t_seg.text
        })

    return result

Text-to-Speech (TTS)

OpenAI TTS

from openai import OpenAI
from pathlib import Path

client = OpenAI()

def text_to_speech(
    text: str,
    voice: str = "alloy",  # alloy, echo, fable, onyx, nova, shimmer
    model: str = "tts-1-hd",  # tts-1 (rapide) ou tts-1-hd (qualité)
    output_path: str = "speech.mp3"
) -> str:
    """Convertit du texte en audio."""
    response = client.audio.speech.create(
        model=model,
        voice=voice,
        input=text,
        speed=1.0  # 0.25 à 4.0
    )

    response.stream_to_file(output_path)
    return output_path

# Exemple
text_to_speech(
    "Bonjour ! Je suis une voix générée par intelligence artificielle.",
    voice="nova",
    output_path="greeting.mp3"
)

# Streaming pour longues réponses
def stream_tts(text: str, voice: str = "alloy"):
    """TTS en streaming."""
    response = client.audio.speech.create(
        model="tts-1",
        voice=voice,
        input=text,
        response_format="opus"  # Meilleur pour streaming
    )

    # Jouer en temps réel avec un lecteur audio
    for chunk in response.iter_bytes(chunk_size=1024):
        yield chunk

Eleven Labs (clonage de voix)

from elevenlabs import generate, play, clone, Voice, VoiceSettings
from elevenlabs import set_api_key

set_api_key("YOUR_API_KEY")

def generate_speech(text: str, voice_id: str = "Rachel") -> bytes:
    """Génère de l'audio avec Eleven Labs."""
    audio = generate(
        text=text,
        voice=voice_id,
        model="eleven_multilingual_v2"
    )

    return audio

# Clonage de voix
def clone_voice(
    name: str,
    audio_files: list[str],
    description: str = ""
) -> Voice:
    """Clone une voix à partir d'échantillons audio."""
    voice = clone(
        name=name,
        description=description,
        files=audio_files  # 1-25 fichiers audio de la voix à cloner
    )

    return voice

# Utiliser la voix clonée
cloned_voice = clone_voice(
    name="Ma voix",
    audio_files=["sample1.mp3", "sample2.mp3", "sample3.mp3"]
)

audio = generate(
    text="Ceci est généré avec ma voix clonée !",
    voice=cloned_voice
)

Coqui TTS (open source)

from TTS.api import TTS

# Lister les modèles disponibles
print(TTS().list_models())

# Charger un modèle multilingue
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2")
tts = tts.to("cuda")

def synthesize_speech(
    text: str,
    speaker_wav: str,  # Fichier audio pour cloner la voix
    language: str = "fr",
    output_path: str = "output.wav"
) -> str:
    """Synthèse vocale avec clonage de voix."""
    tts.tts_to_file(
        text=text,
        speaker_wav=speaker_wav,
        language=language,
        file_path=output_path
    )

    return output_path

# Sans clonage (voix par défaut)
def simple_tts(text: str, output_path: str = "output.wav") -> str:
    tts_simple = TTS("tts_models/fr/css10/vits")
    tts_simple.tts_to_file(text=text, file_path=output_path)
    return output_path

Bark (génération expressive)

from bark import SAMPLE_RATE, generate_audio, preload_models
from scipy.io.wavfile import write as write_wav
import numpy as np

# Précharger les modèles
preload_models()

def generate_with_bark(
    text: str,
    output_path: str = "bark_output.wav"
) -> str:
    """Génération expressive avec Bark."""
    # Bark comprend les annotations
    # [laughs], [sighs], [music], [gasps], ♪ pour chanter, etc.

    audio_array = generate_audio(text)

    write_wav(output_path, SAMPLE_RATE, audio_array)

    return output_path

# Exemples de texte expressif
texts = [
    "Bonjour ! [laughs] Comment allez-vous ?",
    "Oh non... [sighs] C'est vraiment dommage.",
    "♪ La la la, je chante une chanson ♪",
]

for i, text in enumerate(texts):
    generate_with_bark(text, f"expressive_{i}.wav")

Traitement audio avancé

Séparation de sources (Demucs)

import torch
from demucs import pretrained
from demucs.apply import apply_model
import torchaudio

def separate_audio(
    audio_path: str,
    output_dir: str = "./separated"
) -> dict:
    """Sépare les sources audio (voix, drums, bass, other)."""
    # Charger le modèle
    model = pretrained.get_model("htdemucs")
    model = model.to("cuda")

    # Charger l'audio
    wav, sr = torchaudio.load(audio_path)
    wav = wav.to("cuda")

    # Séparer
    with torch.no_grad():
        sources = apply_model(model, wav[None], device="cuda")[0]

    # Sauvegarder chaque source
    source_names = ["drums", "bass", "other", "vocals"]
    paths = {}

    for source, name in zip(sources, source_names):
        path = f"{output_dir}/{name}.wav"
        torchaudio.save(path, source.cpu(), sr)
        paths[name] = path

    return paths

# Exemple : extraire uniquement les voix
paths = separate_audio("song.mp3")
print(f"Voix isolées : {paths['vocals']}")

Classification audio

from transformers import pipeline

# Classification de sons
classifier = pipeline(
    "audio-classification",
    model="MIT/ast-finetuned-audioset-10-10-0.4593"
)

def classify_audio(audio_path: str, top_k: int = 5) -> list:
    """Classifie un fichier audio."""
    results = classifier(audio_path, top_k=top_k)

    return [
        {"label": r["label"], "score": r["score"]}
        for r in results
    ]

# Détection d'émotions vocales
emotion_classifier = pipeline(
    "audio-classification",
    model="ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition"
)

def detect_emotion(audio_path: str) -> dict:
    """Détecte l'émotion dans la voix."""
    results = emotion_classifier(audio_path)
    return {r["label"]: r["score"] for r in results}

Génération de musique

from audiocraft.models import MusicGen
from audiocraft.data.audio import audio_write
import torch

# Charger le modèle (small, medium, large)
model = MusicGen.get_pretrained("facebook/musicgen-medium")
model = model.to("cuda")

def generate_music(
    prompt: str,
    duration: int = 10,  # secondes
    output_path: str = "music"
) -> str:
    """Génère de la musique à partir d'un prompt."""
    model.set_generation_params(
        duration=duration,
        temperature=1.0,
        top_k=250,
        top_p=0.0
    )

    wav = model.generate([prompt])

    audio_write(
        output_path,
        wav[0].cpu(),
        model.sample_rate,
        strategy="loudness"
    )

    return f"{output_path}.wav"

# Exemples
prompts = [
    "A calm piano melody with soft strings, ambient",
    "Upbeat electronic dance music with heavy bass",
    "Acoustic guitar folk song, gentle and warm",
    "Epic orchestral soundtrack, dramatic and powerful"
]

for i, prompt in enumerate(prompts):
    generate_music(prompt, duration=15, output_path=f"track_{i}")

Applications pratiques

Transcription de réunions

def transcribe_meeting(audio_path: str) -> dict:
    """Pipeline complet pour transcrire une réunion."""
    # 1. Transcription avec timestamps
    model = WhisperModel("large-v3", device="cuda")
    segments, info = model.transcribe(audio_path)

    # 2. Diarisation
    from pyannote.audio import Pipeline
    diarization = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")
    speaker_segments = diarization(audio_path)

    # 3. Combiner
    transcript = []
    for segment in segments:
        # Trouver le locuteur
        speaker = "Unknown"
        for turn, _, spk in speaker_segments.itertracks(yield_label=True):
            if turn.start <= segment.start <= turn.end:
                speaker = spk
                break

        transcript.append({
            "time": f"{segment.start:.1f}s",
            "speaker": speaker,
            "text": segment.text
        })

    # 4. Générer un résumé avec un LLM
    from anthropic import Anthropic
    client = Anthropic()

    full_text = "\n".join([
        f"[{t['speaker']}] {t['text']}"
        for t in transcript
    ])

    summary = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": f"""Résume cette réunion avec les points clés et actions à mener :

{full_text}

Résumé :"""
        }]
    ).content[0].text

    return {
        "transcript": transcript,
        "summary": summary,
        "duration": info.duration,
        "language": info.language
    }

Assistant vocal

import speech_recognition as sr
from openai import OpenAI

class VoiceAssistant:
    def __init__(self):
        self.recognizer = sr.Recognizer()
        self.client = OpenAI()
        self.conversation = []

    def listen(self) -> str:
        """Écoute le microphone et transcrit."""
        with sr.Microphone() as source:
            print("Écoute...")
            self.recognizer.adjust_for_ambient_noise(source)
            audio = self.recognizer.listen(source)

        try:
            # Utiliser Whisper via l'API
            with open("temp.wav", "wb") as f:
                f.write(audio.get_wav_data())

            with open("temp.wav", "rb") as f:
                transcript = self.client.audio.transcriptions.create(
                    model="whisper-1",
                    file=f,
                    language="fr"
                )

            return transcript.text

        except Exception as e:
            print(f"Erreur : {e}")
            return ""

    def think(self, user_input: str) -> str:
        """Génère une réponse avec le LLM."""
        self.conversation.append({"role": "user", "content": user_input})

        response = self.client.chat.completions.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": "Tu es un assistant vocal utile et concis."}
            ] + self.conversation
        )

        assistant_message = response.choices[0].message.content
        self.conversation.append({"role": "assistant", "content": assistant_message})

        return assistant_message

    def speak(self, text: str):
        """Synthétise et joue la réponse."""
        response = self.client.audio.speech.create(
            model="tts-1",
            voice="nova",
            input=text
        )

        response.stream_to_file("response.mp3")
        # Jouer l'audio (utiliser pygame, playsound, etc.)

    def run(self):
        """Boucle principale de l'assistant."""
        print("Assistant vocal démarré. Dites 'stop' pour arrêter.")

        while True:
            user_input = self.listen()
            print(f"Vous : {user_input}")

            if "stop" in user_input.lower():
                print("Au revoir !")
                break

            response = self.think(user_input)
            print(f"Assistant : {response}")

            self.speak(response)

Résumé

AUDIO IA :

SPEECH-TO-TEXT
├── Whisper : Standard de référence, multilingue
├── Faster Whisper : 4x plus rapide
├── Diarisation : Identification des locuteurs
└── Temps réel : Streaming avec buffer

TEXT-TO-SPEECH
├── OpenAI TTS : Simple, qualité, 6 voix
├── Eleven Labs : Clonage, expressivité
├── Coqui XTTS : Open source, clonage
└── Bark : Expressions (rires, musique)

TRAITEMENT AVANCÉ
├── Demucs : Séparation de sources
├── Classification : Émotions, sons
├── MusicGen : Génération de musique
└── Effets : Transformation de voix

APPLICATIONS
├── Transcription de réunions
├── Assistants vocaux
├── Sous-titrage automatique
├── Accessibilité
└── Production audio/podcast

Éthique : Le clonage de voix soulève des questions éthiques importantes. Obtenez toujours le consentement de la personne dont vous clonez la voix, et n'utilisez pas ces technologies pour de la désinformation ou de l'usurpation d'identité.

On this page