Skip to main content

Morfologia delle trascrizioni, parte III: il primo script

Timecode à la carte
Timecode à la carte

ShareTIGR

16/05/2024

In contributi precedenti è stata questione di trascrizioni in formato testo adatte all'uso al di fuori di un ambiente multimediale integrato e dell'idea di corredarle di un numero limitato di indicazioni temporali, così da facilitare la messa in relazione con documenti audio/video senza compromettere la leggibilità della trascrizione. Per raggiungere quest'ultimo scopo, poiché le funzioni di esportazione dall'annotatre ELAN in formato txt non offrono opzioni del genere, è stato necessario scrivere un apposito programma, con alcune conseguenze anche sulle fasi successive di elaborazione delle trascrizioni.

Il programma si chiama timecode_at_intervals e il linguaggio che ho scelto per scriverlo è Python. Avevo letto qua e là di linguisti e linguiste che usavano Python e avevo capito che era facilmente integrabile con pacchetti di codice pronti all'uso per il Natural Language Processing NLP. Sembrava anche presentare certe somiglianze con php, un altro linguaggio che mi era capitato di usare per gestire template di pagine web in Wordpress. E poi... esistono ottimi manuali online e applicazioni coinvolgenti per il cellulare che permettono di imparare da zero le basi di Python.

