Neste artigo, compartilho um script Python desenvolvido como uma Prova de Conceito (POC) para automatizar a tradução dos posts do meu blog, utilizando o modelo de linguagem GPT-4 da OpenAI. Este script é especificamente projetado para tratar arquivos Markdown na estrutura do meu blog Hugo, facilitando a gestão multilíngue dos meus artigos. Eles estão disponíveis em Inglês, Espanhol e Chinês.

Iniciação ao Projeto: Fundir IA e Automação para Meu Blog

Este projeto de automação da tradução dos meus artigos de blog foi iniciado pela minha crescente fascinação pela inteligência artificial. Inspirado por minhas experiências preliminares com as APIs OpenAI GPT-4 e Mistral AI, fui atraído pela ideia de concretizar essas tecnologias em um projeto prático, oferecendo um valor tangível ao meu blog. Não era apenas uma busca por dominar as ferramentas de IA, mas também um desejo de fundir automação e inovação para enriquecer meu espaço digital.

Este projeto se transformou em uma aventura onde a IA não era apenas um assunto de escrita, mas sim um parceiro ativo no desenvolvimento. A ideia de traduzir meus artigos de maneira simples e eficiente com a IA, enquanto explorava suas capacidades de automação, abria perspectivas fascinantes. Tratava-se de uma oportunidade de transcender as barreiras linguísticas, tornando meu conteúdo acessível a um público mais amplo, enquanto navegava no domínio em constante evolução da inteligência artificial.

O Desafio

O desafio principal era criar um script capaz de traduzir com precisão e conservar a formatação original dos artigos, incluindo blocos de código, links e imagens. Outro desafio era garantir que o script pudesse ser facilmente adaptado para suportar diferentes idiomas. Ele também precisava ser capaz de levar em conta esta estrutura:

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

A Solução: Um Script Inovador

Concebi um script Python que se baseia na API OpenAI GPT-4 para traduzir o texto enquanto preserva os elementos não-textuais. Graças a uma série de regras de processamento e ao uso de placeholders, o script pode identificar e excluir os blocos de código e outros elementos não traduzíveis, garantindo que o conteúdo traduzido permaneça fiel ao original.

Funcionalidades Chave

  1. Tradução Precisa com GPT-4: O script utiliza o modelo GPT-4 da OpenAI para traduzir o texto do francês para o inglês, assegurando a manutenção da qualidade e nuance do conteúdo original.
  2. Preservação da Formatação: Os blocos de código, URLs e caminhos de imagem são identificados e deixados intactos durante a tradução, garantindo que a formatação original seja preservada.
  3. Flexibilidade Multilíngue: O script foi projetado para ser facilmente adaptável a diferentes línguas de origem e destino, permitindo uma grande variedade de aplicações multilíngues.
  4. Suporte a Arquivos Markdown: Capacidade de traduzir documentos escritos em Markdown, mantendo sua estrutura e formatação específicas.
  5. Automação da Tradução de Diretórios: Tradução automática dos arquivos Markdown encontrados em um diretório fornecido e seus subdiretórios, facilitando a gestão de grandes volumes de conteúdo.
  6. Integração de Nota de Tradução: Adiciona automaticamente uma nota de tradução ao final dos documentos traduzidos, indicando o modelo GPT usado para a tradução.
  7. Configuração e Personalização Fáceis: Configurações padrão personalizáveis para a chave API, o modelo GPT, as línguas de origem e destino, e os diretórios de arquivos, oferecendo grande flexibilidade de uso.
  8. Relatório de Desempenho: O script fornece um feedback sobre o tempo necessário para traduzir cada arquivo, permitindo monitorar seu desempenho.

Código do script

O código está disponível também aqui: 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()

Detalhes do script

Importações de módulos

Primeiramente, temos algumas importações de módulos necessários, como os, argparse, time e re. Esses módulos são usados para realizar operações no sistema de arquivos, analisar argumentos de linha de comando, medir o tempo de execução e realizar operações de busca e substituição de texto.

