Dans cet article, je partage un script Python développé comme un Proof of Concept (POC) pour automatiser la traduction des posts de mon blog, en utilisant le modèle de langage GPT-4 d’OpenAI. Ce script est spécifiquement conçu pour traiter des fichiers Markdown dans la structure de mon blog Hugo, facilitant la gestion multilingue de mes articles. Ils sont disponibles en Anglais, Espagnol et Chinois.

Initiation au Projet : Fusionner IA et Automatisation pour Mon Blog

Ce projet d’automatisation de la traduction de mes articles de blog a été initié par ma fascination croissante pour l’intelligence artificielle. Inspiré par mes expériences préliminaires avec les APIs OpenAI GPT-4 et Mistral AI, j’ai été attiré par l’idée de concrétiser ces technologies dans un projet pratique, offrant une valeur tangible à mon blog. Ce n’était pas seulement une quête de maîtriser les outils d’IA, mais aussi un désir de fusionner l’automatisation et l’innovation pour enrichir mon espace numérique.

Ce projet s’est transformé en une aventure où l’IA n’était pas seulement un sujet d’écriture, mais un partenaire actif dans le développement. L’idée de traduire mes articles de manière simple et efficace avec l’IA, tout en explorant ses capacités d’automatisation, ouvrait des perspectives fascinantes. Il s’agissait d’une opportunité de transcender les barrières linguistiques, rendant mon contenu accessible à un public plus large, tout en naviguant dans le domaine en constante évolution de l’intelligence artificielle.

Le Défi

Le défi principal était de créer un script capable de traduire avec précision et de conserver la mise en forme originale des articles, notamment les blocs de code, les liens et les images. Un autre défi était de s’assurer que le script puisse être facilement adapté pour prendre en charge différentes langues. Il devait aussi être capable de prendre en compte cette structure :

├── content
│   ├── about
│   │   └── a-propos-du-blog-jls42.md
│   ├── mentions
│   │   └── mentions-legales.md
│   ├── posts
│   │   ├── blog
│   │   │   └── nouveau-theme-logo.md
│   │   ├── ia
│   │   │   ├── poc-mistral-ai-mixtral.md
│   │   │   ├── poc-openai-api-gpt4.md
│   │   │   └── stable-difusion-aws-ec2.md
│   │   ├── infrastructure
│   │   │   └── infrastruture-as-code-serverless-ha-jls42-org.md
│   │   └── raspberry-pi
│   │       ├── glusterfs_distribue_replique_sur_raspberry_pi_via_ansible.md
│   │       ├── initialisation-auto-de-raspbian-sur-raspberry-pi.md
│   │       ├── installation-de-docker-sur-raspberry-pi-via-ansible.md
│   │       └── installation-de-kubernetes-sur-raspberry-pi-via-ansible.md

La Solution : Un Script Innovant

J’ai conçu un script Python qui s’appuie sur l’API OpenAI GPT-4 pour traduire le texte tout en préservant les éléments non-textuels. Grâce à une série de règles de traitement et à l’utilisation de placeholders, le script peut identifier et exclure les blocs de code et autres éléments non traduisibles, garantissant ainsi que le contenu traduit reste fidèle à l’original.

Fonctionnalités Clés

  1. Traduction Précise avec GPT-4 : Le script utilise le modèle GPT-4 d’OpenAI pour traduire le texte du français à l’anglais, en s’assurant de conserver la qualité et la nuance du contenu original.
  2. Préservation de la Mise en Forme : Les blocs de code, les URL et les chemins d’image sont identifiés et laissés intacts pendant la traduction, garantissant que la mise en forme originale est préservée.
  3. Flexibilité Multilingue : Le script est conçu pour être facilement adaptable à différentes langues source et cible, permettant une grande variété d’applications multilingues.
  4. Prise en Charge des Fichiers Markdown : Capacité de traduire des documents écrits en Markdown, en conservant leur structure et formatage spécifiques.
  5. Automatisation de la Traduction de Répertoires : Traduction automatique des fichiers Markdown trouvés dans un répertoire donné et de ses sous-répertoires, facilitant la gestion de gros volumes de contenu.
  6. Intégration de Note de Traduction : Ajoute automatiquement une note de traduction à la fin des documents traduits, indiquant le modèle GPT utilisé pour la traduction.
  7. Configuration et Personnalisation Faciles : Paramètres par défaut personnalisables pour la clé API, le modèle GPT, les langues source et cible, et les répertoires de fichiers, offrant une grande souplesse d’utilisation.
  8. Rapport de Performance : Le script fournit un retour d’information sur le temps nécessaire pour traduire chaque fichier, permettant de surveiller sa performance.

