În acest articol, împărtășesc un script Python dezvoltat ca un Proof of Concept (POC) pentru automatizarea traducerii postărilor de pe blogul meu, folosind modelul de limbaj GPT-4 de la OpenAI. Acest script este special conceput pentru a procesa fișiere Markdown în structura blogului meu Hugo, facilitând gestionarea multilingvă a articolelor mele. Ele sunt disponibile în Engleză, Spaniolă și Chineză.

Inițierea Proiectului: Îmbinarea IA și Automatizării pentru Blogul Meu

Acest proiect de automatizare a traducerii articolelor mele de blog a fost inițiat din fascinația mea în creștere pentru inteligența artificială. Inspirat de experiențele mele preliminare cu API-urile OpenAI GPT-4 și Mistral AI, am fost atras de ideea de a concretiza aceste tehnologii într-un proiect practic, oferind o valoare tangibilă blogului meu. Nu era doar o căutare de a stăpâni uneltele IA, ci și o dorință de a îmbina automatizarea și inovația pentru a îmbogăți spațiul meu digital.

Acest proiect s-a transformat într-o aventură unde IA nu era doar un subiect de scris, ci un partener activ în dezvoltare. Ideea de a traduce articolele mele într-un mod simplu și eficient cu IA, explorând în același timp capacitățile sale de automatizare, deschidea perspective fascinante. Era vorba despre o oportunitate de a transcende barierele lingvistice, făcând conținutul meu accesibil unui public mai larg, navigând totodată în domeniul în continuă evoluție al inteligenței artificiale.

Provocarea

Provocarea principală era de a crea un script capabil să traducă cu precizie și să păstreze formatarea originală a articolelor, inclusiv blocurile de cod, link-urile și imaginile. O altă provocare era să se asigure că scriptul poate fi ușor adaptat pentru a suporta diferite limbi. El trebuia de asemenea să poată lua în considerare această structură:

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

Soluția: Un Script Inovator

Am conceput un script Python care se bazează pe API-ul OpenAI GPT-4 pentru a traduce textul păstrând în același timp elementele non-textuale. Printr-o serie de reguli de procesare și utilizarea de elemente placeholder, scriptul poate identifica și exclude blocurile de cod și alte elemente non-traductibile, asigurându-se astfel că textul tradus rămâne fidel originalului.

Funcționalități Cheie

  1. Traducere Precisă cu GPT-4: Scriptul folosește modelul GPT-4 de la OpenAI pentru a traduce textul din franceză în engleză, asigurând păstrarea calității și a nuanțelor conținutului original.
  2. Păstrarea Formatării: Blocurile de cod, URL-urile și căile imaginilor sunt identificate și lăsate intacte în timpul traducerii, garantând păstrarea formatei originale.
  3. Flexibilitate Multilingvă: Scriptul este conceput pentru a fi ușor de adaptat pentru diferite limbi sursă și țintă, permițând o mare varietate de aplicații multilingve.
  4. Suport pentru Fișiere Markdown: Capacitatea de a traduce documente scrise în Markdown, păstrând structura și formatarea specifică.
  5. Automatizarea Traducerii Directoarelor: Traducerea automată a fișierelor Markdown găsite într-un director dat și în subdirectoarele acestuia, facilitând gestionarea unui volum mare de conținut.
  6. Adăugarea Automată a Notei de Traducere: Adaugă automat o notă de traducere la sfârșitul documentelor traduse, indicând modelul GPT utilizat pentru traducere.
  7. Configurare și Personalizare Ușoară: Setări implicite personalizabile pentru cheia API, modelul GPT, limbile sursă și țintă, și directoarele de fișiere, oferind o mare flexibilitate în utilizare.
  8. Raport de Performanță : Scriptul oferă feedback despre timpul necesar pentru a traduce fiecare fișier, permițând monitorizarea performanței acestuia.

Codul scriptului

Codul este disponibil și aici: 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()

Detalii despre script

Importarea modulelor

Mai întâi, avem câteva importuri de module necesare, cum ar fi os, argparse, time și re. Aceste module sunt utilizate pentru a efectua operațiuni pe sistemul de fișiere, analiza argumentele din linia de comandă, măsura timpul de execuție și efectua operațiuni de căutare și înlocuire a textului.

