Szukaj

infrastructureblogia

Rewolucjonizowanie tłumaczeń wpisów na blogu za pomocą SI

Rewolucjonizowanie tłumaczeń wpisów na blogu za pomocą SI

W tym artykule dzielę się skryptem Pythona opracowanym jako Proof of Concept (POC) do automatyzacji tłumaczeń wpisów na moim blogu, wykorzystując model językowy GPT-4 od OpenAI. Ten skrypt został specjalnie zaprojektowany do przetwarzania plików Markdown, ułatwiając wielojęzyczne zarządzanie moimi artykułami. Tłumaczenia są dostępne za pomocą selektora języka u góry strony.

Rozpoczęcie projektu: Połączenie SI i automatyzacji dla mojego bloga

Projekt automatyzacji tłumaczeń moich artykułów zaczął się od mojego rosnącego zainteresowania sztuczną inteligencją. Zainspirowany wstępnymi doświadczeniami z API OpenAI GPT-4 i Mistral AI, zapragnąłem wdrożyć te technologie w praktycznym projekcie, przynoszącym wymierną wartość mojemu blogowi. Nie chodziło tylko o opanowanie narzędzi AI, ale także o chęć połączenia automatyzacji i innowacji, by wzbogacić moją przestrzeń cyfrową.

Projekt przemienił się w przygodę, w której SI nie było tylko tematem do pisania, lecz aktywnym partnerem w rozwoju. Pomysł prostego i skutecznego tłumaczenia artykułów za pomocą SI, jednocześnie eksplorując jej możliwości automatyzacji, otwierał fascynujące perspektywy. Była to okazja do przekraczania barier językowych, udostępniając treści szerszej publiczności, jednocześnie poruszając się w ciągle zmieniającym się obszarze sztucznej inteligencji.

Wyzwanie

Głównym wyzwaniem było stworzenie skryptu zdolnego do dokładnego tłumaczenia przy zachowaniu oryginalnego formatowania artykułów, w szczególności bloków kodu, linków i obrazów. Kolejnym wyzwaniem było zapewnienie, że skrypt będzie łatwo dostosowywalny do obsługi różnych języków. Musiał także być w stanie 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 Pythona oparty na API OpenAI GPT-4 do tłumaczenia tekstu przy zachowaniu elementów nietekstowych. Dzięki zestawowi reguł przetwarzania i użyciu symboli zastępczych, skrypt potrafi identyfikować i wykluczać bloki kodu oraz inne elementy niepodlegające tłumaczeniu, zapewniając, że przetłumaczona zawartość pozostaje wierna oryginałowi.

Kluczowe funkcje

  1. Precyzyjne tłumaczenie z 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 oryginału.
  2. Zachowanie formatowania : Bloki kodu, adresy URL i ścieżki do obrazów są identyfikowane i pozostawiane bez zmian podczas tłumaczenia, zapewniając zachowanie oryginalnego formatowania.
  3. Elastyczność wielojęzyczna : Skrypt jest zaprojektowany tak, by łatwo adaptować go do różnych języków źródłowych i docelowych, umożliwiając szerokie zastosowania wielojęzyczne.
  4. Obsługa plików Markdown : Możliwość tłumaczenia dokumentów napisanych w Markdown, zachowując ich strukturę i formatowanie.
  5. Automatyzacja tłumaczenia katalogów : Automatyczne tłumaczenie plików Markdown znalezionych w danym katalogu i jego podkatalogach, ułatwiając zarządzanie dużymi ilościami treści.
  6. Wstawianie noty o tłumaczeniu : Automatyczne dodawanie noty o tłumaczeniu na końcu przetłumaczonych dokumentów, wskazującej użyty model GPT.
  7. Łatwa konfiguracja i personalizacja : Domyślne ustawienia, które można zmieniać dla klucza API, modelu GPT, języków źródłowego i docelowego oraz katalogów plików, zapewniając dużą elastyczność użytkowania.
  8. Raport wydajności : Skrypt dostarcza informacje o czasie potrzebnym na przetłumaczenie każdego pliku, co pozwala monitorować jego wydajność.

Kod skryptu

Le code est disponible aussi ici : Tłumacz Markdown wspomagany przez AI

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

Szczegóły skryptu

Importy 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żą do operacji na systemie plików, analizowania argumentów linii poleceń, mierzenia czasu wykonania oraz przeprowadzania operacji wyszukiwania i zastępowania 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ą domyślne wartości używane w skrypcie, które można zmienić, podając argumenty z linii 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. Te bloki kodu są delimitowane potrójnymi backtickami (). Les blocs de code sont stockés dans une liste appelée code_blocks`).
  2. Następnie funkcja zastępuje bloki kodu symbolami zastępczymi w tekście. Placeholders mają postać #CODEBLOCK{index}#, gdzie index jest indeksem odpowiadającym blokowi kodu w liście code_blocks.
  3. Funkcja tworzy wiadomość dla API OpenAI. Ta wiadomość zawiera dwie części : wiadomość systemową, która instruuje API, aby przetłumaczyło tekst z języka źródłowego na język docelowy pozostawiając elementy takie jak URL-e, ścieżki obrazów i bloki kodu niezmienione, oraz wiadomość użytkownika, która zawiera tekst do przetłumaczenia.
  4. Funkcja wysyła żądanie tłumaczenia do API przy użyciu metody client.chat.completions.create(). Określa model do użycia oraz wiadomości do przetłumaczenia.
  5. Odpowiedź z API zawiera przetłumaczony tekst. Funkcja pobiera przetłumaczony tekst i zastępuje symbole zastępcze oryginalnymi blokami kodu.
  6. Na koniec funkcja zwraca przetłumaczony tekst.

Funkcja add_translation_note

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

  1. Funkcja tworzy notę 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 noty przy użyciu API OpenAI. Argumenty przekazywane do translate_with_openai obejmują francuską notę oraz pozostałe argumenty.
  3. Funkcja formatuje przetłumaczoną notę, dodając znaki formatowania.
  4. Na końcu funkcja zwraca sformatowaną notę o tłumaczeniu.

Funkcja translate_markdown_file

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

Ten skrypt nie tylko zwiększył 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 udostępniania wiedzy.

Doświadczenie użytkownika 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 minutes (248.70 secondes)
  • Hiszpański : Około 4.7 minutes (284.05 secondes)
  • Łącznie : Około 8.7 minutes (532.75 secondes) Te czasy pokazują wydajność i szybkość skryptu.

Wyniki

Uwaga : Ten przykład ilustruje działanie skryptu na dawnej strukturze Hugo bloga. Blog został od tego czasu przeniesiony do Astro z nową wielojęzyczną architekturą. Tłumaczenia są teraz dostępne za pośrednictwem zintegrowanego selektora języka.

Ten wpis na blogu jest skrótem moich doświadczeń w automatyzacji tłumaczeń za pomocą SI. To dowód na to, że łącząc programowanie z sztuczną inteligencją, możliwości są niemal nieograniczone, otwierając nowe i ekscytujące horyzonty w dziedzinie dzielenia się wiedzą i dostępności treści.

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