Code du script

Le code est disponible aussi ici : AI-Powered Markdown Translator

#!/usr/bin/env python3

import os
import argparse
import time
from openai import OpenAI
import re

# Initialisation de la configuration avec les valeurs par défaut
DEFAULT_API_KEY = 'votre-clé-api-par-défaut'
DEFAULT_MODEL = "gpt-4-1106-preview"
DEFAULT_SOURCE_LANG = 'fr'
DEFAULT_TARGET_LANG = 'en'
DEFAULT_SOURCE_DIR = 'content/posts'
DEFAULT_TARGET_DIR = 'traductions_en'

MODEL_TOKEN_LIMITS = {
    "gpt-4-1106-preview": 4096,
    "gpt-4-vision-preview": 4096,
    "gpt-4": 8192,
    "gpt-4-32k": 32768,
    "gpt-4-0613": 8192,
    "gpt-4-32k-0613": 32768
}

# Fonction de traduction
def translate_with_openai(text, client, args):
    """
    Traduit le texte donné du langage source au langage cible en utilisant l'API OpenAI.
    
    Args:
        text (str) : Le texte à traduire.
        client : L'objet client OpenAI.
        args : Les arguments contenant les informations sur le langage source, le langage cible et le modèle.
        
    Returns:
        str : Le texte traduit.
    """
    # Détecter et stocker les blocs de code
    code_blocks = re.findall(r'(^```[a-zA-Z]*\n.*?\n^```)', text, flags=re.MULTILINE | re.DOTALL)
    placeholders = [f"#CODEBLOCK{index}#" for index, _ in enumerate(code_blocks)]
    
    # Remplacer les blocs de code par des placeholders
    for placeholder, code_block in zip(placeholders, code_blocks):
        text = text.replace(code_block, placeholder)
    
    # Création du message pour l'API
    messages = [
        {"role": "system", "content": f"Translate the following text from {args.source_lang} to {args.target_lang}, ensuring that elements such as URLs, image paths, and code blocks (delimited by ```) are not translated. Leave these elements unchanged."},
        {"role": "user", "content": text}
    ]
    
    # Envoi de la demande de traduction
    response = client.chat.completions.create(
        model=args.model,
        messages=messages
    )
    
    # Obtenir le texte traduit et remplacer les placeholders par les blocs de code originaux
    translated_text = response.choices[0].message.content.strip()
    for placeholder, code_block in zip(placeholders, code_blocks):
        translated_text = translated_text.replace(placeholder, code_block)

    return translated_text

def add_translation_note(client, args):
    """
    Ajoute une note de traduction à un document.

    Args:
        client : Le client de traduction.
        args : Arguments supplémentaires.

    Returns:
        La note de traduction formatée.
    """
    # Note de traduction en français
    translation_note_fr = "Ce document a été traduit de la version française du blog par le modèle "
    # Traduire la note en langue cible
    translated_note = translate_with_openai(translation_note_fr + args.model, client, args)
    # Formatage de la note de traduction
    return f"\n\n**{translated_note}**\n\n"

