Sök

infrastructureblogia

Revolutionera översättningen av bloggartiklar med AI

Revolutionera översättningen av bloggartiklar med AI

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 OpenAIs språkmodell GPT-4. Skriptet är särskilt utformat för att bearbeta Markdown-filer och underlättar flerspråkig hantering av mina artiklar. Översättningarna är tillgängliga via språkväljaren högst upp på sidan.

Projektstart: Förena AI och automatisering för min blogg

Detta projekt för att automatisera översättningen av mina bloggartiklar startade ur min växande fascination för artificiell intelligens. Inspirerad av mina inledande erfarenheter med OpenAI GPT-4-API:erna och Mistral AI drogs jag till idén att förverkliga dessa tekniker i ett praktiskt projekt som ger verkligt värde för min blogg. Det handlade inte bara om att bemästra AI-verktyg, utan också om att förena automatisering och innovation för att berika min digitala plattform.

Projektet förvandlades till ett äventyr där AI inte bara var ett skrivämne, utan en aktiv partner i utvecklingen. Idén att översätta mina artiklar enkelt och effektivt med AI, samtidigt som jag utforskade dess automatiseringsmöjligheter, öppnade fascinerande perspektiv. Det var en möjlighet att överskrida språkliga barriä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 artificiell intelligens.

Utmaningen

Huvudutmaningen var att skapa ett skript som kunde översätta noggrant samtidigt som originalformateringen bevarades, särskilt kodblock, länkar och bilder. En annan utmaning var att se till 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 använder OpenAI:s 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 säkerställer att den översatta texten förblir trogen originalet.

Nyckelfunktioner

  1. Noggrann översättning med GPT-4 : Skriptet använder OpenAI:s GPT-4-modell för att översätta text från franska till engelska och säkerställer att kvaliteten och nyanserna i originalet bevaras.
  2. Bevarande av formatering : Kodblock, URL:er och bildvägar identifieras och lämnas orörda under översättningen, vilket garanterar att originalformateringen bevaras.
  3. Flerspråkig flexibilitet : Skriptet är utformat för att enkelt anpassas till olika käll- och mål språk, vilket möjliggör en mängd flerspråkiga tillämpningar.
  4. Stöd för Markdown-filer : Förmåga att översätta dokument skrivna i Markdown samtidigt som deras struktur och formatering bibehålls.
  5. Automatiserad översättning av kataloger : Automatisk översättning av Markdown-filer som hittas i en given katalog och dess undermappar, vilket underlättar hantering av stora mängder innehåll.
  6. Inkludering av översättningsanteckning : Lägger automatiskt till en översättningsanteckning i slutet av översatta dokument, som anger vilken GPT-modell som användes för översättningen.
  7. Lätt konfiguration och anpassning : Anpassningsbara standardinställningar för API-nyckel, GPT-modell, käll- och målspråk samt filkataloger, vilket ger stor flexibilitet i användningen.
  8. Prestandarapportering : Skriptet ger återkoppling om tiden som krävs för att översätta varje fil, vilket möjliggör övervakning av dess prestanda.

Skriptkod

Koden finns även här: AI-drivet Markdown-översättningsverktyg

#!/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()

Fördjupning i 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 filsystemoperationer, analysera kommandoradsargument, mäta körtid och utföra sök- och ersättningsoperationer i 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 ange kommandoradsargument.

Funktion translate_with_openai

Nästa är funktionen translate_with_openai. Denna funktion tar en text, ett 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 den:

  1. Funktionen använder ett reguljärt uttryck för att upptäcka och lagra kodblock i texten. Dessa kodblock är avgränsade av tre backticks (). Les blocs de code sont stockés dans une liste appelée 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 motsvarande kodblock i listan code_blocks.
  3. Funktionen skapar ett meddelande för OpenAI API. Detta meddelande innehåller två delar: ett systemmeddelande som instruerar API:t att översätta texten från källspråket till målspråket och att lämna element som URL:er, bildvägar och kodblock oförändrade, samt ett användarmeddelande som innehåller texten som ska översättas.
  4. Funktionen skickar översättningsförfrågan till API:t genom att använda metoden client.chat.completions.create(). Den specificerar vilken modell som ska användas och vilka meddelanden som ska översättas.
  5. API:s svar 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

Därefter har vi funktionen add_translation_note. Denna funktion lägger till en översättningsanteckning i ett dokument. Den tar ett OpenAI-klientobjekt och argument som parametrar. Så här fungerar den:

  1. Funktionen skapar en översättningsanteckning på franska med variabeln translation_note_fr.
  2. Därefter använder funktionen translate_with_openai för att översätta översättningsanteckningen med OpenAI API. Argumenten som skickas till translate_with_openai inkluderar den franska översättningsanteckningen och övriga argument.
  3. Funktionen formaterar den översatta anteckningen genom att lägga till formateringskaraktärer.
  4. Slutligen returnerar funktionen den formaterade översättningsanteckningen.

Funktion translate_markdown_file

Sedan har vi funktionen translate_markdown_file. Denna funktion tar sökvägen till en inmatad Markdown-fil, sökvägen till en utmatad fil, ett OpenAI-klientobjekt och argument som parametrar. Den översätter innehållet i Markdown-filen med OpenAI:s översättnings-API och skriver den översatta texten till utmatningsfilen.

Detta skript har inte bara förbättrat tillgängligheten för mina bloggartiklar, utan också öppnat dörrar för nya möjligheter till automatisering inom flerspråkigt innehållsskapande. Det är ett steg framåt mot en bredare och mer inkluderande spridning av kunskap.

Användarupplevelse 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é.

Behandlingstid

  • Engelska : Ungefär 4 minuter (248.70 sekunder)
  • Spanska : Ungefär 4.7 minuter (284.05 sekunder)
  • Sammanlagt : Ungefär 8.7 minuter (532.75 sekunder) Dessa tider visar skriptets effektivitet och snabbhet.

Resultat

Obs : Detta exempel illustrerar hur skriptet fungerade på den tidigare Hugo-strukturen för bloggen. Bloggen har sedan dess migrerats till Astro med en ny flerspråkig arkitektur. Översättningarna är nu tillgängliga via den inbyggda språkväljaren.

Detta blogginlägg är en sammanfattning av min erfarenhet av automatiserad översättning med AI. Det är ett bevis på att när programmering kombineras med artificiell intelligens är möjligheterna nästan obegränsade, vilket öppnar nya och spännande vyer inom kunskapsdelning och tillgänglighet av innehåll.

Detta dokument har översatts från franska till svenska med modellen gpt-5-mini. För mer information om översättningsprocessen, se https://gitlab.com/jls42/ai-powered-markdown-translator