Aller au contenu principal

Diarisation : Identifier Qui Parle

Mis à jour le 29 juillet 2026

Qu’est-ce que la diarisation

La diarisation (speaker diarization) est la capacité à identifier et séparer les différents locuteurs dans un enregistrement audio. Le modèle attribue automatiquement un identifiant à chaque voix distincte et segmente la transcription en conséquence.

L’écart de valeur est considérable. Une réunion à cinq personnes transcrite sans diarisation produit un bloc de texte où plus personne ne sait qui a pris quel engagement ; la même réunion diarisée devient un compte-rendu attribuable. C’est pourquoi cette fonctionnalité est essentielle pour tous les enregistrements multi-locuteurs : réunions, interviews, appels téléphoniques, débats, tables rondes.

Activer la diarisation

Un seul paramètre suffit : diarize=True.

import os
from mistralai import Mistral

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

with open("reunion_equipe.mp3", "rb") as f:
    response = client.audio.transcriptions.complete(
        model="voxtral-mini-latest",
        file={"content": f, "file_name": "reunion_equipe.mp3"},
        diarize=True,
        timestamp_granularities=["segment"]
    )

La diarisation fonctionne de pair avec les timestamps par segment : c’est le segment qui porte l’information. Chaque segment retourné contient désormais un champ speaker identifiant le locuteur.

Exploiter les résultats

L’affichage le plus simple parcourt les segments et préfixe chaque prise de parole de son auteur et de son horodatage.

for seg in response.segments:
    temps = f"{seg.start:.1f}s"
    print(f"[{temps}] {seg.speaker} : {seg.text}")

Le résultat prend cette forme :

[0.0s] speaker_0 : Bonjour à tous, on commence la réunion hebdomadaire.
[3.2s] speaker_0 : Julien, tu veux commencer avec le point technique ?
[5.8s] speaker_1 : Oui, alors cette semaine on a finalisé la migration.
[12.4s] speaker_1 : Tout est déployé en production depuis mercredi.
[15.1s] speaker_2 : Super, et côté performances, on a vu une amélioration ?
[18.3s] speaker_1 : Oui, le temps de réponse a baissé de trente pour cent.

Les locuteurs sont identifiés comme speaker_0, speaker_1, speaker_2, etc. Le modèle ne connaît pas les noms — c’est à vous de mapper ces identifiants aux personnes réelles. En pratique, une écoute des trente premières secondes suffit à établir la correspondance, que vous consignez ensuite dans un simple dictionnaire.

# Mapping des identifiants aux noms réels
noms_locuteurs = {
    "speaker_0": "Marie (Manager)",
    "speaker_1": "Julien (Tech Lead)",
    "speaker_2": "Sarah (Product)",
}

