Dictionnaire phonétique du français et de ses variations — Gabriel Bergounioux
Appui SPGoO : Yvan Stroppa
Construction d’une plateforme nommée passy sur la base de la réalisation effectuée pour MP Tours (DeepBdd-Bddictionnairique) dans un contexte de langue française. Ce travail est réalisé en collaboration avec G. Bergounioux et avec la participation de l’ATILF (Nancy).
Objectif : concevoir une plateforme Web d’alimentation, de collecte et d’exploitation de données phonétiques.
Importation des données du TLF
Première étape: récupération des données du TLF de l’ATILF pour constituer la base de départ de notre corpus phonétique soit 54734 entrées.

Création d’un Workflow :

Elaboration d’un workflow de traitements pour permettre à la plateforme d’avoir un côté communautaire, on envisage dès le départ une saisie multiple par des utilisateurs de type contributeur. Ce qui permettra d’avoir, vu le chantier, des forces vives pour alimenter et corriger les entrées. Dans ce circuit d’alimentation deux voies sont prévues : une alimentation manuelle et une alimentation automatique.
Alimentation manuelle : réservée aux contributeurs, elle permettra à des utilisateurs spécifiques de proposer des corrections et ajouts des données à partir d’une interface dédiée. Un environnement
Alimentation automatique : déclenchée par le Backend de la plateforme pour l’extraction de corpus sonores. cet agent IA devra en permanence sonder des corpus existants et des fonds sonores publics pour en extraire des séquences et les proposer à la plateforme.
Pour ces deux circuits d’alimentation nous mettons en place un Workflow qui aura pour objectif de valider les propositions des contributeurs et de la partie IA afin de garantir une grande qualité des données mises à la disposition des utilisateurs.
Extraction des données ESLO2 :
Constitution et extraction des entrées fournies par ESLO2 : le corpus nous permet d’extraire à partir des transcriptions C des enregistrements des illustrations sonores très variées des mots et de leur prononciation.
Création d’un script python pour extraire des fichiers de transcriptions les différentes informations.
Préparation de l’environnement pour les extractions: Installation des packages suivants pour faciliter et interpréter les données extraites dans un environnement python3.12
pip3 install spacy nlp nltk
python -m spacy download fr_core_news.sm
pip install git+https://github.com/ClaudeCoulombe/FrenchLeffLemmatizer.git
Ces différents package vont nous permettre d’obtenir directement la lemmatisation des mots pour constituer un lexique et la morpho-syntaxe des expressions extraites le tout enregistrer dans deux collections de notre base de données MongoDB : eslo2 et lexique_eslo2
Retour expérience du parser XML : import xml.etree.ElementTree as ET
1 / Ce package entre les versions 3.9 et 3.12 de python a évolué et l’emploi de getChildren pour trouver les enfants d’une branche de la structure XML n’est plus accessible dans les dernières versions.
2 / Interprétation des blocs à l’aide du parser.
Bloc classique :
<Turn speaker="spk1" startTime="403.994" endTime="407.699">
<Sync time="403.994"/>
oui mais je me suis excusé c'est bon là
<Sync time="406.048"/>
j'ai pas fait exprès
</Turn>
Bloc spécifique :
<Turn startTime="0" endTime="120.852" speaker="spk1">
<Sync time="0"/>
<Sync time="0.586"/>
<Event desc="rire" type="noise" extent="instantaneous"/>
<Sync time="1.409"/>
c'est moi
<Sync time="2.462"/>
<Sync time="120.295"/>
ça va ?
</Turn>
Attention aux lignes vides, lors de la recomposition du bloc, elles ne sont pas interprétées par le parser. Si on reconstitue ce bloc de la manière suivante ….<Sync time=”0″/><Sync time=”0.586″/><Event desc=”rire” type=”noise” extent=”instantaneous”/>…
le parser ne distingue pas les éléments intermédiaires et repositionne mal les groupes de mots. D’où l’ajout systématique d’une chaîne de caractères que l’on pourra distinguer et filtrer par la suite ….<Sync time=”0″/>YS<Sync time=”0.586″/>YS
Résultats de l’extraction à partir de 511 fichiers TRS des enregistrements d’ESLO2 :
62802 Blocs multi-speakers non interprétés
338951 Documents générés dans MongoDB pour les groupes de souffle
40753 entrées différentes ajoutées dans la lexique Eslo2.
Extraction des données ESLO 1 :
Résultats de l’extraction à partir de 346 fichiers TRS des enregistrements d’ESLO1 :
39265 Blocs multi-speakers non interprétés
400633 Documents générés dans MongoDB pour les groupes de souffle
38855 entrées différentes ajoutées dans la lexique Eslo1.
Restrictions:
Nous faisons le choix dans le traitement des transcriptions de ne pas prendre en compte les blocs multi-speakers pour éviter de la confusion et afin d’avoir des enregistrements clairs et précis.
Exemple de bloc multi-speakers
<Turn speaker="spk5 spk1" startTime="407.699" endTime="410.971">
<Sync time="407.699"/>
<Who nb="1"/>
bon tu es tu es
<Event desc="pi" type="pronounce" extent="instantaneous"/>
parce que c'est
<Event desc="rire" type="noise" extent="instantaneous"/>
<Who nb="2"/>
<Event desc="rire" type="noise" extent="instantaneous"/>
<Sync time="410.086"/>
<Who nb="1"/>
<Who nb="2"/>
</Turn>
On peut constater que dans ce découpage les éléments ne sont pas assez précis et n’apportent pas d’informations supplémentaires pour notre plateforme passy, qui met en avant l’écoute et la prononciation des mots par un seul locuteur.
Détail du code pour l’extraction
def traite_bloc(bb,speakers,fichier):
"""
Traitement du bloc Turn pour en extraire les éléments
"""
global nb_speakers_multiple, liste_mots
tree = ET.ElementTree(ET.fromstring(bb))
root=tree.getroot()
Turn=root.attrib
# on regarde si plusieurs speakers
if "speaker" not in Turn:
print("pas de speaker dans le bloc")
return
tab_speakers=Turn["speaker"].split(" ")
D_bloc_recompose={}
if len(tab_speakers)<2 :
txt_complet=""
textes=[]
debut=Turn["startTime"]
ref_end=Turn["endTime"]
#on parcourt les deux listes en même temps
for indice,txt in zip(list(root), root.itertext()):
if "time" in indice.attrib : #<Sync time="407.699"/>
ref_debut= indice.attrib['time']
if debut!=ref_debut:
textes.append({"debut":debut, "fin":ref_debut,"texte":txt_complet.strip()})
debut=ref_debut
txt_complet=txt
#pour le dernier
textes.append({"debut":debut, "fin":ref_end,"texte":txt_complet.strip()})
for texte in textes:
D_bloc_recompose={}
if texte["texte"]!="" and texte["texte"]!="YS" :
mot_propre=texte["texte"].replace("'"," ").replace("?"," ")
tab_res = re.split('\s+', mot_propre)
for mot in tab_res:
if mot in liste_mots:
liste_mots[mot]+=1
else:
liste_mots[mot]=1
D_bloc_recompose["enreg"]=fichier
D_bloc_recompose["locuteur"]=speakers[Turn["speaker"]]["name"]
D_bloc_recompose["texte"]=texte["texte"]
D_bloc_recompose["morpho"]=[{y:x} for x,y in return_POS(texte["texte"])]
D_bloc_recompose["debut"]=texte["debut"]
D_bloc_recompose["fin"]=texte["fin"]
# on enregistre la structure directement dans MongoDB
mycol.insert_one(D_bloc_recompose)
else :
nb_speakers_multiple+=1