Constantes

Em seguida, temos constantes definidas, como DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR e DEFAULT_TARGET_DIR. Essas constantes representam os valores padrão usados no script, mas podem ser alteradas especificando argumentos de linha de comando.

Função translate_with_openai

Em seguida, temos a função translate_with_openai. Esta função recebe um texto, um objeto cliente OpenAI e argumentos como parâmetros. Ela usa a API OpenAI para traduzir o texto do idioma de origem para o idioma alvo. Veja como funciona:

  1. A função utiliza uma expressão regular para detectar e armazenar blocos de código no texto. Esses blocos de código são delimitados por crases triplas (). Os blocos de código são armazenados em uma lista chamada code_blocks`.
  2. Em seguida, a função substitui os blocos de código por placeholders no texto. Os placeholders são cadeias da forma #CODEBLOCK{index}#, onde index é o índice do bloco de código correspondente na lista code_blocks.
  3. A função cria uma mensagem para a API OpenAI. Esta mensagem contém duas partes: uma mensagem de sistema que indica à API para traduzir o texto do idioma de origem para o idioma alvo, deixando elementos como URLs, caminhos de imagem e blocos de código inalterados, e uma mensagem de usuário que contém o texto a ser traduzido.
  4. A função envia a solicitação de tradução à API usando o método client.chat.completions.create(). Ela especifica o modelo a ser usado e as mensagens a serem traduzidas.
  5. A resposta da API contém o texto traduzido. A função recupera o texto traduzido e substitui os placeholders pelos blocos de código originais.
  6. Finalmente, a função retorna o texto traduzido.

Função add_translation_note

Em seguida, temos a função add_translation_note. Esta função adiciona uma nota de tradução a um documento. Ela recebe um objeto cliente OpenAI e argumentos como parâmetros. Veja como funciona:

  1. A função cria uma nota de tradução em francês usando a variável translation_note_fr.
  2. Em seguida, a função usa a função translate_with_openai para traduzir a nota de tradução usando a API OpenAI. Os argumentos passados para translate_with_openai incluem a nota de tradução em francês e os outros argumentos.
  3. A função formata a nota de tradução traduzida adicionando caracteres de formatação.
  4. Finalmente, a função retorna a nota de tradução formatada.

Função translate_markdown_file

Em seguida, temos a função translate_markdown_file. Esta função recebe o caminho de um arquivo Markdown de entrada, o caminho de um arquivo de saída, um objeto cliente OpenAI e argumentos como parâmetros. Ela traduz o conteúdo do arquivo Markdown usando a API de tradução OpenAI e escreve o conteúdo traduzido no arquivo de saída.

Este script não apenas melhorou a acessibilidade dos meus artigos de blog, mas também abriu caminho para novas possibilidades de automação no campo da criação de conteúdo multilíngue. É um passo à frente em direção a uma maior e mais inclusiva disseminação do conhecimento. ## Experiência de Uso e Tempo de Processamento

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

Tempo de Processamento

  • Inglês: Cerca de 4 minutos (248.70 segundos)
  • Espanhol: Cerca de 4.7 minutos (284.05 segundos)
  • Total acumulado: Cerca de 8.7 minutos (532.75 segundos) Esses tempos demonstram a eficiência e a rapidez do script.

Resultados

Você pode acessar os resultados dessas gerações de conteúdo traduzido nestes links:

Este post de blog é um resumo da minha experiência em automação de tradução com IA. É uma prova de que, quando se associa a programação à inteligência artificial, as possibilidades são quase ilimitadas, abrindo novos e empolgantes horizontes no campo da disseminação de conhecimento e da acessibilidade do conteúdo.

Este documento foi traduzido da versão fr para a língua pt usando o modelo gpt-4o. Para mais informações sobre o processo de tradução, consulte https://gitlab.com/jls42/ai-powered-markdown-translator