for seg in response.segments:
    nom = noms_locuteurs.get(seg.speaker, seg.speaker)
    minutes = int(seg.start // 60)
    secondes = int(seg.start % 60)
    print(f"[{minutes:02d}:{secondes:02d}] {nom}")
    print(f"  {seg.text}\n")

Une fois le mapping en place, les durées de segment se transforment en indicateurs. Cumuler seg.end - seg.start par locuteur vous donne le temps de parole de chacun — une mesure que les animateurs de réunion et les responsables qualité en centre d’appels utilisent volontiers.

from collections import defaultdict

temps_parole = defaultdict(float)

for seg in response.segments:
    duree = seg.end - seg.start
    temps_parole[seg.speaker] += duree

print("=== Temps de parole ===")
total = sum(temps_parole.values())
for locuteur, duree in sorted(temps_parole.items()):
    nom = noms_locuteurs.get(locuteur, locuteur)
    pourcentage = (duree / total) * 100
    minutes = int(duree // 60)
    secondes = int(duree % 60)
    print(f"{nom} : {minutes}m{secondes:02d}s ({pourcentage:.1f}%)")
=== Temps de parole ===
Marie (Manager) : 8m23s (28.4%)
Julien (Tech Lead) : 12m45s (43.2%)
Sarah (Product) : 8m22s (28.4%)

Générer un compte-rendu structuré

La diarisation combinée aux segments permet de produire un compte-rendu directement lisible. L’astuce du script suivant tient en une ligne : il n’écrit un nouvel en-tête que lorsque le locuteur change, ce qui regroupe les interventions consécutives d’une même personne au lieu de les émietter.

def generer_compte_rendu(segments, noms):
    """Génère un compte-rendu Markdown à partir des segments diarisés."""
    lignes = ["# Compte-rendu de réunion\n"]
    locuteur_actuel = None

    for seg in segments:
        nom = noms.get(seg.speaker, seg.speaker)

        if seg.speaker != locuteur_actuel:
            locuteur_actuel = seg.speaker
            minutes = int(seg.start // 60)
            secondes = int(seg.start % 60)
            lignes.append(f"\n**{nom}** ({minutes:02d}:{secondes:02d}) :")

        lignes.append(f"  {seg.text}")

    return "\n".join(lignes)


compte_rendu = generer_compte_rendu(response.segments, noms_locuteurs)

with open("compte_rendu.md", "w", encoding="utf-8") as f:
    f.write(compte_rendu)

print("Compte-rendu généré")

Aller jusqu’à l’analyse complète

Voici le script qui rassemble tout ce qui précède : transcription diarisée, statistiques par intervenant et restitution en JSON, prêt à alimenter un tableau de bord ou un LLM de synthèse.

import os
import json
from collections import defaultdict
from mistralai import Mistral

def analyser_reunion(chemin_audio: str, noms: dict = None):
    """Transcrit et analyse une réunion complète."""
    client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

    # Transcrire avec diarisation
    with open(chemin_audio, "rb") as f:
        response = client.audio.transcriptions.complete(
            model="voxtral-mini-latest",
            file={"content": f, "file_name": chemin_audio},
            diarize=True,
            timestamp_granularities=["segment"]
        )

    noms = noms or {}

    # Statistiques
    stats = defaultdict(lambda: {"duree": 0.0, "segments": 0, "mots": 0})
    for seg in response.segments:
        stats[seg.speaker]["duree"] += seg.end - seg.start
        stats[seg.speaker]["segments"] += 1
        stats[seg.speaker]["mots"] += len(seg.text.split())

    # Résultat
    resultat = {
        "transcription": response.text,
        "nb_locuteurs": len(stats),
        "duree_totale": max(s.end for s in response.segments),
        "statistiques": {
            noms.get(loc, loc): {
                "duree_secondes": round(data["duree"], 1),
                "nb_segments": data["segments"],
                "nb_mots": data["mots"]
            }
            for loc, data in stats.items()
        }
    }

    return resultat

# Utilisation
resultat = analyser_reunion("reunion.mp3", {
    "speaker_0": "Marie",
    "speaker_1": "Julien",
    "speaker_2": "Sarah"
})

print(json.dumps(resultat["statistiques"], indent=2, ensure_ascii=False))

Ce que la diarisation ne fait pas

Gardez en tête quatre limites avant de promettre un résultat à un client. Le modèle ne reconnaît aucune identité : il distingue des voix, pas des personnes, et le mapping reste à votre charge. Il détecte en revanche seul le nombre de locuteurs, vous n’avez pas à le spécifier. Deux voix très proches — par exemple deux personnes du même sexe et du même âge — peuvent occasionnellement être confondues, ce qui justifie une relecture rapide des passages critiques. Enfin, la diarisation n’existe qu’en mode offline avec Voxtral Mini Transcribe V2 : elle n’est pas disponible avec Voxtral Realtime, et aucun réglage ne contourne cette contrainte.

Points clés à retenir

  • Activez la diarisation avec diarize=True — un seul paramètre
  • Combinez avec timestamp_granularities=["segment"] pour des résultats structurés
  • Chaque segment contient un champ speaker (speaker_0, speaker_1, etc.)
  • Mappez les identifiants aux noms réels dans votre code
  • Exploitez les statistiques : temps de parole, nombre d’interventions, nombre de mots
  • La diarisation n’est disponible qu’en mode offline