Commit 48bea1a5 authored by Morgane Pica's avatar Morgane Pica
Browse files

init dossier tableaux avec readme

parent cd029a59
Loading
Loading
Loading
Loading
+64 −0
Changes for correction-par-tableaux/readme.md: 64 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Correction du texte sur M.O.Excel/L.O.Calc
--------------
#### Présentation :
* Pour **faciliter les opérations de correction des textes**, nous avons produit des tableaux permettant de travailer en-dehors du XML. Ces tableaux ont été écrits par un script Python disponible dans ce même dossier (`tableaux_a_modifier.ipynb`) et exécutable via Jupyter Notebook.
* Nos tableaux comportent deux types d'objets, à raison d'un par ligne : a) les **tokens** (mots, ponctuation...) et b) les **sauts de ligne** avec leur att.facs contenant le numéro de facsimilé, pour permettre un retour à l'image en cas de besoin.
* Un tableau comprend nombre de colonnes destinées à faciliter l'utilisation ou typer précisément les corrections effectuées.

#### Ce que permettent ces tableaux :
* De **séparer** repérage des tokens problématiques et correction à proprement parler en permettant de marquer des tokens comme "à corriger".
* De **garder trace** des tokens déjà traités en les marquant comme "corrigés".
* La correction des **lemmes** (en réécrivant directement dans la colonne "lemme").
* La correction des **POS** (en réécrivant directement dans la colonne "pos").
* De signaler des **tokens mal tokenisés**.
* De **trier** les tokens par forme/lemme/POS/à corriger pour traiter des cas semblables ensemble, puis de remettre tout le tableau dans l'ordre original ensuite (en utilisant la fonction de tri sur Excel ou Calc).

#### Ce que ne permettent pas ces tableaux :
* La correction des **formes mal transcrites**. Dans ce cas, on peut noter les corrections à faire mais ces corrections devront être faites directement dans le XML.
* La **re-tokenisation elle-même** lorsque des tokens sont mal tokenisés : on peut marquer un token comme "à scinder" ou "à fusionner", mais l'action elle-même devra être faite directement dans le XML.
-----------------

#### Les différentes colonnes et comment les utiliser :
###### -> n° de ligne
Cette colonne numérote les éléments en fonction de leur ordre dans le fil du texte, quelle que soit leur numérotation dans le document et quelle que soit leur nature (`<w>` ou `<lb>`). C'est grâce à elle que le document peut être remis dans l'ordre du texte (via la fonction de tri Excel/Calc), après un tri par forme/pos/lemme.

###### -> nature
Cette colonne répertorie la nature de l'élément représenté dans la ligne (`<w>` ou `<lb>`). Elle est destinée à la fois à l'utilisateurice et à la machine pour pouvoir ignorer facilement les lignes de `<lb>` qui par définition ne porteront pas de corrections.

###### -> n°/id
* Si l'élément de cette ligne est un `<w>`, la colonne portera sa numérotation dans le document, afin de permettre l'application automatique des éventuelles corrections enregistrées pour le token.
* Si l'élément de cette ligne est un `<lb>`, la colonne portera son attribut facs. Cette information contient le numéro de la page dont proviennent les tokens suivant le `<lb>`. Ce numéro permet donc à l'utilisateurice, en cas de token mal transcrit, de savoir quelle page regarder pour corriger le token. Attention, le numéro de page correspond à la numérotation des images du témoin par Transkribus, et non au numéro de la page tel qu'imprimé sur l'original.

###### -> forme "diplo"
Colonne pouvant être vide.
Si le token comprend une modernisation/correction d'aucun type (un élément `<choice>`, quels que soient ses enfants), la colonne contiendra du texte, et ce texte sera différent de la colonne suivante. S'il n'y a pas de modernisation/correction, la colonne sera vide.

###### -> forme modernisée
Cette colonne contient le mot-forme, lorsqu'il ne comporte pas de modernisations/corrections, ou bien sa forme corrigée/modernisée lorsqu'il en comporte.

