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.textFaster 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 resultText-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 chunkEleven 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_pathBark (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é.