# Traitement des fichiers Markdown
def translate_markdown_file(file_path, output_path, client, args):
    """
    Traduit le contenu d'un fichier markdown en utilisant l'API de traduction OpenAI et écrit le contenu traduit dans un nouveau fichier.

    Args:
        file_path (str): Chemin vers le fichier markdown d'entrée.
        output_path (str): Chemin vers le fichier de sortie où le contenu traduit sera écrit.
        client: Client de traduction OpenAI.
        args: Arguments supplémentaires pour le processus de traduction.

    Returns:
        None
    """
    print(f"Traitement du fichier : {file_path}")
    start_time = time.time()

    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

    translated_content = translate_with_openai(content, client, args)
    
    # Ajouter la note de traduction à la fin du contenu traduit
    translation_note = add_translation_note(client, args)
    translated_content_with_note = translated_content + translation_note

    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(translated_content_with_note)

    end_time = time.time()
    print(f"Traduction terminée en {end_time - start_time:.2f} secondes.")

def translate_directory(input_dir, output_dir, client, args):
    """
    Traduit tous les fichiers markdown dans le répertoire d'entrée et ses sous-répertoires.

    Args:
        input_dir (str): Chemin vers le répertoire d'entrée.
        output_dir (str): Chemin vers le répertoire de sortie.
        client: Objet client de traduction.
        args: Arguments supplémentaires pour la traduction.

    Returns:
        None
    """
    for root, dirs, files in os.walk(input_dir, topdown=True):
        # Exclure les dossiers qui commencent par "traductions_"
        dirs[:] = [d for d in dirs if not d.startswith("traductions_")]

        for file in files:
            if file.endswith('.md'):
                file_path = os.path.join(root, file)
                base, _ = os.path.splitext(file)
                # Ajouter le nom du modèle utilisé dans le nom du fichier de sortie
                output_file = f"{base}-{args.model}-{args.target_lang}.md"
                relative_path = os.path.relpath(root, input_dir)
                output_path = os.path.join(output_dir, relative_path, output_file)

                os.makedirs(os.path.dirname(output_path), exist_ok=True)

                if not os.path.exists(output_path):
                    translate_markdown_file(file_path, output_path, client, args)
                    print(f"Fichier '{file}' traité.")


def main():
    """
    Fonction principale pour traduire les fichiers Markdown.

    Args:
        --source_dir (str): Répertoire source contenant les fichiers Markdown.
        --target_dir (str): Répertoire cible pour sauvegarder les traductions.
        --model (str): Modèle GPT à utiliser.
        --target_lang (str): Langue cible pour la traduction.
        --source_lang (str): Langue source pour la traduction.
    """
    parser = argparse.ArgumentParser(description="Traduit les fichiers Markdown.")
    parser.add_argument('--source_dir', type=str, default=DEFAULT_SOURCE_DIR, help='Répertoire source contenant les fichiers Markdown')
    parser.add_argument('--target_dir', type=str, default=DEFAULT_TARGET_DIR, help='Répertoire cible pour sauvegarder les traductions')
    parser.add_argument('--model', type=str, default=DEFAULT_MODEL, help='Modèle GPT à utiliser')
    parser.add_argument('--target_lang', type=str, default=DEFAULT_TARGET_LANG, help='Langue cible pour la traduction')
    parser.add_argument('--source_lang', type=str, default=DEFAULT_SOURCE_LANG, help='Langue source pour la traduction')

    args = parser.parse_args()

    openai_api_key = os.getenv('OPENAI_API_KEY', DEFAULT_API_KEY)
    with OpenAI(api_key=openai_api_key) as client:
        translate_directory(args.source_dir, args.target_dir, client, args)

if __name__ == "__main__":
    main()

Zoom sur le script

Importations de modules

Tout d’abord, nous avons quelques importations de modules nécessaires, tels que os, argparse, time et re. Ces modules sont utilisés pour effectuer des opérations sur le système de fichiers, analyser les arguments de ligne de commande, mesurer le temps d’exécution et effectuer des opérations de recherche et de remplacement de texte.

Constantes

Ensuite, nous avons des constantes définies, telles que DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR et DEFAULT_TARGET_DIR. Ces constantes représentent les valeurs par défaut utilisées dans le script, mais elles peuvent être modifiées en spécifiant des arguments de ligne de commande.

Fonction translate_with_openai

