En este artículo, comparto un script de Python desarrollado como una Prueba de Concepto (POC) para automatizar la traducción de las entradas de mi blog, utilizando el modelo de lenguaje GPT-4 de OpenAI. Este script está específicamente diseñado para procesar archivos Markdown en la estructura de mi blog Hugo, facilitando la gestión multilingüe de mis entradas. Están disponibles en Inglés, Español y Chino.

Introducción al Proyecto: Fusionar IA y Automatización para Mi Blog

Este proyecto de automatización de la traducción de mis entradas de blog fue iniciado por mi creciente fascinación por la inteligencia artificial. Inspirado por mis experiencias iniciales con las APIs de OpenAI GPT-4 y Mistral AI, me atrajo la idea de materializar estas tecnologías en un proyecto práctico, ofreciendo un valor tangible a mi blog. No solo se trataba de dominar las herramientas de IA, sino también de fusionar la automatización e innovación para enriquecer mi espacio digital.

Este proyecto se transformó en una aventura donde la IA no era solo un tema de escritura, sino un socio activo en el desarrollo. La idea de traducir mis entradas de manera simple y eficiente con la IA, al mismo tiempo que exploraba sus capacidades de automatización, abría perspectivas fascinantes. Se trataba de una oportunidad de trascender barreras lingüísticas, haciendo mi contenido accesible a una audiencia más amplia, al mismo tiempo que navegaba en el campo en constante evolución de la inteligencia artificial.

El Desafío

El desafío principal era crear un script capaz de traducir con precisión y conservar el formato original de las entradas, en particular los bloques de código, los enlaces y las imágenes. Otro desafío era asegurarse de que el script pudiera ser fácilmente adaptado para admitir diferentes idiomas. También debía ser capaz de considerar esta estructura:

├── 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 Solución: Un Script Innovador

Diseñé un script de Python que se basa en la API de OpenAI GPT-4 para traducir el texto, al tiempo que preserva los elementos no textuales. Gracias a una serie de reglas de procesamiento y el uso de marcadores de posición, el script puede identificar y excluir los bloques de código y otros elementos no traducibles, garantizando así que el contenido traducido permanezca fiel al original.

Características Clave

  1. Traducción Precisa con GPT-4: El script utiliza el modelo GPT-4 de OpenAI para traducir el texto del francés al inglés, asegurando de conservar la calidad y la sutileza del contenido original.
  2. Preservación del Formato: Los bloques de código, las URL y las rutas de imagen se identifican y dejan intactos durante la traducción, garantizando que el formato original se preserve.
  3. Flexibilidad Multilingüe: El script está diseñado para ser fácilmente adaptable a diferentes idiomas fuente y objetivo, permitiendo una gran variedad de aplicaciones multilingües.
  4. Compatibilidad con Archivos Markdown: Capacidad de traducir documentos escritos en Markdown, manteniendo su estructura y formato específicos.
  5. Automatización de la Traducción de Directorio: Traducción automática de archivos Markdown encontrados en un directorio dado y sus subdirectorios, facilitando la gestión de grandes volúmenes de contenido.
  6. Integración de Nota de Traducción: Agrega automáticamente una nota de traducción al final de los documentos traducidos, indicando el modelo GPT utilizado para la traducción.
  7. Configuración y Personalización Fáciles: Parámetros predeterminados personalizables para la clave API, el modelo GPT, los idiomas fuente y objetivo, y los directorios de archivos, ofreciendo gran flexibilidad de uso. Informe de Rendimiento: El script proporciona información sobre el tiempo necesario para traducir cada archivo, lo que permite monitorear su rendimiento.

Código del script

El código está disponible aquí: 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()

Enfoque en el script

Importaciones de módulos

Primero, tenemos algunas importaciones de módulos necesarios, tales como os, argparse, time y re. Estos módulos se utilizan para realizar operaciones en el sistema de archivos, analizar argumentos de línea de comandos, medir el tiempo de ejecución y realizar operaciones de búsqueda y reemplazo de texto.

Constantes