###### -> forme corrigée
Cette colonne sert à enregistrer d'éventuelles corrections sur le mot-forme, indistinctement de la version du mot corrigée. La correction ne sera pas automatiquement appliquée au XML, mais sera transférée en commentaire XML dans le token, charge à l'utilisateurice de modifier le XML. Si le token doit être corrigé et a deux versions ("diplo" et "modernisée"), nous suggérons à l'utilisateurice d'écrire dans la colonne "forme corrigée" d'abord la forme "diplo", même si elle ne change pas, puis une espace, puis la forme "modernisée", même si elle ne change pas. Cela permettra une comparaison visuelle efficace avec le token d'origine à l'intérieur du XML.

###### -> lemme
Cette colonne contient la valeur de l'attribut att.lemma du token. Elle peut être corrigée directement dans cette colonne si besoin.

###### -> pos
Cette colonne contient la valeur de l'attribut att.pos du token. Elle peut être corrigée directement dans cette colonne si besoin.

###### -> à scinder
Cette colonne sert à signaler par un X les tokens mal tokenisés devant être scindés. Ce type de changement ne pouvant être automatiquement appliqués au XML, elle sera transférée en commentaire XML dans le token, charge à l'utilisateurice de modifier le XML.

###### -> à fusionner avec le w n°
Cette colonne sert à signaler les tokens mal tokenisés devant être fusionnés. Ce type de changement ne pouvant être automatiquement appliqués au XML, elle sera transférée en commentaire XML dans le token, charge à l'utilisateurice de modifier le XML.

###### -> à corriger
Cette colonne sert à marquer les tokens identifiés comme à corriger par un X. Les tokens ambigus (avec plusieurs POS possibles) et inconnus du dictionnaire utilisé à la lemmatisation sont d'emblée marqués par le script produisant les tableaux. La colonne peut aussi être marquée manuellement par l'utilisateurice pour fractionner son travail.

###### -> corrigé
Cette colonne sert à marqué un token comme traité par l'utilisateurice. **Il est impératif de bien penser à marquer un X dans sa colonne pour chaque token traité, car sinon les corrections ne seront pas vues par le script de resynchronisation.**

---------------------
#### Que faire lorsqu'on a un tableau à resynchroniser
La synchronisation de vos corrections nécessite l'exécution du script Python `resync-corrections-tableaux.ipynb`. Si vous n'êtes pas à l'aise avec Python, vous pouvez utiliser GitHub pour communiquer avec l'équipe de ConDÉ ou bien écrire un mail à Pierre Larrivée, porteur du projet.
Si vous êtes à l'aise avec Python et Jupyter Notebook, le script vous permet de faire une resynchronisation locale.
Si vous êtes également à l'aise avec le XML, vous pouvez repérer les commentaires contenus dans des éléments `<w>` pour faire les éventuelles retokénisations ou corrections de mots-formes que vous aviez repérées. Vous pourrez ensuite contacter l'équipe ConDÉ sur GitHub ou écrire un mail à Pierre Larrivée pour proposer vos corrections.
 No newline at end of file
+275 −0
Changes for correction-par-tableaux/tableaux_a_modifier.ipynb: 275 added lines, 0 removed lines.
Original line number Diff line number Diff line
%% Cell type:code id: tags:

``` python
import xml.etree.ElementTree as ET
import csv


# Pour que Python comprenne les éléments dont on parlera,
# il faut lui donner la déclaration TEI, mais comme c'est
# le NS de base, pas besoin de lui donner un préfixe.
ET.register_namespace('', "http://www.tei-c.org/ns/1.0")
```

%% Cell type:code id: tags:

