In dit artikel deel ik een Python-script dat ontwikkeld is als een Proof of Concept (POC) om de vertaling van mijn blogposts te automatiseren, met behulp van het GPT-4-taalmodel van OpenAI. Dit script is specifiek ontworpen om Markdown-bestanden in de structuur van mijn Hugo-blog te verwerken, wat het beheer van meertalige artikelen vergemakkelijkt. Ze zijn beschikbaar in het Engels, Spaans en Chinees.

Projectinitiatie: AI en Automatisering voor Mijn Blog Samenbrengen

Dit project voor het automatiseren van de vertaling van mijn blogartikelen werd geïnitieerd door mijn groeiende fascinatie voor kunstmatige intelligentie. Geïnspireerd door mijn vroege ervaringen met de OpenAI GPT-4 en Mistral AI API’s, werd ik aangetrokken door het idee om deze technologieën in een praktisch project te integreren, dat waarde zou toevoegen aan mijn blog. Het was niet alleen een zoektocht om AI-tools te beheersen, maar ook een verlangen om automatisering en innovatie te combineren om mijn digitale ruimte te verrijken.

Dit project veranderde in een avontuur waarin AI niet alleen een schrijfonderwerp was, maar een actieve partner in de ontwikkeling. Het idee om mijn artikelen eenvoudig en efficiënt met AI te vertalen, terwijl ik de automatiseringsmogelijkheden verkende, bood fascinerende perspectieven. Het was een kans om taalbarrières te overstijgen, mijn inhoud toegankelijk te maken voor een breder publiek, terwijl ik me bewoog in het voortdurend evoluerende domein van kunstmatige intelligentie.

De Uitdaging

De grootste uitdaging was om een script te maken dat nauwkeurig kon vertalen en de oorspronkelijke opmaak van de artikelen kon behouden, inclusief codeblokken, links en afbeeldingen. Een andere uitdaging was ervoor te zorgen dat het script eenvoudig aanpasbaar zou zijn voor verschillende talen. Het moest ook in staat zijn om rekening te houden met deze structuur:

├── 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

De Oplossing: Een Innovatief Script

Ik heb een Python-script ontworpen dat gebruik maakt van de OpenAI GPT-4 API om de tekst te vertalen, terwijl niet-tekstuele elementen behouden blijven. Met behulp van een reeks verwerkingsregels en placeholders kan het script codeblokken en andere niet-vertaalbare elementen identificeren en uitsluiten, waardoor de vertaalde inhoud trouw blijft aan het origineel.

Belangrijkste Eigenschappen

  1. Nauwkeurige Vertaling met GPT-4: Het script gebruikt het GPT-4 model van OpenAI om de tekst van het Frans naar het Engels te vertalen, waarbij de kwaliteit en nuance van de oorspronkelijke inhoud behouden blijven.
  2. Behoud van Opmaak: Codeblokken, URL’s en afbeeldingspaden worden geïdentificeerd en intact gelaten tijdens de vertaling, waardoor de oorspronkelijke opmaak behouden blijft.
  3. Meertalige Flexibiliteit: Het script is ontworpen om eenvoudig aan te passen aan verschillende bron- en doeltalen, wat een grote verscheidenheid aan meertalige toepassingen mogelijk maakt.
  4. Ondersteuning voor Markdown-bestanden: Mogelijkheid om documenten geschreven in Markdown te vertalen, terwijl hun specifieke structuur en opmaak behouden blijven.
  5. Automatisering van Directory Vertaling: Automatische vertaling van Markdown-bestanden gevonden in een opgegeven directory en zijn subdirectories, wat het beheer van grote hoeveelheden inhoud vergemakkelijkt.
  6. Integratie van Vertalingsnotitie: Voegt automatisch een vertalingsnotitie toe aan het einde van de vertaalde documenten, waarin het gebruikte GPT-model voor de vertaling wordt vermeld.
  7. Eenvoudige Configuratie en Personalisatie: Standaardinstellingen die aanpasbaar zijn voor de API-sleutel, het GPT-model, de bron- en doeltalen en de bestandsdirectories, wat een grote flexibiliteit in het gebruik biedt.
  8. Prestatierapport: Het script geeft feedback over de tijd die nodig is om elk bestand te vertalen, waardoor de prestaties kunnen worden bewaakt.

Scriptcode

De code is ook hier beschikbaar: 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()

Inzoomen op het script

Importeren van modules

Eerst hebben we enkele nodig modules geïmporteerd, zoals os, argparse, time en re. Deze modules worden gebruikt om operaties op het bestandssysteem uit te voeren, opdrachtregelargumenten te analyseren, de uitvoertijd te meten en zoek- en vervangingsoperaties op tekst uit te voeren.