Ensuite, nous avons la fonction translate_with_openai. Cette fonction prend un texte, un objet client OpenAI et des arguments en tant que paramètres. Elle utilise l’API OpenAI pour traduire le texte de la langue source à la langue cible. Voici comment cela fonctionne :

  1. La fonction utilise une expression régulière pour détecter et stocker les blocs de code dans le texte. Ces blocs de code sont délimités par des triple backticks (). Les blocs de code sont stockés dans une liste appelée code_blocks`.
  2. Ensuite, la fonction remplace les blocs de code par des placeholders dans le texte. Les placeholders sont des chaînes de la forme #CODEBLOCK{index}#, où index est l’indice du bloc de code correspondant dans la liste code_blocks.
  3. La fonction crée un message pour l’API OpenAI. Ce message contient deux parties : un message système qui indique à l’API de traduire le texte de la langue source à la langue cible en laissant les éléments tels que les URL, les chemins d’image et les blocs de code inchangés, et un message utilisateur qui contient le texte à traduire.
  4. La fonction envoie la demande de traduction à l’API en utilisant la méthode client.chat.completions.create(). Elle spécifie le modèle à utiliser et les messages à traduire.
  5. La réponse de l’API contient le texte traduit. La fonction récupère le texte traduit et remplace les placeholders par les blocs de code originaux.
  6. Enfin, la fonction renvoie le texte traduit.

Fonction add_translation_note

Ensuite, nous avons la fonction add_translation_note. Cette fonction ajoute une note de traduction à un document. Elle prend un objet client OpenAI et des arguments en tant que paramètres. Voici comment cela fonctionne :

  1. La fonction crée une note de traduction en français en utilisant la variable translation_note_fr.
  2. Ensuite, la fonction utilise la fonction translate_with_openai pour traduire la note de traduction en utilisant l’API OpenAI. Les arguments passés à translate_with_openai incluent la note de traduction en français et les autres arguments.
  3. La fonction formate la note de traduction traduite en ajoutant des caractères de mise en forme.
  4. Enfin, la fonction renvoie la note de traduction formatée.

Fonction translate_markdown_file

Ensuite, nous avons la fonction translate_markdown_file. Cette fonction prend le chemin d’un fichier Markdown d’entrée, le chemin d’un fichier de sortie, un objet client OpenAI et des arguments en tant que paramètres. Elle traduit le contenu du fichier Markdown en utilisant l’API de traduction OpenAI et écrit le contenu traduit dans le fichier de sortie.

Ce script a non seulement amélioré l’accessibilité de mes articles de blog, mais a également ouvert la voie à de nouvelles possibilités d’automatisation dans le domaine de la création de contenu multilingue. C’est un pas en avant vers un partage plus large et plus inclusif des connaissances.

Expérience d’Utilisation et Temps de Traitement

Exemples d’Usage

# Création des répertoires cibles
jls42@Boo:~/blog/jls42$ mkdir content/traductions_en content/traductions_es

###############################################
# Demande de traduction à l'IA vers l'anglais #
###############################################
jls42@Boo:~/blog/jls42$ python3 translate.py --source_dir content/ --target_dir content/traductions_en
Traitement du fichier : content/posts/ia/stable-difusion-aws-ec2.md
Traduction terminée en 21.57 secondes.
Fichier 'stable-difusion-aws-ec2.md' traité.
Traitement du fichier : content/posts/ia/poc-openai-api-gpt4.md
Traduction terminée en 34.87 secondes.
Fichier 'poc-openai-api-gpt4.md' traité.
Traitement du fichier : content/posts/ia/poc-mistral-ai-mixtral.md
Traduction terminée en 62.47 secondes.
Fichier 'poc-mistral-ai-mixtral.md' traité.
Traitement du fichier : content/posts/raspberry-pi/installation-de-kubernetes-sur-raspberry-pi-via-ansible.md
Traduction terminée en 46.37 secondes.
Fichier 'installation-de-kubernetes-sur-raspberry-pi-via-ansible.md' traité.
Traitement du fichier : content/posts/raspberry-pi/installation-de-docker-sur-raspberry-pi-via-ansible.md
Traduction terminée en 10.08 secondes.
Fichier 'installation-de-docker-sur-raspberry-pi-via-ansible.md' traité.
Traitement du fichier : content/posts/raspberry-pi/initialisation-auto-de-raspbian-sur-raspberry-pi.md
Traduction terminée en 17.17 secondes.
Fichier 'initialisation-auto-de-raspbian-sur-raspberry-pi.md' traité.
Traitement du fichier : content/posts/blog/nouveau-theme-logo.md
Traduction terminée en 12.91 secondes.
Fichier 'nouveau-theme-logo.md' traité.
Traitement du fichier : content/posts/infrastructure/infrastruture-as-code-serverless-ha-jls42-org.md
Traduction terminée en 12.64 secondes.
Fichier 'infrastruture-as-code-serverless-ha-jls42-org.md' traité.
Traitement du fichier : content/mentions/mentions-legales.md
Traduction terminée en 11.90 secondes.
Fichier 'mentions-legales.md' traité.
Traitement du fichier : content/about/a-propos-du-blog-jls42.md
Traduction terminée en 18.72 secondes.
Fichier 'a-propos-du-blog-jls42.md' traité.

################################################
# Demande de traduction à l'IA vers l'espagnol #
################################################
jls42@Boo:~/blog/jls42$ python3 translate.py --source_dir content/ --target_dir content/traductions_es --target_lang es
Traitement du fichier : content/posts/ia/stable-difusion-aws-ec2.md
Traduction terminée en 33.19 secondes.
Fichier 'stable-difusion-aws-ec2.md' traité.
Traitement du fichier : content/posts/ia/poc-openai-api-gpt4.md
Traduction terminée en 25.24 secondes.
Fichier 'poc-openai-api-gpt4.md' traité.
Traitement du fichier : content/posts/ia/poc-mistral-ai-mixtral.md
Traduction terminée en 58.78 secondes.
Fichier 'poc-mistral-ai-mixtral.md' traité.
Traitement du fichier : content/posts/raspberry-pi/installation-de-kubernetes-sur-raspberry-pi-via-ansible.md
Traduction terminée en 17.64 secondes.
Fichier 'installation-de-kubernetes-sur-raspberry-pi-via-ansible.md' traité.
Traitement du fichier : content/posts/raspberry-pi/installation-de-docker-sur-raspberry-pi-via-ansible.md
Traduction terminée en 19.60 secondes.
Fichier 'installation-de-docker-sur-raspberry-pi-via-ansible.md' traité.
Traitement du fichier : content/posts/raspberry-pi/initialisation-auto-de-raspbian-sur-raspberry-pi.md
Traduction terminée en 37.12 secondes.
Fichier 'initialisation-auto-de-raspbian-sur-raspberry-pi.md' traité.
Traitement du fichier : content/posts/blog/nouveau-theme-logo.md
Traduction terminée en 18.91 secondes.
Fichier 'nouveau-theme-logo.md' traité.
Traitement du fichier : content/posts/infrastructure/infrastruture-as-code-serverless-ha-jls42-org.md
Traduction terminée en 30.73 secondes.
Fichier 'infrastruture-as-code-serverless-ha-jls42-org.md' traité.
Traitement du fichier : content/mentions/mentions-legales.md
Traduction terminée en 13.14 secondes.
Fichier 'mentions-legales.md' traité.
Traitement du fichier : content/about/a-propos-du-blog-jls42.md
Traduction terminée en 11.24 secondes.
Fichier 'a-propos-du-blog-jls42.md' traité.

Temps de Traitement

  • Anglais : Environ 4 minutes (248.70 secondes)
  • Espagnol : Environ 4.7 minutes (284.05 secondes)
  • Total cumulé : Environ 8.7 minutes (532.75 secondes) Ces temps démontrent l’efficacité et la rapidité du script.

Résulats

Vous pouvez dès à présent accéder aux résultats de ces générations de contenu traduit sur ces liens :

Ce post de blog est un condensé de mon expérience en automatisation de traduction avec l’IA. C’est une preuve que, quand on associe la programmation à l’intelligence artificielle, les possibilités sont presque illimitées, ouvrant des horizons nouveaux et passionnants dans le domaine du partage de connaissances et de l’accessibilité du contenu.