W tym artykule dzielę się skryptem Python opracowanym jako Proof of Concept (POC) do automatyzacji tłumaczeń postów mojego bloga, wykorzystując model językowy GPT-4 od OpenAI. Ten skrypt jest specjalnie zaprojektowany do przetwarzania plików Markdown w strukturze mojego bloga Hugo, ułatwiając zarządzanie wielojęzycznymi artykułami. Są one dostępne po Angielsku, Hiszpańsku i Chińsku.

Rozpoczęcie Projektu: Połączenie SI i Automatyzacji na Moim Blogu

Ten projekt automatyzacji tłumaczenia moich artykułów na blogu został zainicjowany przez moją rosnącą fascynację sztuczną inteligencją. Zainspirowany moimi wczesnymi doświadczeniami z API OpenAI GPT-4 i Mistral AI, zainteresowałem się pomysłem przeniesienia tych technologii do praktycznego projektu, oferując rzeczywistą wartość mojemu blogowi. To nie była tylko kwestia opanowania narzędzi SI, ale także pragnienie połączenia automatyzacji i innowacji, aby wzbogacić moją przestrzeń cyfrową.

Ten projekt przekształcił się w przygodę, w której SI nie była tylko tematem do pisania, ale aktywnym partnerem w rozwoju. Pomysł tłumaczenia moich artykułów w prosty i efektywny sposób za pomocą SI, przy jednoczesnym eksplorowaniu jej możliwości automatyzacji, otwierał fascynujące perspektywy. Była to okazja do przekroczenia barier językowych, udostępniając moją treść szerszej publiczności, przy jednoczesnym poruszaniu się w stale ewoluującej dziedzinie sztucznej inteligencji.

Wyzwanie

Głównym wyzwaniem było stworzenie skryptu zdolnego do dokładnego tłumaczenia i zachowania oryginalnego formatowania artykułów, w szczególności bloków kodu, linków i obrazów. Kolejnym wyzwaniem było zapewnienie, że skrypt można łatwo dostosować do obsługi różnych języków. Musiał również uwzględnić tę 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

Rozwiązanie: Innowacyjny Skrypt

Stworzyłem skrypt Python, który opiera się na API OpenAI GPT-4, aby tłumaczyć tekst, jednocześnie zachowując nietekstowe elementy. Dzięki serii reguł przetwarzania i wykorzystaniu symboli zastępczych skrypt może identyfikować i wykluczać bloki kodu oraz inne nietłumaczalne elementy, zapewniając, że przetłumaczona treść pozostanie wierna oryginałowi.

Kluczowe Funkcje

  1. Dokładne Tłumaczenie za pomocą GPT-4: Skrypt wykorzystuje model GPT-4 od OpenAI do tłumaczenia tekstu z francuskiego na angielski, dbając o zachowanie jakości i niuansów oryginalnej treści.
  2. Zachowanie Formatowania: Bloki kodu, URL-e i ścieżki obrazów są identyfikowane i pozostają nienaruszone podczas tłumaczenia, zapewniając zachowanie oryginalnego formatowania.
  3. Elastyczność Wielojęzyczna: Skrypt jest zaprojektowany tak, aby można go było łatwo dostosować do różnych języków źródłowych i docelowych, co umożliwia szeroką gamę zastosowań wielojęzycznych.
  4. Obsługa Plików Markdown: Możliwość tłumaczenia dokumentów napisanych w Markdown, przy zachowaniu ich specyficznej struktury i formatowania.
  5. Automatyzacja Tłumaczenia Katalogów: Automatyczne tłumaczenie plików Markdown znajdujących się w danym katalogu i jego podkatalogach, ułatwiające zarządzanie dużymi wolumenami treści.
  6. Integracja Notki Tłumaczeniowej: Automatyczne dodawanie notki tłumaczeniowej na końcu przetłumaczonych dokumentów, wskazującej model GPT użyty do tłumaczenia.
  7. Łatwa Konfiguracja i Personalizacja: Domyślne ustawienia konfiguracyjne dla klucza API, modelu GPT, języków źródłowych i docelowych oraz katalogów plików, oferujące dużą elastyczność użytkowania.
  8. Raport Wydajności : Skrypt dostarcza informacji zwrotnej na temat czasu potrzebnego na przetłumaczenie każdego pliku, umożliwiając monitorowanie jego wydajności.

Kod skryptu

Kod jest również dostępny tutaj: 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()

Skupienie na skrypcie

Importowanie modułów

Na początku mamy kilka niezbędnych importów modułów, takich jak os, argparse, time i re. Moduły te są używane do operacji na systemie plików, analizowania argumentów wiersza poleceń, mierzenia czasu wykonania oraz wykonywania operacji wyszukiwania i zamiany tekstu.

Stałe