Constanten

Vervolgens hebben we constanten gedefinieerd, zoals DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR en DEFAULT_TARGET_DIR. Deze constanten vertegenwoordigen de standaardwaarden die in het script worden gebruikt, maar ze kunnen worden gewijzigd door het specificeren van opdrachtregelargumenten.

Functie translate_with_openai

Vervolgens hebben we de functie translate_with_openai. Deze functie neemt een tekst, een OpenAI-clientobject en argumenten als parameters. Het gebruikt de OpenAI API om de tekst van de brontaal naar de doeltaal te vertalen. Hier is hoe het werkt:

  1. De functie gebruikt een reguliere expressie om codeblokken in de tekst te detecteren en op te slaan. Deze codeblokken worden begrensd door triple backticks (). De codeblokken worden opgeslagen in een lijst genaamd code_blocks`.
  2. Vervolgens vervangt de functie de codeblokken door placeholders in de tekst. De placeholders zijn tekenreeksen van de vorm #CODEBLOCK{index}#, waarbij index de index is van het overeenkomstige codeblok in de lijst code_blocks.
  3. De functie maakt een bericht voor de OpenAI API. Dit bericht bevat twee delen: een systeembericht dat de API vertelt om de tekst van de brontaal naar de doeltaal te vertalen, terwijl elementen zoals URL’s, afbeeldingspaden en codeblokken ongewijzigd blijven, en een gebruikersbericht dat de te vertalen tekst bevat.
  4. De functie verstuurt het vertaalverzoek naar de API met behulp van de methode client.chat.completions.create(). Het specificeert het te gebruiken model en de te vertalen berichten.
  5. Het antwoord van de API bevat de vertaalde tekst. De functie haalt de vertaalde tekst op en vervangt de placeholders door de originele codeblokken.
  6. Ten slotte retourneert de functie de vertaalde tekst.

Functie add_translation_note

Vervolgens hebben we de functie add_translation_note. Deze functie voegt een vertaalnotitie toe aan een document. Het neemt een OpenAI-clientobject en argumenten als parameters. Hier is hoe het werkt:

  1. De functie maakt een vertaalnotitie in het Frans met behulp van de variabele translation_note_fr.
  2. Vervolgens gebruikt de functie de functie translate_with_openai om de vertaalnotitie te vertalen met behulp van de OpenAI API. De argumenten doorgegeven aan translate_with_openai omvatten de vertaalnotitie in het Frans en de andere argumenten.
  3. De functie formatteert de vertaalnotitie door opmaaktekens toe te voegen.
  4. Ten slotte retourneert de functie de geformatteerde vertaalnotitie.

Functie translate_markdown_file

Vervolgens hebben we de functie translate_markdown_file. Deze functie neemt het pad van een invoer-Markdownbestand, het pad van een uitvoerbestand, een OpenAI-clientobject en argumenten als parameters. Het vertaalt de inhoud van het Markdown-bestand met behulp van de OpenAI vertaaldienst en schrijft de vertaalde inhoud naar het uitvoerbestand.

Dit script heeft niet alleen de toegankelijkheid van mijn blogartikelen verbeterd, maar ook de weg geopend naar nieuwe mogelijkheden voor automatisering op het gebied van meertalige contentcreatie. Het is een stap vooruit naar een bredere en meer inclusieve kennisdeling. ## Gebruikerservaring en Verwerkingstijd

Voorbeelden van Gebruik

# 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é.

Verwerkingstijd

  • Engels : Ongeveer 4 minuten (248.70 seconden)
  • Spaans : Ongeveer 4.7 minuten (284.05 seconden)
  • Totale tijd : Ongeveer 8.7 minuten (532.75 seconden) Deze tijden tonen de efficiëntie en snelheid van het script aan.

Resultaten

U kunt nu de resultaten van deze vertaalde inhoudsgeneraties bekijken via deze links:

Deze blogpost is een samenvatting van mijn ervaring met geautomatiseerde vertaling met AI. Het is een bewijs dat, wanneer je programmeren combineert met kunstmatige intelligentie, de mogelijkheden bijna onbeperkt zijn, en nieuwe en spannende perspectieven biedt op het gebied van kennisdeling en contenttoegankelijkheid.

Dit document is vertaald van de versie fr naar de taal nl met behulp van het model gpt-4o. Voor meer informatie over het vertaalproces, zie https://gitlab.com/jls42/ai-powered-markdown-translator