Transcription de réunions dans Gemini 3.5 Transcribe : intervenants, horodatages et vocabulaire en pratique
Un guide pratique pour transformer l'enregistrement d'une réunion de 45 minutes en transcription vérifiée ou en base de sous-titres avec Gemini 3.5 Transcribe : sélection des options de configuration, découpage adéquat des fichiers audio longs, assemblage des horodatages par mot via le SDK Python et exécution du contrôle qualité manuel.
Sommaire

Transformer l’enregistrement audio d’une réunion professionnelle en un document de travail fiable exige des choix d’architecture délibérés lors de la configuration des paramètres de reconnaissance vocale. Dans Gemini 3.5 Transcribe, il n’existe aucun mode universel « tout-en-un » : la normalisation éditoriale approfondie (smart), la séparation des intervenants (diarization_mode), la grille temporelle mot à mot (timestamp_granularities) et les lexiques propres à un domaine (custom_vocabulary) constituent des fonctionnalités d’API mutuellement isolées.
Tout pipeline de traitement doit commencer par définir son objectif final : avez-vous besoin d’un bloc de texte concis et fluide pour une lecture rapide, d’une base structurée pour une analyse en aval, ou d’un ensemble de repères temporels précis pour le montage vidéo ? Tenter de combiner des paramètres mutuellement incompatibles entraîne des erreurs de validation de schéma avant même le traitement de la requête.
Voici un guide pratique complet de bout en bout : comment préparer un enregistrement de 45 minutes de deux intervenants truffé de terminologie technique, respecter les limites documentées de l’API, traiter les deux parties à l’aide du SDK Python officiel, assembler des structures de données préliminaires, les vérifier et les corriger par rapport à l’enregistrement audio, puis transmettre des copies vérifiées à un rédacteur de compte rendu ou à un monteur de sous-titres.
Contraintes architecturales et conflits de paramètres
Pour illustrer ce pipeline, prenons l’exemple d’une session de travail classique : Alexey (Tech Lead) et Mikhail (Product Manager) passent 45 minutes à discuter de l’architecture de migration et du déploiement de services associés aux noms de projets internes DataPulse et CloudForge. La conversation comporte du jargon technique, des emprunts lexicaux, des interruptions rapides et des hésitations.
Lors de la conception d’une intégration avec Gemini 3.5 Transcribe, trois règles strictes doivent être prises en compte :
- Incompatibilité entre vocabulaire personnalisé et métadonnées structurelles : Le paramètre
custom_vocabulary(qui accepte jusqu’à 1 000 expressions, avec une recommandation pratique allant jusqu’à 100) ne peut pas être transmis conjointement avecdiarization_modeoutimestamp_granularities. Vous devez opérer un arbitrage de conception : soit confier au modèle la transcription exacte des noms de marques spécialisés (en renonçant à l’étiquetage automatique des intervenants et aux horodatages), soit demander l’alignement précis des intervenants et du temps tout en validant la terminologie spécialisée lors de la phase de post-traitement. - Incompatibilité entre le mode Smart et l’alignement temporel : Le mode
smartapplique une normalisation de la parole : il supprime les tics de langage, les bégaiements et les faux départs tout en restructurant la syntaxe grammaticale. Les jetons textuels étant supprimés, fusionnés ou réorganisés, le modèle ne peut pas faire correspondre le texte obtenu à l’axe temporel du flux audio sous-jacent. Par conséquent, l’attribution des intervenants et les horodatages au mot près ne sont pas disponibles en modesmart. De plus, ce mode renvoie uniquement du texte continu non annoté (output_text) et n’extrait pas automatiquement de liste de tâches ou de points d’action (Action Items). - Limite de 30 minutes pour les métadonnées avancées : Les requêtes de transcription standard sans annotations détaillées acceptent des fichiers audio d’une durée maximale de 60 minutes. En revanche, dès que vous activez
diarization_modeoutimestamp_granularities, la durée maximale documentée par fichier descend à 30 minutes. La soumission de fichiers dépassant ce seuil sort des spécifications prises en charge par l’API et ne doit pas être tentée ; tout enregistrement long doit être découpé côté client avant son envoi.
Préparation et découpage de l’enregistrement de 45 minutes
Pour extraire la diarisation et les horodatages au niveau des mots à partir d’un enregistrement de 45 minutes, le fichier source doit être scindé en segments strictement inférieurs à 30 minutes. Dans le cadre de notre scénario hypothétique, nous divisons l’enregistrement en deux segments :
- Partie 1 : 00:00–25:00 (considérée conventionnellement comme durant exactement 1500.0 secondes) ;
- Partie 2 : 25:00–45:00 (les 20 minutes restantes, soit 1200.0 secondes).
La frontière de 1500.0 secondes est choisie ici dans le seul but de simplifier les calculs de cet exemple. Dans un environnement de production, les découpes doivent être positionnées lors de pauses naturelles entre les tours de parole, et la durée physique exacte du premier segment doit impérativement être extraite des métadonnées du fichier multimédia à l’aide d’un outil d’inspection tel que ffprobe.
Le découpage de l’audio introduit deux difficultés majeures en matière de continuité :
- Réinitialisation des horodatages dans le second segment : L’API traite le second segment comme un fichier totalement indépendant, réinitialisant ses décalages temporels internes par mot pour démarrer à
0.000s. Pour reconstituer une chronologie continue sur l’ensemble de la réunion, la durée réelle du premier segment doit être ajoutée programmatiquement à chaque horodatage de mot extrait du second segment. - Portée locale des étiquettes d’intervenants : Le modèle attribue les identifiants d’intervenants tels que
spk_1etspk_2de manière isolée au sein de chaque appel d’API. L’intervenant désigné commespk_1dans le premier segment peut ainsi recevoir l’étiquettespk_2dans le second. Fusionner des étiquettes techniques identiques provenant de requêtes distinctes sans vérification préalable fausserait l’attribution des propos. Chaque segment requiert une table de correspondance indépendante, validée face aux participants réels par une écoute ponctuelle.
Variantes de configuration selon les cas d’usage
Les paramètres de transcription sont configurés dans le champ transcription_config du dictionnaire generation_config. Voici les configurations de référence adaptées aux différents besoins opérationnels.
Pour un compte rendu de réunion fluide et normalisé, sans repères d’intervenants ni horodatages (adapté aux fichiers complets de moins de 60 minutes) :
generation_config = {
"transcription_config": {
"mode": "smart"
}
}
Pour les échanges articulés autour de noms de produits de niche ou de jargon propriétaire où l’orthographe exacte est prioritaire :
generation_config = {
"transcription_config": {
"custom_vocabulary": ["DataPulse", "CloudForge", "ClickHouse", "gRPC"]
}
}
Pour l’établissement de protocoles de réunion et de grilles temporelles de sous-titres (soumis à la limite de 30 minutes d’audio) :
generation_config = {
"transcription_config": {
"mode": {
"type": "verbatim",
"diarization_mode": "speaker",
"timestamp_granularities": ["word"],
}
}
}
Pipeline complet avec le SDK Python : traitement en deux parties
Ce script est exécuté avant toute écoute de l’audio ou vérification manuelle. Il téléverse les deux segments via la Files API, envoie les requêtes à l’Interactions API, extrait les annotations mot à mot, valide les horodatages et les identifiants d’intervenants, décale la chronologie de la seconde partie de 1500.0 secondes et génère des fichiers de travail préliminaires :
meeting_transcript.txt— un premier jet de transcription du dialogue en UTF-8, structuré par tours de parole ;word_timestamps.json— un tableau brut d’horodatages continus au niveau des mots, destiné au découpage des sous-titres.
Les fichiers générés par ce script constituent explicitement des ébauches non vérifiées, et non des documents finaux. L’opérateur doit écouter l’enregistrement, associer les jetons techniques d’intervenants aux voix réelles (speaker mapping), contrôler l’exactitude de la terminologie technique (terms) et vérifier les décalages temporels (time offsets). Après cet audit, il convient de mettre à jour les paramètres de configuration dans le code et de relancer le pipeline, ou d’éditer directement les fichiers texte générés. Les copies finales ne doivent être remises à un rédacteur de compte rendu ou à un monteur de sous-titres qu’à l’issue de ce protocole de vérification.
Le script produit des structures de données intermédiaires pour les analystes et les monteurs vidéo ; il ne génère pas automatiquement de liste de tâches ni de fichiers de sous-titres formatés en .srt. Les noms des intervenants et la limite de 1500.0 secondes sont spécifiés ici à titre de démonstration dans le cadre de ce scénario hypothétique.
import json
from google import genai
client = genai.Client()
audio_part1 = client.files.upload(file="meeting_part1.mp3")
audio_part2 = client.files.upload(file="meeting_part2.mp3")
transcription_mode_config = {
"transcription_config": {
"mode": {
"type": "verbatim",
"diarization_mode": "speaker",
"timestamp_granularities": ["word"],
}
}
}
interaction_part1 = client.interactions.create(
model="gemini-3.5-transcribe",
input=[
{
"type": "audio",
"uri": audio_part1.uri,
"mime_type": audio_part1.mime_type,
}
],
generation_config=transcription_mode_config,
)
interaction_part2 = client.interactions.create(
model="gemini-3.5-transcribe",
input=[
{
"type": "audio",
"uri": audio_part2.uri,
"mime_type": audio_part2.mime_type,
}
],
generation_config=transcription_mode_config,
)
def extract_word_annotations(interaction):
words = []
for step in getattr(interaction, "steps", []) or []:
for content in getattr(step, "content", []) or []:
for annotation in getattr(content, "annotations", []) or []:
if getattr(annotation, "type", None) == "word_info":
words.append(annotation)
return words
def parse_offset_seconds(offset_val, word_text):
if offset_val is None or offset_val == "":
raise ValueError(f"Отсутствует таймкод для слова '{word_text}'. Требуется проверка аудиозаписи.")
val_str = str(offset_val)
if val_str.endswith("s"):
val_str = val_str[:-1]
try:
return float(val_str)
except ValueError:
raise ValueError(f"Некорректный формат таймкода '{offset_val}' для слова '{word_text}'. Требуется проверка аудиозаписи.")
words_part1 = extract_word_annotations(interaction_part1)
words_part2 = extract_word_annotations(interaction_part2)
if not words_part1 or not words_part2:
raise ValueError("Один из аудиосегментов не содержит пословных аннотаций. Пустой результат не может считаться успешным.")
part1_offset_seconds = 0.0
part2_offset_seconds = 1500.0
manual_mapping_part1 = {
"spk_1": "Алексей",
"spk_2": "Михаил",
}
manual_mapping_part2 = {
"spk_1": "Михаил",
"spk_2": "Алексей",
}
unified_word_stream = []
for word in words_part1:
text = getattr(word, "text", "")
raw_speaker = getattr(word, "speaker", None)
if not raw_speaker or raw_speaker not in manual_mapping_part1:
raise ValueError(f"Неизвестный спикер '{raw_speaker}' в части 1. Требуется ручная верификация по аудио.")
resolved_speaker = manual_mapping_part1[raw_speaker]
word_start = parse_offset_seconds(getattr(word, "start_offset", None), text) + part1_offset_seconds
word_end = parse_offset_seconds(getattr(word, "end_offset", None), text) + part1_offset_seconds
unified_word_stream.append({
"text": text,
"speaker": resolved_speaker,
"start_seconds": word_start,
"end_seconds": word_end,
"part": 1,
})
for word in words_part2:
text = getattr(word, "text", "")
raw_speaker = getattr(word, "speaker", None)
if not raw_speaker or raw_speaker not in manual_mapping_part2:
raise ValueError(f"Неизвестный спикер '{raw_speaker}' в части 2. Требуется ручная верификация по аудио.")
resolved_speaker = manual_mapping_part2[raw_speaker]
word_start = parse_offset_seconds(getattr(word, "start_offset", None), text) + part2_offset_seconds
word_end = parse_offset_seconds(getattr(word, "end_offset", None), text) + part2_offset_seconds
unified_word_stream.append({
"text": text,
"speaker": resolved_speaker,
"start_seconds": word_start,
"end_seconds": word_end,
"part": 2,
})
dialogue_turns = []
current_turn = None
for item in unified_word_stream:
if current_turn is None or current_turn["speaker"] != item["speaker"] or current_turn["part"] != item["part"]:
if current_turn is not None:
dialogue_turns.append(current_turn)
current_turn = {
"part": item["part"],
"speaker": item["speaker"],
"start_seconds": item["start_seconds"],
"end_seconds": item["end_seconds"],
"words": [item["text"]],
}
else:
current_turn["end_seconds"] = item["end_seconds"]
current_turn["words"].append(item["text"])
if current_turn is not None:
dialogue_turns.append(current_turn)
def format_timestamp(seconds):
minutes = int(seconds // 60)
remaining_seconds = seconds % 60
return f"{minutes:02d}:{remaining_seconds:06.3f}"
with open("meeting_transcript.txt", "w", encoding="utf-8") as f_transcript:
for turn in dialogue_turns:
start_str = format_timestamp(turn["start_seconds"])
end_str = format_timestamp(turn["end_seconds"])
speech_text = " ".join(turn["words"])
f_transcript.write(f"[{start_str} - {end_str}] {turn['speaker']}: {speech_text}\n")
with open("word_timestamps.json", "w", encoding="utf-8") as f_json:
json.dump(unified_word_stream, f_json, ensure_ascii=False, indent=2)
Exemple illustratif de structure mot à mot et zones de contrôle
Voici une représentation synthétique du flux de données extrait lors d’une transition entre deux intervenants.
Note : Cet extrait sert exclusivement à illustrer la structure des objets retournés, et non de journal d’appel d’API réel. La qualité effective de la transcription dépend de l’acoustique, des microphones et de la clarté d’élocution.
[Строка 1] [spk_1] (0.100s -> 0.420s) Мы
[Строка 2] [spk_1] (0.450s -> 0.810s) переносим
[Строка 3] [spk_1] (0.830s -> 1.250s) ДатаПульс
[Строка 4] [spk_1] (1.300s -> 1.550s) на
[Строка 5] [spk_1] (1.600s -> 2.100s) CloudForge.
[Строка 6] [spk_1] (2.300s -> 2.600s) Да,
[Строка 7] [spk_2] (2.650s -> 2.900s) согласен,
[Строка 8] [spk_2] (2.950s -> 3.400s) э-э-э,
[Строка 9] [spk_2] (3.420s -> 3.900s) логично.
Points de contrôle critiques pour la révision manuelle :
- Association des étiquettes aux participants réels (Lignes 1–5 et 7–9) : Les identifiants
spk_1etspk_2ne sont que des jetons vocaux positionnels arbitraires. Un réviseur doit écouter les premiers instants de chaque segment pour déterminer les identités véritables : par exemple, vérifier que dans la Partie 1,spk_1correspond à Alexey etspk_2à Mikhail. - Passages de relais et brèves interjections (Ligne 6) : Le mot « Да, » est rattaché au tour de parole de
spk_1. Dans une conversation dynamique, il peut en réalité s’agir d’une marque d’acquiescement ou d’une rétroaction vocale émise par l’interlocuteur (spk_2). Les frontières d’alternance des intervenants exigent des vérifications sonores ciblées. - Transcription phonétique des marques non reconnues (Ligne 3) : Lorsque
custom_vocabularyest désactivé, les noms techniques anglophones peuvent être transcrits phonétiquement en caractères cyrilliques (par exempleДатаПульс). Le réviseur doit rectifier ces occurrences pour leur redonner leur graphie canonique :DataPulse. - Interdiction des remplacements automatiques globaux à l’aveugle : Les corrections terminologiques doivent systématiquement être appliquées au cas par cas selon le contexte de la phrase. Une commande « rechercher et remplacer » globale sur l’ensemble du document risquerait de dénaturer des mots courants, des expressions ou des citations littérales présentant des similitudes phonétiques.
- Hésitations et tics de langage (Ligne 8) : En mode
verbatim, les hésitations telles que « э-э-э » sont explicitement enregistrées. Dans un compte rendu rédigé propre, ces éléments sont nettoyés. En revanche, pour des pistes de sous-titres vidéo, leur minutage doit être préservé si le rythme d’affichage doit concorder avec l’articulation visible à l’écran.
Protocole de vérification ponctuelle avant transmission du matériel
Les données brutes générées par concaténation programmatique doivent faire l’objet d’un audit qualité rigoureux portant sur trois points de contrôle :
- Vérifier les intervenants et les limites des prises de parole : Écoutez 15 à 20 secondes d’audio sur 2 ou 3 transitions de tours de parole. Assurez-vous que des voix distinctes n’ont pas été fusionnées sous un même intervenant et que des monologues continus n’ont pas été fragmentés sous des étiquettes fantômes. D’après la documentation officielle, la diarisation pour les réunions réunissant trois personnes ou plus reste expérimentale et réclame une vigilance nettement accrue.
- Vérifier la terminologie, les valeurs numériques et les entités nommées :
Dressez une liste de contrôle ciblée des noms de projets clés (
DataPulse,CloudForge, numéros de versions, allocations budgétaires). Recherchez ces éléments dans le texte et confrontez directement les passages douteux à la piste audio, en évitant tout remplacement de masse inconsidéré. - Vérifier la continuité temporelle aux frontières des segments : Comparez la première minute de la Partie 1 avec la jonction vers la Partie 2 (immédiatement après la limite des 25:00 / 1500.0 secondes). Veillez à ce que les horodatages du second segment prolongent harmonieusement la chronologie au lieu d’être réinitialisés à zéro.
Transmission aux étapes suivantes et conditions d’arrêt du processus
Les fichiers meeting_transcript.txt et word_timestamps.json créés par le script sont produits en amont de toute révision auditive et doivent être traités strictement comme des versions de travail préliminaires. Ne les transmettez jamais dans leur état brut. Appliquez d’abord le protocole de vérification manuelle, harmonisez l’identité des intervenants, la terminologie et les décalages temporels avec l’enregistrement sonore, rectifiez les données (en mettant à jour les paramètres du code puis en relançant le script, ou en modifiant directement les fichiers texte), et ne livrez des copies validées aux équipes en aval qu’ensuite :
- Pour les rédacteurs de compte rendu ou les modèles de résumé (Note Taker / LLM Summarization) : Fournissez une copie vérifiée de la transcription de réunion — un document relu, assorti d’une attribution confirmée des intervenants et d’une terminologie technique normalisée. Ce document sert de socle à la rédaction de synthèses et de relevés de décisions, sans constituer pour autant une liste de points d’action immédiatement exploitable.
- Pour les monteurs vidéo ou spécialistes du sous-titrage (Caption Editor) : Fournissez une copie vérifiée du tableau des horodatages par mot — une séquence validée de mots associés à des repères temporels continus. Les règles typographiques aval (durée d’exposition à l’écran, longueur maximale de ligne, vitesse de lecture) dépendent de la plateforme vidéo et de la langue cibles, après quoi un outil de conversion dédié génère les fichiers de sous-titres définitifs en
.srtou.vtt.
Conditions d’arrêt du processus (Stop Conditions)
Interrompez le flux de travail et ne transmettez aucun fichier aux équipes en aval si l’une des conditions suivantes est vérifiée :
- Un fichier audio d’une durée supérieure à 30 minutes a été soumis pour diarisation ou horodatage par mot sans découpage préalable (ceci dépasse les limites documentées de l’API et ne doit pas être envoyé).
- Les fichiers préliminaires bruts (
meeting_transcript.txtouword_timestamps.json) ont été remis aux utilisateurs finaux directement après l’exécution du script, sans écoute ponctuelle ni révision manuelle. - Les étiquettes d’intervenants du second segment ont été mises en correspondance à l’aveugle d’après les numéros du premier segment sans vérification audio, ou des identifiants d’intervenants non résolus subsistent dans le jeu de données.
- La durée physique effective du premier segment n’a pas été additionnée à la chronologie du second segment, ou des horodatages de mots manquants sont détectés.
- Des règles de remplacement automatique global ont été appliquées à la terminologie sans validation contextuelle, ou des paramètres de configuration et données chiffrées critiques n’ont pas été vérifiés par rapport à l’enregistrement.