Whisper Python : transcription audio gratuite en français
Publié le 12 mars 2026 — Par l'équipe DEV-AI
Qu'est-ce que Whisper ?
Whisper est un modèle de reconnaissance automatique de la parole (ASR) publié en open-source par OpenAI en septembre 2022. Entraîné sur 680 000 heures d'audio multilingue collectées sur le web, il surpasse la plupart des solutions commerciales sur les langues à ressources réduites — dont le français.
Ses points forts :
- 100 % gratuit : pas de clé API, pas de quota, pas d'abonnement
- 99 langues supportées dont le français, l'arabe, le japonais…
- Robuste au bruit : il gère les accents, les chevauchements et les fonds sonores
- Traduction automatique vers l'anglais en un seul appel
- Open-source : code disponible sur GitHub, utilisable en local sans envoyer vos données
Whisper est disponible en plusieurs tailles de modèle (tiny → large-v3) selon le compromis vitesse/précision que vous recherchez. On l'utilise via la bibliothèque Python officielle openai-whisper ou via faster-whisper, une réimplémentation optimisée.
Installation
Whisper requiert Python 3.8+ et ffmpeg (pour décoder les fichiers audio). Voici comment tout installer :
1. Installer ffmpeg
# Ubuntu / Debian
sudo apt update && sudo apt install ffmpeg
# macOS (Homebrew)
brew install ffmpeg
# Windows (Chocolatey)
choco install ffmpeg
2. Installer la bibliothèque Python
pip install openai-whisper
Si vous avez un GPU NVIDIA, installez la version CUDA de PyTorch pour profiter de l'accélération matérielle :
# PyTorch avec CUDA 11.8
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install openai-whisper
Vérifiez l'installation :
python -c "import whisper; print(whisper.__version__)"
Première transcription en 5 lignes
Voici le code minimal pour transcrire un fichier audio :
import whisper
model = whisper.load_model("base")
result = model.transcribe("audio.mp3")
print(result["text"])
C'est tout. Whisper détecte automatiquement la langue, découpe l'audio en segments et retourne le texte complet dans result["text"]. Le dictionnaire result contient aussi :
result["language"]: langue détectée (ex."fr")result["segments"]: liste de segments avec horodatage
Exemple de sortie
import whisper, json
model = whisper.load_model("base")
result = model.transcribe("conference.mp3")
print("Langue détectée :", result["language"])
print("Texte complet :\n", result["text"])
print("\nPremier segment :")
print(json.dumps(result["segments"][0], indent=2, ensure_ascii=False))
Sortie typique :
Langue détectée : fr
Texte complet :
Bonjour et bienvenue dans cette conférence sur l'intelligence artificielle...
Premier segment :
{
"id": 0,
"seek": 0,
"start": 0.0,
"end": 4.5,
"text": " Bonjour et bienvenue dans cette conférence sur l'intelligence artificielle...",
"tokens": [...],
"temperature": 0.0,
"avg_logprob": -0.21,
"compression_ratio": 1.34,
"no_speech_prob": 0.02
}
Choisir le bon modèle
Whisper propose cinq tailles de modèle. Plus le modèle est grand, plus la précision est élevée — mais plus la transcription est lente et gourmande en mémoire.
| Modèle | Paramètres | VRAM requise | Vitesse (CPU) | Précision FR | Cas d'usage |
|---|---|---|---|---|---|
tiny |
39 M | ~1 Go | ~32× | Correcte | Tests rapides, microcontrôleurs |
base |
74 M | ~1 Go | ~16× | Bonne | Prototypage, démo |
small |
244 M | ~2 Go | ~6× | Très bonne | Production légère, podcasts |
medium |
769 M | ~5 Go | ~2× | Excellente | Réunions, sous-titres |
large-v3 |
1550 M | ~10 Go | ~1× | Maximale | Transcription critique, juridique |
Recommandation pratique : commencez avec small sur CPU, passez à medium si vous avez un GPU ou via faster-whisper. Réservez large-v3 aux cas où la précision est critique (contenu médical, juridique, sous-titres professionnels).
Pour charger un modèle spécifique :
import whisper
# Modèle léger pour CPU
model = whisper.load_model("small")
# Modèle large sur GPU
model = whisper.load_model("large-v3", device="cuda")
# Forcer le CPU même si GPU disponible
model = whisper.load_model("medium", device="cpu")
Transcrire en français
Par défaut, Whisper détecte automatiquement la langue. Mais pour du contenu majoritairement français, il est recommandé de forcer la langue afin d'éviter les erreurs de détection (utile pour les accents forts ou les extraits courts) :
import whisper
model = whisper.load_model("small")
# Forcer la langue française
result = model.transcribe("reunion.mp3", language="fr")
print(result["text"])
Traduire vers l'anglais
Whisper peut aussi traduire directement depuis le français (ou toute autre langue) vers l'anglais en passant task="translate" :
import whisper
model = whisper.load_model("small")
# Transcription en français
result_fr = model.transcribe("discours.mp3", language="fr")
print("FR :", result_fr["text"])
# Traduction automatique vers l'anglais
result_en = model.transcribe("discours.mp3", task="translate")
print("EN :", result_en["text"])
Générer des sous-titres SRT
Les segments horodatés de Whisper se transforment facilement en fichier SRT pour les sous-titres vidéo :
import whisper
def format_timestamp(seconds: float) -> str:
"""Convertit des secondes en format SRT HH:MM:SS,mmm"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
def transcribe_to_srt(audio_path: str, output_path: str, language: str = "fr"):
model = whisper.load_model("small")
result = model.transcribe(audio_path, language=language)
srt_lines = []
for i, segment in enumerate(result["segments"], start=1):
start = format_timestamp(segment["start"])
end = format_timestamp(segment["end"])
text = segment["text"].strip()
srt_lines.append(f"{i}\n{start} --> {end}\n{text}\n")
with open(output_path, "w", encoding="utf-8") as f:
f.write("\n".join(srt_lines))
print(f"Fichier SRT généré : {output_path}")
return result
# Utilisation
transcribe_to_srt("video.mp4", "sous-titres.srt", language="fr")
Traiter différents formats audio
Whisper accepte nativement MP3, WAV, M4A, FLAC, OGG, MP4, MKV et bien d'autres formats grâce à ffmpeg. Voici quelques exemples pratiques :
Traitement par lot (batch processing)
import whisper
from pathlib import Path
def batch_transcribe(folder: str, language: str = "fr", model_name: str = "small"):
"""Transcrit tous les fichiers audio d'un dossier."""
model = whisper.load_model(model_name)
audio_extensions = {".mp3", ".wav", ".m4a", ".flac", ".ogg", ".mp4"}
results = {}
for audio_file in Path(folder).iterdir():
if audio_file.suffix.lower() in audio_extensions:
print(f"Traitement : {audio_file.name}")
result = model.transcribe(str(audio_file), language=language)
results[audio_file.name] = result["text"]
# Sauvegarde du texte
output = audio_file.with_suffix(".txt")
output.write_text(result["text"], encoding="utf-8")
print(f" -> Sauvegardé dans {output.name}")
return results
# Transcrire tous les MP3 d'un dossier
transcriptions = batch_transcribe("./podcasts", language="fr")
print(f"{len(transcriptions)} fichier(s) traité(s)")
Extraire l'audio d'une vidéo avant transcription
import subprocess
import whisper
def transcribe_video(video_path: str, language: str = "fr") -> str:
"""Extrait l'audio d'une vidéo puis transcrit."""
audio_path = video_path.replace(".mp4", "_audio.wav")
# Extraction avec ffmpeg
subprocess.run([
"ffmpeg", "-i", video_path,
"-ar", "16000", # 16 kHz optimal pour Whisper
"-ac", "1", # Mono
"-c:a", "pcm_s16le", # WAV PCM 16 bits
audio_path, "-y"
], check=True, capture_output=True)
model = whisper.load_model("small")
result = model.transcribe(audio_path, language=language)
return result["text"]
texte = transcribe_video("formation-nlp.mp4")
print(texte)
Transcription en temps réel depuis le micro
Whisper n'est pas conçu pour le streaming pur (il fonctionne sur des segments entiers), mais on peut simuler une transcription "quasi temps réel" en enregistrant par morceaux de quelques secondes :
pip install sounddevice numpy scipy
import whisper
import sounddevice as sd
import numpy as np
import scipy.io.wavfile as wav
import tempfile
import os
SAMPLE_RATE = 16000 # Hz
CHUNK_DURATION = 5 # secondes par segment
model = whisper.load_model("base")
print("Transcription en cours... (Ctrl+C pour arrêter)")
try:
while True:
# Enregistrement d'un chunk
audio_data = sd.rec(
int(CHUNK_DURATION * SAMPLE_RATE),
samplerate=SAMPLE_RATE,
channels=1,
dtype="float32"
)
sd.wait()
# Sauvegarde temporaire
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
wav.write(tmp.name, SAMPLE_RATE, audio_data)
tmp_path = tmp.name
# Transcription du chunk
result = model.transcribe(tmp_path, language="fr")
if result["text"].strip():
print(result["text"].strip())
os.unlink(tmp_path)
except KeyboardInterrupt:
print("\nTranscription arrêtée.")
Astuce : pour une vraie transcription en continu avec faible latence, orientez-vous vers whisper-streaming ou whisper_live, des bibliothèques qui implémentent des stratégies de buffer et VAD (Voice Activity Detection).
faster-whisper : 4× plus rapide sur CPU
faster-whisper est une réimplémentation de Whisper basée sur CTranslate2, un moteur d'inférence optimisé. Il offre :
- Jusqu'à 4× plus rapide que l'implémentation officielle sur CPU
- 2× moins de mémoire grâce à la quantification INT8
- Compatible avec tous les modèles Whisper (tiny → large-v3)
Installation
pip install faster-whisper
Utilisation de base
from faster_whisper import WhisperModel
# Chargement avec quantification INT8 (CPU)
model = WhisperModel("small", device="cpu", compute_type="int8")
# Transcription
segments, info = model.transcribe("audio.mp3", language="fr")
print(f"Langue détectée : {info.language} (confiance : {info.language_probability:.0%})")
for segment in segments:
print(f"[{segment.start:.1f}s -> {segment.end:.1f}s] {segment.text}")
Générer un SRT avec faster-whisper
from faster_whisper import WhisperModel
def format_ts(seconds: float) -> str:
h = int(seconds // 3600)
m = int((seconds % 3600) // 60)
s = int(seconds % 60)
ms = int((seconds % 1) * 1000)
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
model = WhisperModel("small", device="cpu", compute_type="int8")
segments, info = model.transcribe("video.mp4", language="fr")
with open("sous-titres.srt", "w", encoding="utf-8") as f:
for i, seg in enumerate(segments, start=1):
f.write(f"{i}\n")
f.write(f"{format_ts(seg.start)} --> {format_ts(seg.end)}\n")
f.write(f"{seg.text.strip()}\n\n")
print("Fichier SRT généré avec faster-whisper !")
Comparatif faster-whisper vs openai-whisper
| Critère | openai-whisper | faster-whisper |
|---|---|---|
| Vitesse CPU | Référence (1×) | 2× à 4× |
| Mémoire RAM | Standard | Moitié moins (INT8) |
| Précision | Référence | Quasi identique |
| GPU (CUDA) | Oui | Oui (float16) |
| Streaming segments | Non | Oui (générateur) |
| API | Simple | Légèrement différente |
| Maintenu par | OpenAI | Communauté (SYSTRAN) |
Cas d'usage concrets
1. Transcription automatique de réunions
import whisper
from pathlib import Path
from datetime import datetime
def transcribe_meeting(audio_path: str) -> dict:
"""Transcrit une réunion et génère un compte-rendu structuré."""
model = whisper.load_model("medium")
result = model.transcribe(audio_path, language="fr")
# Durée totale
duration = result["segments"][-1]["end"] if result["segments"] else 0
# Résumé par blocs de 5 minutes
blocks = {}
for seg in result["segments"]:
block_key = int(seg["start"] // 300) * 5
label = f"{block_key:02d}min"
if label not in blocks:
blocks[label] = []
blocks[label].append(seg["text"].strip())
return {
"date": datetime.now().strftime("%Y-%m-%d"),
"duration_min": round(duration / 60, 1),
"full_text": result["text"],
"blocks": {k: " ".join(v) for k, v in blocks.items()}
}
meeting = transcribe_meeting("reunion-equipe.mp3")
print(f"Durée : {meeting['duration_min']} min")
print("\nCompte-rendu par blocs :")
for time, text in meeting["blocks"].items():
print(f"\n[{time}] {text[:200]}...")
2. Pipeline sous-titrage vidéo
from faster_whisper import WhisperModel
import subprocess
from pathlib import Path
def subtitle_video(video_path: str, lang: str = "fr", burn_in: bool = False):
"""Transcrit une vidéo, génère SRT et optionnellement incruste les sous-titres."""
model = WhisperModel("small", device="cpu", compute_type="int8")
segments, _ = model.transcribe(video_path, language=lang)
# Génération du SRT
srt_path = Path(video_path).with_suffix(".srt")
with open(srt_path, "w", encoding="utf-8") as f:
for i, seg in enumerate(segments, 1):
def ts(s):
h,m = int(s//3600), int((s%3600)//60)
return f"{h:02d}:{m:02d}:{int(s%60):02d},{int((s%1)*1000):03d}"
f.write(f"{i}\n{ts(seg.start)} --> {ts(seg.end)}\n{seg.text.strip()}\n\n")
print(f"SRT généré : {srt_path}")
if burn_in:
# Incruster les sous-titres dans la vidéo via ffmpeg
out_path = Path(video_path).stem + "_sous-titres.mp4"
subprocess.run([
"ffmpeg", "-i", video_path,
"-vf", f"subtitles={srt_path}",
out_path, "-y"
], check=True)
print(f"Vidéo avec sous-titres : {out_path}")
subtitle_video("webinaire.mp4", lang="fr", burn_in=True)
3. Indexation de contenus audio pour moteur de recherche
import whisper
import json
from pathlib import Path
def index_audio_library(folder: str) -> list:
"""Indexe une bibliothèque audio pour la recherche full-text."""
model = whisper.load_model("small")
index = []
for audio_file in Path(folder).glob("**/*.mp3"):
result = model.transcribe(str(audio_file), language="fr")
entry = {
"file": str(audio_file),
"title": audio_file.stem.replace("-", " ").title(),
"text": result["text"],
"language": result["language"],
"segments": [
{"start": s["start"], "end": s["end"], "text": s["text"]}
for s in result["segments"]
]
}
index.append(entry)
print(f"Indexé : {audio_file.name}")
# Sauvegarde de l'index
with open("audio_index.json", "w", encoding="utf-8") as f:
json.dump(index, f, ensure_ascii=False, indent=2)
return index
def search_index(query: str, index_path: str = "audio_index.json") -> list:
"""Recherche dans l'index."""
with open(index_path, encoding="utf-8") as f:
index = json.load(f)
query_lower = query.lower()
results = []
for entry in index:
if query_lower in entry["text"].lower():
# Trouver les segments correspondants
matching = [s for s in entry["segments"] if query_lower in s["text"].lower()]
results.append({
"file": entry["file"],
"title": entry["title"],
"matches": matching
})
return results
# Utilisation
index = index_audio_library("./podcasts")
hits = search_index("intelligence artificielle")
for hit in hits:
print(f"\n{hit['title']} :")
for match in hit["matches"]:
print(f" [{match['start']:.0f}s] {match['text']}")
Limites et alternatives
Limites de Whisper
- Pas de streaming natif : Whisper traite des fichiers complets, pas des flux en temps réel. Pour du streaming, voyez
whisper-streamingouwhisper_live. - Lent sur CPU : le modèle
large-v3peut prendre 10× le temps réel sur CPU. Utilisezfaster-whisperavec quantification INT8. - Hallucinations : sur des passages silencieux ou bruités, Whisper peut générer du texte fictif. Filtrez les segments avec un
no_speech_probélevé (> 0.5). - Pas de diarisation : Whisper ne distingue pas les locuteurs. Combinez avec
pyannote-audiopour la diarisation. - Longues transcriptions : au-delà de 30 minutes, la mémoire peut saturer. Découpez l'audio en chunks avec
pydub.
Comparatif Whisper vs solutions alternatives
| Solution | Prix | Qualité FR | Streaming | RGPD / Local |
|---|---|---|---|---|
| Whisper (local) | Gratuit | Excellent | Non natif | 100 % local |
| OpenAI Whisper API | 0,006 $/min | Excellent | Non | Cloud US |
| Google Speech-to-Text | 0,016 $/min | Très bon | Oui | Cloud Google |
| AWS Transcribe | 0,024 $/min | Bon | Oui | Cloud AWS |
| AssemblyAI | 0,012 $/min | Très bon | Oui | Cloud US |
| vosk | Gratuit | Moyen | Oui | 100 % local |
Conclusion : si vous avez des contraintes RGPD ou budgétaires, Whisper local (ou faster-whisper) est le meilleur choix. Pour du streaming temps réel avec diarisation, les APIs cloud restent plus adaptées — mais impliquent l'envoi de données vers des serveurs étrangers.
Aller plus loin avec le NLP
Notre formation NLP couvre la transcription, la vectorisation, les Transformers et la classification de texte — avec des exemples de code prêts à déployer.
Découvrir la formation NLP →