• 0238494791
  • spgoo.ecpy@gmail.com

Dictionnaire phonétique du français et de ses variations — Gabriel Bergounioux

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).

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.

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.

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

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