Constante

Apoi, avem constante definite, cum ar fi DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR și DEFAULT_TARGET_DIR. Aceste constante reprezintă valorile implicite utilizate în script, dar pot fi modificate specificând argumente din linia de comandă.

Funcția translate_with_openai

Apoi, avem funcția translate_with_openai. Această funcție ia un text, un obiect client OpenAI și argumente ca parametri. Folosește API-ul OpenAI pentru a traduce textul din limba sursă în limba țintă. Iată cum funcționează:

  1. Funcția folosește o expresie regulată pentru a detecta și stoca blocurile de cod în text. Aceste blocuri de cod sunt delimitate de trei backtick-uri (). Blocurile de cod sunt stocate într-o listă numită code_blocks`.
  2. Apoi, funcția înlocuiește blocurile de cod cu substituenți în text. Substituenții sunt șiruri de caractere de forma #CODEBLOCK{index}#, unde index este indicele blocului de cod corespunzător din lista code_blocks.
  3. Funcția creează un mesaj pentru API-ul OpenAI. Acest mesaj conține două părți: un mesaj de sistem care indică API-ului să traducă textul din limba sursă în limba țintă lăsând elemente precum URL-urile, căile imaginilor și blocurile de cod neschimbate, și un mesaj de utilizator care conține textul de tradus.
  4. Funcția trimite cererea de traducere la API folosind metoda client.chat.completions.create(). Specifică modelul de utilizat și mesajele de tradus.
  5. Răspunsul API-ului conține textul tradus. Funcția recuperează textul tradus și înlocuiește substituenții cu blocurile de cod originale.
  6. În final, funcția returnează textul tradus.

Funcția add_translation_note

Apoi, avem funcția add_translation_note. Această funcție adaugă o notă de traducere într-un document. Ia un obiect client OpenAI și argumente ca parametri. Iată cum funcționează:

  1. Funcția creează o notă de traducere în franceză folosind variabila translation_note_fr.
  2. Apoi, funcția folosește funcția translate_with_openai pentru a traduce nota de traducere utilizând API-ul OpenAI. Argumentele trecute la translate_with_openai includ nota de traducere în franceză și celelalte argumente.
  3. Funcția formatează nota de traducere tradusă prin adăugarea de caractere de formatare.
  4. În final, funcția returnează nota de traducere formatată.

Funcția translate_markdown_file

Apoi, avem funcția translate_markdown_file. Această funcție ia calea unui fișier Markdown de intrare, calea unui fișier de ieșire, un obiect client OpenAI și argumente ca parametri. Ea traduce conținutul fișierului Markdown folosind API-ul de traducere OpenAI și scrie conținutul tradus în fișierul de ieșire.

Acest script nu doar că a îmbunătățit accesibilitatea articolelor mele de blog, dar a deschis și calea către noi posibilități de automatizare în domeniul creării de conținut multilingv. Este un pas înainte către un schimb mai larg și mai inclusiv al cunoștințelor. ## Experiență de Utilizare și Timp de Procesare

Exemple de Utilizare

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

Timp de Procesare

  • Engleză: Aproximativ 4 minute (248.70 secunde)
  • Spaniolă: Aproximativ 4.7 minute (284.05 secunde)
  • Total cumulat: Aproximativ 8.7 minute (532.75 secunde) Aceste timpuri demonstrează eficiența și rapiditatea scriptului.

Rezultate

Puteți accesa acum rezultatele acestor generații de conținut tradus pe aceste linkuri:

Acest post de blog este un condens al experienței mele în automatizarea traducerilor cu AI. Este o dovadă că, atunci când asociem programarea cu inteligența artificială, posibilitățile sunt aproape nelimitate, deschizând orizonturi noi și incitante în domeniul împărtășirii cunoștințelor și accesibilității conținutului.

Acest document a fost tradus din versiunea fr în limba ro folosind modelul gpt-4o. Pentru mai multe informații despre procesul de traducere, consultați https://gitlab.com/jls42/ai-powered-markdown-translator