``` python
def get_w_txt(word):

    amorig = ''
    expmod = ''

    # S'il y a du texte avant le premier enfant, on l'ajoute.
    if word.text:

        amorig += word.text
        expmod += word.text

    # On boucle sur les enfants du <w> actuel.
    for item in word:

        checklist = [
            '{http://www.tei-c.org/ns/1.0}height',
            '{http://www.tei-c.org/ns/1.0}supplied',
            '{http://www.tei-c.org/ns/1.0}c',
            '{http://www.tei-c.org/ns/1.0}hi'
        ]

        if item.tag in checklist:
            amorig += item.text
            expmod += item.text
            if item.tail:
                amorig += item.tail
                expmod += item.tail

        elif item.tag == '{http://www.tei-c.org/ns/1.0}lb':
            if item.tail:
                amorig += item.tail
                expmod += item.tail

        elif item.tag == '{http://www.tei-c.org/ns/1.0}choice':

            for subitem in item.findall('./*'):
                if subitem.tag == '{http://www.tei-c.org/ns/1.0}am' or subitem.tag == '{http://www.tei-c.org/ns/1.0}orig':
                    amorig += subitem.text

                elif subitem.tag == '{http://www.tei-c.org/ns/1.0}expan' or subitem.tag == '{http://www.tei-c.org/ns/1.0}reg':
                    try:
                        expmod += subitem.text
                    except:
                        "ALERTE !!"

            if item.tail:
                amorig += item.tail
                expmod += item.tail


        elif item.tag == '{http://www.tei-c.org/ns/1.0}add':
            # On refait tous les tests.
            for subitem in item:

            # Si l'enfant est un <height>, on récupère son texte.
                if subitem.tag in checklist:
                    amorig += subitem.text
                    expmod += subitem.text
                    if item.tail:
                        amorig += subitem.tail
                        expmod += subitem.tail

                elif subitem.tag == '{http://www.tei-c.org/ns/1.0}lb':
                    if subitem.tail:
                        amorig += subitem.tail
                        expmod += subitem.tail

                # Si l'enfant est un <choice>, on récupère le texte de son
                # second enfant et on vérifie s'il y a du texte après le <choice>.
                elif subitem.tag == '{http://www.tei-c.org/ns/1.0}choice':

                    for subsub in subitem.findall('./*'):
                        if subsub.tag == '{http://www.tei-c.org/ns/1.0}am' or subsub.tag == '{http://www.tei-c.org/ns/1.0}orig':
                            amorig += subsub.text

                        elif subsub.tag == '{http://www.tei-c.org/ns/1.0}expan' or subsub.tag == '{http://www.tei-c.org/ns/1.0}reg':
                            expmod += subsub.text

                            if subitem.tail:
                                amorig += subitem.tail
                                expmod += subitem.tail

    if amorig != expmod:
        texte = [amorig, expmod]
    else:
        texte = ['', expmod]

    return texte
```

%% Cell type:code id: tags:

