Des mots prononcés au texte propre : comment fonctionne la normalisation textuelle inverse
Les modèles de reconnaissance vocale produisent des mots. Mais lorsque vous dictez "la réunion a lieu le quinze janvier à quatorze heures trente et le budget est de trois mille dollars", vous ne voulez pas voir ces mots exacts. Vous voulez : "La réunion a lieu le 15 janvier à 14:30 et le budget est de 3 000 $."
La transformation de la forme parlée vers la forme écrite s'appelle la normalisation textuelle inverse, ou ITN. C'est l'inverse de ce que fait un système de synthèse vocale (qui convertit le texte écrit en forme parlée). Et c'est l'une de ces fonctionnalités invisibles quand elles marchent, mais exaspérantes quand elles ratent.
Ce que couvre l'ITN
L'ITN gère un éventail de transformations plus large qu'on ne le réalise généralement :
- Nombres. "quarante-deux" → "42", "trois virgule quatorze" → "3,14", "moins sept" → "-7"
- Devises. "trois mille dollars" → "3 000 $", "cinquante euros" → "50 €"
- Dates et heures. "quinze janvier deux mille vingt-six" → "15 janvier 2026", "deux heures trente de l'après-midi" → "14:30"
- Ordinaux. "le troisième élément" → "le 3e élément"
- Unités. "cinq kilomètres" → "5 km", "vingt degrés Celsius" → "20°C"
- Ponctuation. "virgule" → ",", "point" → ".", "point d'interrogation" → "?"
- Commandes vocales. "nouvelle ligne" → vrai retour à la ligne, "deux-points" → ":"
Chacune de ces transformations paraît simple isolément. La complexité vient de l'ambiguïté. Est-ce que "un" désigne le nombre 1, ou l'article ? Est-ce que "mai" désigne le mois, ou une forme verbale ? Est-ce que "tiret" veut dire un trait d'union, ou le mot "tiret" ?
Pourquoi nous avons construit notre propre moteur
La plupart des fournisseurs ASR incluent un ITN de base dans leur pipeline cloud. Mais si vous faites du traitement local, il vous faut un ITN local également — et les options sont limitées. Les bibliothèques open source existantes sont généralement basées sur Python, conçues pour du traitement batch et principalement centrées sur l'anglais.
Nous avions besoin de quelque chose de différent :
- Des performances temps réel. L'ITN s'exécute sur chaque segment de transcription en streaming. Il doit traiter du texte en microsecondes, pas en millisecondes.
- La prise en charge CJK. Le chinois et le japonais ont des systèmes numériques, des conventions de ponctuation et des règles de formatage totalement différents. "三千美元" doit devenir "3 000 $" au même titre que "three thousand dollars".
- Une intégration native. Il nous faut une bibliothèque qui tourne dans une app macOS Swift sans embarquer un runtime Python ni passer par un sous-processus.
Transducteurs à états finis
Notre moteur ITN repose sur des transducteurs à états finis, ou FST. Un FST est une machine à états qui lit une séquence d'entrée et produit une séquence de sortie. Pour l'ITN, l'entrée est une séquence de mots prononcés et la sortie est leur forme écrite normalisée.
L'avantage clé des FST par rapport aux regex ou aux remplacements de chaînes basés sur des règles est la composabilité. Vous pouvez créer de petits FST pour des transformations individuelles — un pour les nombres cardinaux, un pour les dates, un pour les devises — puis les composer en un seul transducteur qui gère tous les cas simultanément, avec une priorité déterministe lorsque les règles se chevauchent.
Nous avons écrit la bibliothèque runtime des FST, libfst, en Zig. Zig nous apporte plusieurs choses importantes pour ce cas d'usage : compatibilité ABI C (afin que la bibliothèque se lie directement à l'app Swift), abstractions à coût nul pour les transitions de la machine à états et contrôle précis de l'allocation mémoire — pas de pauses de garbage collector au milieu d'un traitement texte temps réel.
Le pipeline de compilation des règles
Les règles ITN sont rédigées en Python comme spécifications de transformation déclaratives. Chaque règle décrit un motif (les mots en entrée) et un remplacement (le texte de sortie). La chaîne d'outils Python compile ces règles en fichiers FST binaires — des représentations compactes et optimisées que le runtime Zig charge et exécute.
Cette séparation nous permet d'itérer rapidement sur les règles — Python est excellent pour exprimer des motifs linguistiques — tout en gardant un runtime rapide. Ajouter un nouveau format numérique ou un symbole monétaire revient à modifier un fichier de règles Python puis à recompiler. Le binaire runtime, lui, ne change pas.
Actuellement, nous distribuons des fichiers de règles FST compilés pour le chinois, le japonais et l'anglais. Chaque langue a son propre ensemble de règles, car les conventions de normalisation diffèrent fortement. Le japonais utilise une ponctuation pleine chasse et des mots compteurs différents. Les nombres chinois suivent une logique de groupage en base 10 000 plutôt qu'en base 1 000. L'anglais a ses propres particularités pour les ordinaux et l'heure sur douze heures.
Commandes vocales
L'ITN gère aussi les commandes vocales — des expressions parlées qui se mappent à des actions clavier plutôt qu'à du texte littéral. Lorsque vous dites "nouvelle ligne" pendant une dictée, vous voulez un véritable saut de ligne, pas les mots "nouvelle ligne". Lorsque vous dites "virgule", vous voulez le signe de ponctuation.
Cela crée un défi intéressant de désambiguïsation. Le moteur ITN doit déterminer si "nouvelle ligne" est une commande vocale ou fait partie d'une phrase comme "c'est une nouvelle ligne de produits". Nous gérons cela par le contexte : les commandes vocales sont reconnues à des positions syntaxiques spécifiques (généralement après une pause ou en frontière de proposition), et l'ordre de priorité du FST fait en sorte que l'interprétation en commande soit privilégiée dans les positions ambiguës.
Pour les langues CJK, les commandes vocales sont localisées. Les utilisateurs chinois disent "换行" pour un saut de ligne et "逗号" pour une virgule. Les règles FST sont spécifiques à la langue, donc chaque locale possède son propre vocabulaire naturel de commandes.
La fonctionnalité invisible
Un bon ITN est invisible. Vous dictez naturellement et le texte a l'air juste. Les nombres sont des nombres, les dates sont des dates, la ponctuation est là où elle doit être. Dès que vous devez corriger à la main un "trois mille dollars" littéral ou supprimer les mots "nouvelle ligne" du texte, l'illusion se brise.
Nous avons investi un effort d'ingénierie important dans une fonctionnalité que personne ne remarque lorsqu'elle fonctionne parfaitement. C'est précisément le but. La meilleure expérience de saisie vocale est celle où vous oubliez que vous n'êtes pas en train de taper.
Essayez OnType — la saisie vocale sur l'appareil avec normalisation intelligente du texte pour l'anglais, le chinois et le japonais.