Następnie mamy zdefiniowane stałe takie jak DEFAULT_API_KEY, DEFAULT_MODEL, DEFAULT_SOURCE_LANG, DEFAULT_TARGET_LANG, DEFAULT_SOURCE_DIR i DEFAULT_TARGET_DIR. Stałe te reprezentują wartości domyślne używane w skrypcie, ale mogą być modyfikowane poprzez określenie argumentów wiersza poleceń.

Funkcja translate_with_openai

Następnie mamy funkcję translate_with_openai. Funkcja ta przyjmuje tekst, obiekt klienta OpenAI i argumenty jako parametry. Używa API OpenAI do tłumaczenia tekstu z języka źródłowego na język docelowy. Oto jak to działa:

  1. Funkcja używa wyrażenia regularnego do wykrywania i przechowywania bloków kodu w tekście. Bloki te są delimitowane przez potrójne backticki (). Bloki kodu są przechowywane na liście zwanej code_blocks`.
  2. Następnie funkcja zastępuje bloki kodu placeholderami w tekście. Placehokdery są łańcuchami postaci #CODEBLOCK{index}#, gdzie index jest indeksem odpowiadającego bloku kodu na liście code_blocks.
  3. Funkcja tworzy wiadomość do API OpenAI. Wiadomość ta zawiera dwie części: wiadomość systemową, która instruuje API do tłumaczenia tekstu z języka źródłowego na język docelowy, pozostawiając elementy takie jak URL-e, ścieżki do obrazów i bloki kodu bez zmian, oraz wiadomość użytkownika, która zawiera tekst do przetłumaczenia.
  4. Funkcja wysyła żądanie tłumaczenia do API za pomocą metody client.chat.completions.create(). Specyfikuje model do użycia i wiadomości do przetłumaczenia.
  5. Odpowiedź API zawiera przetłumaczony tekst. Funkcja pobiera przetłumaczony tekst i zastępuje placeholdery oryginalnymi blokami kodu.
  6. Na końcu funkcja zwraca przetłumaczony tekst.

Funkcja add_translation_note

Następnie mamy funkcję add_translation_note. Funkcja ta dodaje notatkę o tłumaczeniu do dokumentu. Przyjmuje obiekt klienta OpenAI i argumenty jako parametry. Oto jak to działa:

  1. Funkcja tworzy notatkę o tłumaczeniu w języku francuskim, używając zmiennej translation_note_fr.
  2. Następnie funkcja używa funkcji translate_with_openai do przetłumaczenia notki o tłumaczeniu przy użyciu API OpenAI. Argumenty przekazane do translate_with_openai zawierają notkę o tłumaczeniu w języku francuskim oraz inne argumenty.
  3. Funkcja formatuje przetłumaczoną notkę o tłumaczeniu, dodając znaki formatowania.
  4. Na końcu funkcja zwraca sformatowaną notkę o tłumaczeniu.

Funkcja translate_markdown_file

Następnie mamy funkcję translate_markdown_file. Funkcja ta przyjmuje ścieżkę do pliku Markdown wejściowego, ścieżkę do pliku wyjściowego, obiekt klienta OpenAI i argumenty jako parametry. Tłumaczy zawartość pliku Markdown przy użyciu API tłumaczenia OpenAI i zapisuje przetłumaczoną zawartość do pliku wyjściowego.

Ten skrypt nie tylko poprawił dostępność moich artykułów na blogu, ale także otworzył drogę do nowych możliwości automatyzacji w zakresie tworzenia treści wielojęzycznych. To krok naprzód w kierunku szerszego i bardziej inkluzywnego dzielenia się wiedzą. ## Doświadczenie użytkowania i czas przetwarzania

Przykłady użycia

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

Czas przetwarzania

  • Angielski: Około 4 minuty (248,70 sekund)
  • Hiszpański: Około 4,7 minuty (284,05 sekund)
  • Całkowity czas sumaryczny: Około 8,7 minuty (532,75 sekund) Te czasy pokazują efektywność i szybkość skryptu.

Wyniki

Możesz teraz uzyskać dostęp do wyników tych wygenerowanych treści pod tymi linkami:

Ten wpis na blogu jest podsumowaniem mojego doświadczenia w automatyzacji tłumaczeń za pomocą sztucznej inteligencji. Jest to dowód na to, że kiedy połączymy programowanie z sztuczną inteligencją, możliwości są prawie nieograniczone, otwierając nowe i ekscytujące perspektywy w dziedzinie udostępniania wiedzy i dostępności treści.

Ten dokument został przetłumaczony z wersji fr na język pl przy użyciu modelu gpt-4o. Aby uzyskać więcej informacji na temat procesu tłumaczenia, odwiedź https://gitlab.com/jls42/ai-powered-markdown-translator