``` python
#Revue le 15 avril. Options pour fichier déjà lemmatisé ajoutées.

def export_tokens_to_csv(chemin_entree, chemin_sortie):

    """
    Fonction récupérant les éléments <w> d'un fichier XML-TEI
    avec leurs @n pour les exporter dans un fichier CSV à
    deux colonnes, l'une pour le numéro, l'autre pour le texte.
    Si l'élément <w> comporte des enfants <height> pour les initiales
    hautes, ou <choice> pour des modernisations/abréviations,
    la fonction compilera une version complète, résolue et modernisée
    pour le logiiel Analog.

    :param chemin_entree: Le chemin local vers un fichier en XML-TEI
        dont on souhaite extraire les tokens pour Analog.
    :param chemin_sortie: L'emplacement local dans lequel on souhaite
        écrire le fichier CSV à donner à Analog.
    """

    l_count = 0

    lbinitlist = []
    winitdict = {}

    # Le dictionnaire dans lequel seront stockés les tokens avant écriture en CSV.
    colonnes = [
        'n° de ligne',
        'nature',
        'n°/id',
        'forme "diplo"',
        'forme modernisée',
        'forme corrigée',
        'lemme',
        'pos',
        'à scinder',
        'à fusionner avec w n°',
        'à corriger',
        'corrigé'
    ]

    with open(chemin_entree) as infile:

        # On va chercher le fichier XML-TEI et on le lit.
        tree = ET.parse(infile)
        root = tree.getroot()

        for parent in root.findall('.//*[{http://www.tei-c.org/ns/1.0}w]'):
            for child in parent.findall('./*'):
                if child.tag == '{http://www.tei-c.org/ns/1.0}w':
                    lbinitlist.append(child.get('n'))
                elif child.tag == '{http://www.tei-c.org/ns/1.0}lb':
                    lbinitlist.append(child.get('facs'))

        for word in root.findall('.//{http://www.tei-c.org/ns/1.0}w'):
            texte = ''
            numero = str(word.get('n'))
            lemmes = str(word.get('lemma'))
            pos = str(word.get('pos'))

            winitdict[numero] = {'lemma':lemmes, 'pos':pos}

            if word.find('{http://www.tei-c.org/ns/1.0}lb'):
                winitdict[numero]['lb'] = word.find('{http://www.tei-c.org/ns/1.0}lb').get('facs')
            else:
                wIndex = lbinitlist.index(numero)
                try:
                    nextIndex = lbinitlist[wIndex+1]
                except:
                    nextIndex = ''
                if "_"in nextIndex:
                    winitdict[numero]['lb'] = nextIndex
                else:
                    winitdict[numero]['lb'] = 'None'

            if word.find('./*') == None :
                winitdict[numero]['original'] = ''
                winitdict[numero]['modernisé'] = word.text

            else:
                winitdict[numero]['original'] = get_w_txt(word)[0]
                winitdict[numero]['modernisé'] = get_w_txt(word)[1]

    # On ouvre le CSV de sortie en mode "écriture", on y écrit le nom des colonnes.
    with open(chemin_sortie, 'w') as csv_file:
        csv_contenu = csv.DictWriter(csv_file, fieldnames = colonnes)
        csv_contenu.writeheader()

        # On boucle sur les éléments <w> du XML, dans l'ordre du fichier.
        # for word in root.findall('.//{http://www.tei-c.org/ns/1.0}w'):
        for word in winitdict.keys():

            dicolocal = winitdict[word]

            l_count += 1

            if '|' in dicolocal['pos'] or dicolocal['pos'] == 'Inconnu':
                a_corriger = 'X'
            else:
                a_corriger = ''


            if dicolocal['lb'] != 'None':
                csv_contenu.writerow({
                    'n° de ligne' : str(l_count),
                    'nature' : 'saut de ligne',
                    'n°/id' : dicolocal['lb'],
                    'forme "diplo"' :'',
                    'forme modernisée':'',
                    'forme corrigée':'',
                    'lemme' :'',
                    'pos' :'',
                    'à scinder' :'',
                    'à fusionner avec w n°' :'',
                    'à corriger' :'',
                    'corrigé' :''
                })

                l_count += 1

                csv_contenu.writerow({
                    'n° de ligne' : str(l_count),
                    'nature' : 'w',
                    'n°/id' : word,
                    'forme "diplo"' : dicolocal['original'],
                    'forme modernisée' : dicolocal['modernisé'],
                    'forme corrigée':'',
                    'lemme' : dicolocal['lemma'],
                    'pos' : dicolocal['pos'],
                    'à scinder' :'',
                    'à fusionner avec w n°' :'',
                    'à corriger' : a_corriger,
                    'corrigé' :''
                })

            else:

                csv_contenu.writerow({
                    'n° de ligne' : str(l_count),
                    'nature' : 'w',
                    'n°/id' : word,
                    'forme "diplo"' : dicolocal['original'],
                    'forme modernisée' : dicolocal['modernisé'],
                    'forme corrigée':'',
                    'lemme' : dicolocal['lemma'],
                    'pos' : dicolocal['pos'],
                    'à scinder' :'',
                    'à fusionner avec w n°' :'',
                    'à corriger' : a_corriger,
                    'corrigé' :''
                })
```

%% Cell type:code id: tags:

``` python
temoins = ['basnage','berault','gc','institutions','merville','morisse','pesnelle','rouille','ruines','tac','terrien']

for temoin in temoins:
    export_tokens_to_csv('/home/erminea/Documents/CONDE/editions/base-version/' + temoin + '_base.xml',
                 temoin + '_tableau_pour_corrections.csv')
    print(temoin + " : terminé")
```

%% Output

    basnage : terminé