Per risolvere il problema del timecode, oltre al codice Python in sé, un ingrediente indispensabile - e utile a trattare tanti altri problemi di elaborazione dei testi - sono le cosiddette espressioni regolari (in breve RegEx, dall'inglese Regular Expressions). Chi ha già interrogato un corpus linguistico probabilmente le conosce: è un insieme di segni e di regole sintattiche che servono a trovare determinate stringhe di caratteri in un testo. Nel nostro caso, una espressione regolare importante è, per esempio, quella che trova tutte le istanze di timecode. Nello script ho usato "\d\d:\d\d:\d\d\.\d{3}": due cifre (\d) seguite da due punti, altre due cifre e due punti, altre due cifre, un punto e, infine, tre cifre. Avrei anche potuto usare "\d{2}:\d{2}:\d{2}.\d{3}", ricorrendo in modo sistematico alle parentesi graffe per indicare il numero di occorrenze di un segno che le precede, in questo caso \d 'cifra'. Comunque, la sequenza definita da quelle espressioni corrisponde al formato del timecode in ELAN, che indica - in cifre - ore, minuti, secondi e millesimi di secondi.

Adoperando Python e il modulo RegEx di Python, lo script esegue i seguenti compiti, semplificando un poco (e se i dettagli non interessano, si salti pure questa parte nella lettura):

(a) Chiede all'utente di digitare il nome e il percorso di un documento txt esportato da ELAN con il timecode e, in base a questo input, legge il documento, salva localmente il testo sotto forma di lista di righe e chiude il documento.

(b) Chiede all'utente di specificare un intervallo in secondi e memorizza quel valore.

(c) Il documento esportato da ELAN elenca in ordine cronologico ogni segmento annotato, seguito da una riga con le indicazioni dei suoi momenti iniziale e finale. Lo script reperisce tutti i timecode iniziali e li mette in una lista. C'è da aggiungere che in questo processo abbiamo voluto saltare i codici che si riferiscono a segmenti contenenti la parentesi quadra "[", che segnala l'inizio di un discorso pronunciato in sovrapposizione con un altro. Per delle ragioni sulle quali torneremo più avanti in questo blog, questo provvedimento riduce il rischio di includere timecode che si riferisce a un punto all'interno di una parola.

(d) Lo script converte in secondi i timecode ritenuti, registra il primo timecode in una seconda lista - chiamiamola la lista filtrata - e assegna il suo valore a un contatore. Percorre in seguito la lista originale fino a raggiungere un timecode la cui distanza dal contatore supera l'intervallo definito. Inserisce quel timecode nella lista filtrata, aumenta il contatore del valore dell'intervallo e ripete la procedura fino a raggiungere la fine della lista di partenza.

(e) Torna allora al documento, paragona ogni timecode a inizio riga con quelli della lista filtrata e cancella le righe i cui timecode iniziali non figurano nella lista.

(f) Nelle righe di timecode ritenute, elimina i timecode finali e aggiunge l'etichetta "--TIMECODE--" all'inizio della riga, nella stessa posizione dove, nelle righe che contengono discorso, si trova il nome del/la parlante. I trattini servono a segnalare all'occhio umano il carattere specifico dell'indicazione, per non confonderla visivamente con i nomi dei/lle parlanti.

(g) Nelle righe di discorso che precedono il timecode e alle quali esso si riferisce, lo script colloca la marca "((TC))" all'inizio del segmento. In quel momento torna utile aver evitato - durante la procedura (c) descritta sopra - i segmenti che con una certa probabilità iniziano all'interno di una parola: infatti una marca "((TC))" all'interno di una parola si legge male.

(h) Infine lo script salva il testo modificato in un nuovo documento, aggiungendo " _tcfltrd" al nome del documento.

Come si vede nel video di questa settimana, lo script va chiamato dalla linea di comando del computer, un'applicazione di base con la quale più membri del team, tra i quali io stessa, non avevamo particolare familiarità prima di ShareTIGR. Abbiamo perciò scritto delle istruzioni che guidano passo per passo l'uso di timecode_at_intervals e degli script successivi, con qualche spiegazione sul perché di certe scelte. Le singole operazioni eseguite dallo script sono inoltre descritte all'interno dello stesso, in commenti che precedono i passi di codice eseguibile sui quali portano. Istruzioni e commenti formano una documentazione fondamentale come pro memoria, per lavorare in un team e in generale per descrivere un flusso di lavoro, come in questo blog o in una pubblicazione scientifica.

Dopo molti fallimenti e aggiustamenti, lo script funziona attualmente bene tranne in un caso, che abbiamo notato applicandolo alla trascrizione di un'interazione in classe che contiene lunghi momenti di silenzio. Quando la durata di un silenzio è maggiore dell'intervallo definito - nel nostro caso 10 secondi - il programma nella sua versione attuale si comporta in modo indesiderato e il documento risultante deve essere corretto a mano, eliminando alcuni timecode superflui. Ma abbiamo identificato la causa del problema e quindi dovremmo essere in grado di correggere l'errore!

Il risultato di questa tappa di elaborazione è un documento che elenca in ordine cronologico i segmenti annotati, ciascuno preceduto dal nome del/la parlante, e dà un'informazione temporale a intervalli che corrispondono approssimativamente all'intervallo definito. L'approssimazione deriva dal fatto che sono stati ritenuti solo timecode di inizio segmento, saltandone pure alcuni perché in sovrapposizione. In questo modo, infatti, si crea una granularità, nella misura del tempo, che dipende dalla lunghezza dei segmenti e dalla frequenza delle sovrapposizioni. Scegliendo un intervallo di 10 secondi si ottiene, nella versione finale delle trascrizioni txt, circa una riga di timecode ogni dieci righe, quando la conversazione è vivace, e un tasso più alto di righe col timecode quando i turni sono più lunghi.

Timecode_at_intervals produce un documento intermedio, che ancora non si presta all'uso nella ricerca. Chi ha già esportato documenti txt da ELAN forse metterà le mani nei capelli: in effetti, quando si esporta senza timecode, ELAN mette a disposizione delle opzioni che producono esiti decisamente migliori del nostro documento intermedio. Ma la formattazione fattibile in ELAN, alla quale abbiamo rinunciato per poter filtrare il timecode, si può riprodurre in casa. Inoltre, anche se migliore del nostro documento intermedio, l'impaginazione automatica delle trascrizioni txt prodotta da ELAN non è soddisfacente in alcuni casi, per cui comunque è inevitabile procedere a degli aggiustamenti. Nei prossimi contributi descriveremo questi ulteriori aggiustamenti, in parte automatici, in parte manuali, che riguardano per esempio la cancellazione dei nomi di parlanti superflui, la concatenazione e reimpaginazione di segmenti consecutivi prodotti dallo/a stesso/a parlante e l'ordine e allineamento dei segmenti prodotti in sovrapposizione.

Johanna Miecznikowski

Morfologia delle trascrizioni, parte III