I den här artikeln delar jag ett Python-skript utvecklat som ett Proof of Concept (POC) för att automatisera översättningen av mina blogginlägg, med hjälp av OpenAI:s GPT-4 språkmodell. Detta skript är specifikt utformat för att hantera Markdown-filer i strukturen av min Hugo-blogg, vilket underlättar flerspråkig hantering av mina artiklar. De finns tillgängliga på Engelska, Spanska och Kinesiska.

Projektinitiering: Kombinera AI och Automation för Min Blogg

Detta projekt för att automatisera översättningen av mina bloggartiklar initierades av min växande fascination för artificiell intelligens. Inspirerad av mina preliminära erfarenheter med OpenAIs GPT-4 och Mistral AI:s API:er, lockades jag av idén att konkretisera dessa teknologier i ett praktiskt projekt som erbjuder ett verkligt värde för min blogg. Det handlade inte bara om att bemästra AI-verktyg, utan också om en önskan att kombinera automation och innovation för att berika mitt digitala utrymme.

Detta projekt förvandlades till ett äventyr där AI inte bara var ett ämne att skriva om, utan en aktiv partner i utvecklingen. Idén att enkelt och effektivt översätta mina artiklar med AI, samtidigt som jag utforskar dess automatiseringsförmågor, öppnade fascinerande perspektiv. Det handlade om en möjlighet att övervinna språkbarriärer och göra mitt innehåll tillgängligt för en bredare publik, samtidigt som jag navigerade i det ständigt föränderliga området av artificiell intelligens.

Utmaningen

Den huvudsakliga utmaningen var att skapa ett skript som kunde översätta noggrant och behålla den ursprungliga formateringen av artiklarna, särskilt kodblock, länkar och bilder. En annan utmaning var att säkerställa att skriptet enkelt kunde anpassas för att stödja olika språk. Det behövde också kunna hantera följande struktur:

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

Lösningen: Ett Innovativt Skript

Jag utformade ett Python-skript som bygger på OpenAIs GPT-4 API för att översätta texten samtidigt som icke-textuella element bevaras. Genom en serie behandlingsregler och användning av platshållare, kan skriptet identifiera och exkludera kodblock och andra icke-översättbara element, vilket garanterar att det översatta innehållet förblir troget originalet.

Nyckelfunktioner

  1. Noggrann Översättning med GPT-4: Skriptet använder OpenAIs GPT-4 modell för att översätta text från franska till engelska, och säkerställer att kvaliteten och nyansen i originalinnehållet bevaras.
  2. Bevarande av Formatering: Kodblock, URL:er och bildvägar identifieras och lämnas orörda under översättningen, vilket säkerställer att den ursprungliga formateringen bevaras.
  3. Flerspråkig Flexibilitet: Skriptet är utformat för att enkelt kunna anpassas till olika käll- och målspråk, vilket möjliggör en bred variation av flerspråkiga tillämpningar.
  4. Stöd för Markdown-filer: Förmåga att översätta dokument skrivna i Markdown, samtidigt som deras specifika struktur och formatering bevaras.
  5. Automatisering av Katalogöversättning: Automatisk översättning av Markdown-filer som hittas i en given katalog och dess underkataloger, vilket underlättar hanteringen av stora mängder innehåll.
  6. Integrering av Översättningsnot: Lägger automatiskt till en översättningsnot i slutet av de översatta dokumenten, som anger vilken GPT-modell som användes för översättningen.
  7. Enkel Konfiguration och Anpassning: Anpassningsbara standardinställningar för API-nyckel, GPT-modell, käll- och målspråk, samt filkataloger, vilket ger stor användningsflexibilitet.
  8. Prestandarapport: Skriptet ger feedback om tiden som krävs för att översätta varje fil, vilket möjliggör övervakning av dess prestanda.

Skriptkod

Koden är också tillgänglig här: 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()

Fokus på skriptet

Modulimporter

Först har vi några nödvändiga modulimporter, såsom os, argparse, time och re. Dessa moduler används för att utföra operationer på filsystemet, analysera kommandoradsargument, mäta exekveringstiden och utföra sök- och ersättningsoperationer för text.

