Generateur de discours creux en langue coton |
Les traitements en relation avec textes et langues ont fait l’objet de recherches importantes qui ont marqué les débuts de l’intelligence artificielle et probablement le mouvement de la linguistique structurale avec des personnalités comme Bar-Hillel, Bloomfield, Harris et Chomsky [GANASCIA, 1992, p. 71 à 79]. Plus récemment le thème de la génération automatique de texte a été approfondi avec les travaux de Jean-Pierre Balpe [BALPE, 2000]. L’objectif de l’expérimentation proposée ici est la génération de texte à partir d’une librairie de mots. Le socle des librairies de mots est donné par le livre de François-Bernard Huyghe, La langue de coton. C’est la langue du discours médiatique par excellence éventuellement pratiquée en politique. François-Bernard Huyghe se livre en fait à une critique féroce de ce qu’il considère, dans les médias en général, comme une technique grinçante de l’art de la séduction à des fins de manipulation, de dissimulation ou de pouvoir [HUYGHE, 1991]. Lors du travail préparatoire
deux grands aspects ont pu être observés : la génération
automatique de type paradigmatique, par catégories de mots et d’expressions,
avec des résultats intéressants, et la génération
automatique de syntagmes éventuellement étendus à
la production de paragraphes entiers, beaucoup plus difficile. Vous trouverez
plus de détails dans ma thèse [DROUILLON, 2003, p.114, 127] |
![]() |
TELECHARGER aaaTexte des explications, aaaExecutable (Windows), aaaSource (utilise la librairie Allegro)
|
![]() |
EXPLICATIONS 1. Principe S’appuyer sur des protophrases. Ce sont des modèles de phrases littéralement utilisés comme des moules à phrases. Chaque protophrase est un syntagme constitué de primitives qui sont des catégories de mots. La génération automatique consiste à prendre pour chaque catégorie un mot au hasard. Voici un exemple de protophrase : aaaaa
Sélectionner
dans une listeaaaaa : verbe à l’infinitif 2. Mise en forme
et initialisation aaaaa 1. Une constante chaîne de caractère comme : "bonjour". En fait elle est mémorisée comme un tableau de caractère. Il contient aaaaaaa les caractères de la chaîne et se termine par un ' \0 ' qui en marque la fin [KERNIGHAN, 1995, p.29]. aaaaa
2.
Un tableau de caractère du genre : aaaaaaa Remarquons que dans le premier cas « chaine1[10] » il y a deux cases disponibles en plus (initialisées à zéro). Dans le aaaaa aaaaaaa second, la taille du tableau « chaine1 » est automatiquement ajustée sur le nombre de caractères de la chaîne qui lui est aaaaa aaaaaaa affectée à l’initialisation. Le ' \0 ' final est implicite. La taille du tableau « chaine1 » est alors de huit caractères. aaaaa
3.
Le pointeur de caractères : char* chaine2 = "bonjour"
; Le tableau de pointeurs
de caractères va permettre de stocker les mots par catégorie.
Chaque catégorie a son tableau de char* initialisé directement
dans le programme. Une sentinelle est placée à la fin du
tableau. C’est une astuce pour fournir un test d’arrêt
à la fin du tableau alors que le nombre de ses éléments
n’est pas connu. La sentinelle est simplement la valeur 0 castée
en char*, c’est-à-dire la valeur NULL mais dans le type char*. Compte-tenu du nombre
important de catégories de mots ainsi parfois que du nombre éventuellement
élevé de mots par catégorie, il est plus clair dans
le programme d’utiliser un fichier par catégorie. De ce fait
les données du programme se trouvent partagées sur plusieurs
fichiers. Voici l’ensemble des catégories de mots du programme. Chacune correspond à un tableau de char* qui est défini dans un fichier dédié : extern char*adj_f_p[
];aaaaaaaaa
// adjectif féminin pluriel Toujours au niveau des structures de données, il reste à stocker le résultat qui est une ou plusieurs phrases générées par le programme. Il s’agit d’un char* déclaré en global. Les fonctions qui l’utilisent sont regroupées dans un seul fichier. Le nombre total de protophrases disponibles dans le programme est accessible via une macro ce qui donne les deux déclarations suivantes : #define NB_PROTO
8 Faire une protophrase (2) Son principe est de stocker un ensemble de mots selon la définition d’une protophrase. Le stockage des mots est effectué à l’aide d’un tableau de char* de la taille du nombre des éléments qui composent le syntagme. Il est nommé « mot ». (3) Chaque position du syntagme correspond à la position équivalente du tableau par numéro d’ordre. Certaines positions sont affectées d’un mot fixe, d’une ponctuation ou d’un article suivi d’une apostrophe. D’autres sont piochées dans la liste du genre voulu avec un appel à la fonction « select » qui prend en argument la liste dans laquelle sélectionner un mot avec le nom du tableau correspondant. (4) A l’issue du remplissage du tableau « mot » il s’agit d’ajouter chaque mot de la phrase obtenue au texte en cours d’élaboration. C’est le rôle de la fonction « ajoute_liste » qui prend en argument un char* et est appelée pour chaque mot du syntagme via une boucle for. Détail de la fonction « select » La sélection d’un mot dans une liste s’effectue de la façon suivante : (1)aaaa char* select(char** type_mot) (1) La fonction « select » prend un pointeur de pointeur sur char en paramètre, à savoir une double indirection avec un char**. Ceci afin de pouvoir passer en argument un tableau de char* qui est lui-même une double indirection, un char**. La fonction renvoie une chaîne de caractères (2) Il n’y
a pas dans le programme de référence à la taille
des listes et le nombre des éléments n’est pas connu.
Ainsi le premier point est de compter le nombre des éléments
de la liste. La variable « i » est incrémentée
de 0 à la fin de la liste. (4) Ce nombre détermine le mot de la liste que retourne la fonction avec l’expression « type_mot[ i] » Détail de la fonction « ajoute_liste » Une fois l’ensemble
des mots du syntagme de la protophrase réuni dans le tableau «
mot » de la fonction « frabrique_proto_1 », il reste
à copier dans l’ordre chacun de ces mots à la suite
du texte en cours d’élaboration et stocké dans la
variable globale de type char* (1)aaaa void ajoute_liste(char* mot) (4) aaaaaaaaa if( ! LISTE) (1) La fonction « ajoute_liste » ne renvoie rien et a un char* en paramètre. Il s’agit du mot à ajouter à la liste des mots du texte en cours. (2) Deux variables sont nécessaires, une pour avoir la taille du texte déjà réalisé et l’autre pour avoir la taille du mot à ajouter de façon à pouvoir augmenter la taille du bloc de mémoire en conséquence. (3) Initialisation de la variable « t2 » avec un appel à la fonction « strlen » de la librairie standard du C <string.h>. Cette fonction retourne la longueur en nombre de caractères de la chaîne passée en argument (sans compter le caractère nul de la fin). (4) S’il s’agit du premier mot de la liste LISTE prend la taille « t2 » du premier mot et une adresse mémoire lui est affectée. (5) Si LISTE est
déjà une adresse mémoire, des mots lui ont été
affectés et il est nécessaire de connaître sa taille
afin de pouvoir l’augmenter en proportion du nouveau mot à
ajouter. C’est ce qui motive l’appel à la fonction
« strlen » qui prend LISTE en argument et affecte la valeur
de retour à la variable « t1 ». La longueur total du
texte, t1, est augmentée de 1 afin de mettre soit un espace pour
séparer deux mots soit le caractère nul nécessaire
à la fin de la chaîne de caractères. La taille du
bloc de mémoire à l’adresse de LISTE est ensuite réallouée
selon le nouveau nombre total des caractères ( t1+t2 ) requis par
le texte. (6) Il s’agit de gérer les espaces qui séparent les mots. Il y en a toujours un sauf dans le cas de ponctuation et d’une apostrophe. Précisons que chaque lettre fait l’objet d’un codage et peut être traduite par un nombre entier . Ainsi la valeur ASCII de l’apostrophe est 39 et celle de l’espace est 32. Si le mot n’est pas un point, s’il n’est pas une virgule et s’il n’est pas une apostrophe, un espace est ajouté à la dernière position de la chaîne liste, juste après le dernier caractère et juste derrière lui est indiquée la fin de la chaîne avec le caractère nul. (7) Si en revanche le mot est un point, une virgule ou une apostrophe, il n’y a pas d’espace à ajouter et la fin de la chaîne est juste derrière le dernier caractère, indiquée par le caractère nul. (8) Pour finir, une
fois l’espace mémoire préparé et la jonction
entre la liste existante et le nouveau mot éclaircie, il reste
à copier le mot à la fin de la liste. Pour ce faire c’est
un appel à la fonction « strcat » de la librairie standard
<string.h>. Cette fonction prend deux chaînes de caractères
en argument et concatène la seconde à la suite de la première
à partir du premier caractère nul qu’elle rencontre.,
et sous réserve que l’espace mémoire soit suffisant. 3. Processus générateur Le principe génératif est mis en scène de la façon suivante : (1)aaaa while(!key[KEY_ESC]){ (2)aaaaaaaaa if(key[KEY_ENTER]){ (2) si pression sur la touche Entrée (enter), une nouvelle palette de couleur est créée, l’écran est effacé, (3) La fonction « construit_texte » est appelée. Cette fonction prend un nombre aléatoire de protophrases en argument dans la fourchette de 1 à 5. (4) Lorsque le texte est créé il est affiché à l’écran avec un appel à la fonction « affiche_texte ». Détail de la fonction « construit_texte » Cette fonction permet de sélectionner plusieurs protophrases et de les enchaîner en une seule liste, le texte résultant : (1)aaaa void construit_texte(int nombre_proto) (2)aaaaaaaaaa if( LISTE ) (3)aaaaaaaaaa do{ (8)aaaaaaaaaa correction_majuscules(); (1) La fonction «
construit_texte » prend comme paramètre le nombre total de
protophrases à additionner pour faire un texte. (5) Un switch, fondé sur la valeur de la variable « choix », dirige vers l’appel de la fonction de fabrication de protophrase correspondante. (6) Le nombre de protophrases qui restent à fabriquer et ajouter à la liste est diminué de 1. (7) L’action
reprend tant qu’il y a des protophrases à ajouter à
la liste, c’est-à-dire que le nombre des protophrases à
faire est supérieur (8) Une fois le texte terminé, il y a à corriger les majuscules après les points. C’est le rôle de la fonction « correction_majuscules ». Détail de la fonction « correction_majuscules » Cette fonction parcourt la chaîne de caractères LISTE et à chaque fois qu’un point est trouvé, la première lettre du premier mot suivant est mise en majuscule : (1)aaaa void correction_majuscules(void) (3)aaaaaaaaa do{ (4) aaaaaaaaaaaaaif( *p == '.' ) (5) aaaaaaaaaaaaaif ( flag == TRUE &&
isgraph ( *p ) ){ (1) La fonction « correction_majuscules » ne renvoie pas de valeur et n’a pas de paramètre. (2) Deux variables
locales sont utilisées. La première « p » est
un char* initialisé sur l’adresse de LISTE qui va servir
à parcourir la liste. La seconde « flag » sert à
marquer la rencontre éventuelle d’un point. (5) Deuxième
test : si flag est sur TRUE, un point a été rencontré
et il faut mettre en majuscule la première lettre qui arrive. Il
faut attendre cette première lettre et c’est le rôle
de l’appel de la fonction « isgraph » de la librairie
<ctype.h> standard du C. Cette fonction retourne vrai si son argument
est un caractère affichable différent d’un espace
et faux sinon. Si flag est TRUE et « isgraph » retourne vrai
alors les instructions sont effectuées : Détail de la fonction « affiche_texte » Une fois le texte mis en forme et corrigé, il n’y a plus qu’à l’afficher, c’est le rôle de l’appel de la fonction « affiche_texte » (1)aaaa void affiche_texte( void ) (3)aaaaaaaax=ECRAN_X/8; (4)aaaaaaaado{ (1) La fonction « affiche_texte » n’a pas de paramètre et ne renvoie aucune valeur. (2) Plusieurs variables locales sont nécessaires à son fonctionnement. Trois chaînes de caractères dont une, « tmp », qui est initialisée avec une taille de deux caractères (un caractère plus le caractère nul). En fait le texte va être affiché lettre par lettre. La variable « tmp » va permettre d’isoler chaque lettre et d’utiliser une fonction de la librairie Allegro pour l’affichage d’une chaîne de caractère. La chaîne de caractère « p » est initialisée sur LISTE et va servir à parcourir le texte. Les variables « x » et « y » correspondent à la position dans l’écran. « tx » va servir à délimiter la taille horizontale pour le texte. Comme le texte sera toujours relativement court il n’ y a pas de limite verticale. Les variables « pasx » et « pasy » déterminent les pas d’avancement horizontaux et verticaux pour chaque lettre. La variable « color » est pour la couleur. (3) La variable x, position horizontale, est initialisée pour la marge gauche sur un huitième de l’écran. Pour la marge droite également avec la taille de l’écran moins un huitième. La marge en haut est deux fois la marge horizontale. Il n’y a pas de marge en bas mais les textes restent au centre de l’écran. Le pas d’avancement est de 8 pixels à l’horizontal. Il correspond à la taille de chaque lettre de la police utilisée (une police de base comme celle du « Bios » et fournie par l’environnement ). Il est le double en vertical. (4) (7) Boucle do-while. Le test d’arrêt est du type de celui vu avec la fonction précédente « correction_majuscules » et comporte un test supplémentaire sur l’état de la touche Echap afin de pouvoir quitter le programme sans attendre la fin de cette boucle si demandé par l’utilisateur. (5) Le premier point est de savoir dès le début de chaque mot s’il va tenir sur la ligne ou pas, et s’il faut passer à la ligne suivante en incrémentant y. Pour ce faire, à partir de chaque espace trouvé (valeur ASCII 32), le nombre de lettres est compté jusqu’à l’espace suivant ou la fin éventuelle du texte. C’est le rôle des variables « i » et « c » dans la boucle for. Une fois ce nombre obtenu, il est multiplié par le pas d’avancement, additionné à la position horizontale courante et le résultat est comparé à la borne horizontale droite. S’il est supérieur, il faut passer à la ligne c’est-à-dire augmenter y de pasx et faire revenir la position horizontale sur la marge de gauche. (6) Quoiqu’il
en soit, la lettre courante est affectée à la première
position de la chaîne tmp. Ensuite appel de la fonction «
textout » qui peut afficher une chaîne de caractère
dans une bitmap. Cette fonction prend plusieurs arguments et voici son
prototype : Le premier argument
est la bitmap de référence, le second la police utilisée,
le troisième la chaîne de caractère à afficher,
les quatrième et cinquième la position initiale et le dernier
la couleur. Pour notre appel la fonction prend la bitmap écran,
screen, la fonte « font » par défaut, la chaîne
de caractère tmp c’est-à-dire la lettre courante à
la position ( x, y ) et avec une couleur qui évolue de 1 à
255 et selon la palette. (8) Après
fin de la boucle l’espace mémoire alloué à
la variable tmp est libéré. Eléments bibliographiques cités BALPE Jean-Pierre,
L'art et le numérique, Hermès, Paris 2000. GANASCIA, Jean-Gabriel, L’âme-machine, les enjeux de l’intelligence artificielle, Seuil, Paris 1990. HUYGHE François-Bernard, La langue de coton, Robert Laffont, Paris 1991. KERNIGHAN Brian, RITCHIE Dennis, Le langage C, Masson, Paris 1995, première édition 1978.
|
![]() |