A continuación, tenemos constantes definidas, tales como DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR y DEFAULT_TARGET_DIR. Estas constantes representan los valores predeterminados utilizados en el script, pero pueden ser modificados especificando argumentos de línea de comandos.

Función translate_with_openai

A continuación, tenemos la función translate_with_openai. Esta función toma un texto, un objeto cliente OpenAI y argumentos como parámetros. Utiliza la API de OpenAI para traducir el texto del idioma fuente al idioma objetivo. Aquí está cómo funciona:

  1. La función utiliza una expresión regular para detectar y almacenar bloques de código en el texto. Estos bloques de código están delimitados por tres acentos graves (). Los bloques de código se almacenan en una lista llamada code_blocks`.
  2. A continuación, la función reemplaza los bloques de código por marcadores de posición en el texto. Los marcadores de posición son cadenas del tipo #CODEBLOCK{index}#, donde index es el índice del bloque de código correspondiente en la lista code_blocks.
  3. La función crea un mensaje para la API de OpenAI. Este mensaje contiene dos partes: un mensaje del sistema que indica a la API que traduzca el texto del idioma fuente al idioma objetivo dejando las URL, las rutas de imagen y los bloques de código sin cambios, y un mensaje de usuario que contiene el texto a traducir.
  4. La función envía la solicitud de traducción a la API utilizando el método client.chat.completions.create(). Especifica el modelo a usar y los mensajes a traducir.
  5. La respuesta de la API contiene el texto traducido. La función recupera el texto traducido y reemplaza los marcadores de posición por los bloques de código originales.
  6. Finalmente, la función devuelve el texto traducido.

Función add_translation_note

A continuación, tenemos la función add_translation_note. Esta función agrega una nota de traducción a un documento. Toma un objeto cliente OpenAI y argumentos como parámetros. Aquí está cómo funciona:

  1. La función crea una nota de traducción en francés utilizando la variable translation_note_fr.
  2. A continuación, la función utiliza la función translate_with_openai para traducir la nota de traducción utilizando la API de OpenAI. Los argumentos pasados a translate_with_openai incluyen la nota de traducción en francés y otros argumentos.
  3. La función formatea la nota de traducción traducida agregando caracteres de formato.
  4. Finalmente, la función devuelve la nota de traducción con formato.

Función translate_markdown_file

A continuación, tenemos la función translate_markdown_file. Esta función toma la ruta de un archivo de entrada Markdown, la ruta de un archivo de salida, un objeto cliente OpenAI y argumentos como parámetros. Traduce el contenido del archivo Markdown utilizando la API de traducción de OpenAI y escribe el contenido traducido en el archivo de salida.

Este script no solo ha mejorado la accesibilidad de mis artículos de blog, sino que también ha abierto el camino a nuevas posibilidades de automatización en el campo de la creación de contenido multilingüe. Es un paso adelante hacia un intercambio más amplio e inclusivo de conocimientos. ## Experiencia de Uso y Tiempo de Procesamiento

Ejemplos de Uso

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

Tiempo de Procesamiento

  • Inglés: Aproximadamente 4 minutos (248.70 segundos)
  • Español: Aproximadamente 4.7 minutos (284.05 segundos)
  • Total acumulado: Aproximadamente 8.7 minutos (532.75 segundos) Estos tiempos demuestran la eficacia y la rapidez del script.

Resultados

Ahora puede acceder a los resultados de estas generaciones de contenido traducido en estos enlaces:

Esta publicación del blog es un resumen de mi experiencia en la automatización de la traducción con IA. Es una prueba de que, cuando se combinan la programación y la inteligencia artificial, las posibilidades son casi ilimitadas, abriendo nuevos y emocionantes horizontes en el campo del intercambio de conocimientos y la accesibilidad del contenido.

**Este documento ha sido traducido desde la versión fr por el modelo mistral-medium.

Note: “fr” stands for French, so “la versión fr” means “the French version”. “Mistral-medium” is a medium-sized language model developed by Hugging Face, so “por el modelo mistral-medium” means “by the mistral-medium model”.**