Konstanter

Därefter har vi definierade konstanter, såsom DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR och DEFAULT_TARGET_DIR. Dessa konstanter representerar standardvärden som används i skriptet, men de kan ändras genom att specificera kommandoradsargument.

Funktion translate_with_openai

Nästa är funktionen translate_with_openai. Denna funktion tar en text, en OpenAI-klientobjekt och argument som parametrar. Den använder OpenAI API för att översätta texten från källspråket till målspråket. Så här fungerar det:

  1. Funktionen använder ett reguljärt uttryck för att upptäcka och lagra kodblock i texten. Dessa kodblock avgränsas av trippel backticks (). Kodblocken lagras i en lista som kallas code_blocks`.
  2. Därefter ersätter funktionen kodblocken med platshållare i texten. Platshållarna är strängar av formen #CODEBLOCK{index}#, där index är indexet för det motsvarande kodblocket i listan code_blocks.
  3. Funktionen skapar ett meddelande för OpenAI API. Detta meddelande innehåller två delar: ett systemmeddelande som instruerar API:et att översätta texten från källspråket till målspråket och låta element som URL:er, bildvägar och kodblock vara oförändrade, och ett användarmeddelande som innehåller texten som ska översättas.
  4. Funktionen skickar översättningsförfrågan till API:et med hjälp av metoden client.chat.completions.create(). Den specificerar vilken modell som ska användas och vilka meddelanden som ska översättas.
  5. Svaren från API:et innehåller den översatta texten. Funktionen hämtar den översatta texten och ersätter platshållarna med de ursprungliga kodblocken.
  6. Slutligen returnerar funktionen den översatta texten.

Funktion add_translation_note

Nästa är funktionen add_translation_note. Denna funktion lägger till en översättningsnot till ett dokument. Den tar en OpenAI-klientobjekt och argument som parametrar. Så här fungerar det:

  1. Funktionen skapar en översättningsnot på franska med hjälp av variabeln translation_note_fr.
  2. Därefter använder funktionen funktionen translate_with_openai för att översätta översättningsnotet med hjälp av OpenAI API. Argumenten som skickas till translate_with_openai inkluderar översättningsnoten på franska och de andra argumenten.
  3. Funktionen formaterar den översatta översättningsnoten genom att lägga till formateringskaraktärer.
  4. Slutligen returnerar funktionen den formaterade översättningsnoten.

Funktion translate_markdown_file

Nästa är funktionen translate_markdown_file. Denna funktion tar sökvägen av en ingående Markdown-fil, sökvägen av en utgående fil, en OpenAI-klientobjekt och argument som parametrar. Den översätter innehållet i Markdown-filen med hjälp av OpenAI översättnings-API och skriver det översatta innehållet till utgående filen.

Detta skript har inte bara förbättrat tillgängligheten för mina bloggartiklar utan har också öppnat vägen för nya automatiseringsmöjligheter inom området för skapande av flerspråkigt innehåll. Det är ett steg framåt mot en bredare och mer inkluderande spridning av kunskap. ## Användarerfarenhet och Bearbetningstid

Användningsexempel

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

Bearbetningstid

  • Engelska : Cirka 4 minuter (248,70 sekunder)
  • Spanska : Cirka 4,7 minuter (284,05 sekunder)
  • Total ackumulerad tid : Cirka 8,7 minuter (532,75 sekunder) Dessa tider visar skriptets effektivitet och snabbhet.

Resultat

Du kan nu komma åt resultaten av dessa översättningsgenereringar på följande länkar:

Detta blogginlägg är en sammanfattning av mina erfarenheter inom översättningsautomatisering med AI. Det är ett bevis på att när man kombinerar programmering med artificiell intelligens, är möjligheterna nästan obegränsade, vilket öppnar nya och spännande horisonter inom området kunskapsdelning och innehållstillgänglighet.

Detta dokument har översatts från version fr till språket sv med hjälp av modellen gpt-4o. För mer information om översättningsprocessen, besök https://gitlab.com/jls42/ai-powered-markdown-translator