이 기사에서는 OpenAI의 GPT-4 언어 모델을 사용하여 블로그 게시물의 번역을 자동화하기 위해 개발된 Proof of Concept (POC) Python 스크립트를 공유합니다. 이 스크립트는 특히 제 Hugo 블로그 구조에서 Markdown 파일을 처리하도록 설계되어 다국어 관리가 용이합니다. 이들은 영어, 스페인어, 중국어로 제공됩니다.
프로젝트 시작: 내 블로그를 위한 AI와 자동화의 융합
이 블로그 게시물 번역 자동화 프로젝트는 인공지능에 대한 나의 증가하는 관심에서 시작되었습니다. OpenAI GPT-4와 Mistral AI API를 사용한 초기 경험에서 영감을 받아, 이러한 기술을 실질적인 프로젝트로 실현하여 내 블로그에 실질적인 가치를 제공하는 아이디어에 매료되었습니다. 이것은 단순히 AI 도구를 숙달하는 탐구가 아니라 내 디지털 공간을 풍부하게 하기 위한 자동화와 혁신을 융합하려는 열망이었습니다.
이 프로젝트는 AI가 단순한 글쓰기 주제가 아니라 개발의 적극적인 파트너 역할을 한 모험으로 변모했습니다. AI를 사용하여 내 게시물을 간편하고 효율적으로 번역하면서 자동화 기능을 탐험하는 아이디어는 매혹적인 전망을 열어주었습니다. 이는 언어 장벽을 초월하여 내 콘텐츠를 더 넓은 청중에게 접근 가능하게 만드는 기회이자, 끊임없이 진화하는 인공지능 분야를 탐험하는 기회이기도 했습니다.
도전
주요 도전 과제는 코드 블록, 링크 및 이미지를 포함하여 기사의 원래 형식을 유지하면서 정확하게 번역할 수 있는 스크립트를 작성하는 것이었습니다. 또 다른 도전 과제는 다른 언어를 쉽게 지원할 수 있도록 스크립트를 조정할 수 있는 것이었습니다. 이 구조도 고려해야 했습니다:
├── 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
해법: 혁신적인 스크립트
저는 OpenAI GPT-4 API를 활용하여 텍스트를 번역하면서 비텍스트 요소를 보존하는 Python 스크립트를 설계했습니다. 일련의 처리 규칙과 플레이스홀더를 사용하여 스크립트는 코드 블록과 기타 번역할 수 없는 요소를 식별하고 제외할 수 있어 번역된 콘텐츠가 원본을 충실히 유지하도록 보장합니다.
주요 기능
- GPT-4와 함께하는 정확한 번역: 스크립트는 OpenAI의 GPT-4 모델을 사용하여 프랑스어 텍스트를 영어로 번역하면서 원래 콘텐츠의 품질과 뉘앙스를 유지합니다.
- 형식 보존: 코드 블록, URL 및 이미지 경로를 식별하고 번역 중 그대로 유지하여 원래 형식을 보존합니다.
- 다국어 유연성: 스크립트는 다양한 소스 및 타겟 언어에 쉽게 적응할 수 있도록 설계되어 다양한 다국어 응용 프로그램에 사용할 수 있습니다.
- Markdown 파일 지원: Markdown으로 작성된 문서를 번역하면서 구조와 형식을 유지할 수 있습니다.
- 디렉토리 번역 자동화: 지정된 디렉토리와 하위 디렉토리에서 찾은 Markdown 파일을 자동으로 번역하여 대량의 콘텐츠 관리를 용이하게 합니다.
- 번역 주석 통합: 번역된 문서 끝에 사용된 GPT 모델을 표시하는 번역 주석을 자동으로 추가합니다.
- 쉽고 쉬운 설정 및 맞춤화: API 키, GPT 모델, 소스 및 타겟 언어, 파일 디렉토리에 대한 기본 설정을 사용자 지정할 수 있어 사용의 유연성을 제공합니다.
- 성능 보고서: 스크립트는 각 파일을 번역하는 데 걸리는 시간에 대한 피드백을 제공하여 성능을 모니터링할 수 있게 합니다.
스크립트 코드
코드는 여기에서도 확인할 수 있습니다: 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()
스크립트 개요
모듈 임포트
먼저, os
, argparse
, time
, re
등 필요한 모듈 몇 가지를 임포트합니다. 이 모듈들은 파일 시스템 작업, 명령줄 인수 분석, 실행 시간 측정 및 텍스트 검색 및 교체 작업에 사용됩니다.
상수
다음으로, DEFAULT_API_KEY
, DEFAULT_MODEL
, DEFAULT_SOURCE_LANG
, DEFAULT_TARGET_LANG
, DEFAULT_SOURCE_DIR
, DEFAULT_TARGET_DIR
와 같은 상수들이 정의되어 있습니다. 이 상수들은 스크립트에서 사용되는 기본값을 나타내지만, 명령줄 인수를 지정하여 변경할 수 있습니다.
translate_with_openai
함수
다음으로, translate_with_openai
함수가 있습니다. 이 함수는 텍스트, OpenAI 클라이언트 객체 및 인수를 매개변수로 받아들입니다. 이 함수는 OpenAI API를 사용하여 텍스트를 원본 언어에서 대상 언어로 번역합니다. 작동 방식은 다음과 같습니다:
- 함수는 정규 표현식을 사용하여 텍스트 내의 코드 블록을 감지하고 저장합니다. 이 코드 블록들은 백틱 세 개(
)로 구분됩니다. 코드 블록은
code_blocks`라는 리스트에 저장됩니다. - 그런 다음 함수는 텍스트 내의 코드 블록을 플레이스홀더로 교체합니다. 플레이스홀더는
#CODEBLOCK{index}#
형식의 문자열이며, 여기서index
는code_blocks
리스트 내의 코드 블록의 인덱스입니다. - 함수는 OpenAI API에 보낼 메시지를 생성합니다. 이 메시지에는 시스템 메시지와 사용자 메시지의 두 부분이 포함됩니다. 시스템 메시지는 API에게 URL, 이미지 경로 및 코드 블록 등은 변경하지 않고 텍스트를 번역하라는 지시를 포함하며, 사용자 메시지는 번역할 텍스트를 포함합니다.
- 함수는
client.chat.completions.create()
메소드를 사용하여 API에게 번역 요청을 보냅니다. 여기서 사용할 모델과 번역할 메시지를 지정합니다. - API 응답에는 번역된 텍스트가 포함됩니다. 함수는 이 번역된 텍스트를 가져와 플레이스홀더를 원본 코드 블록으로 교체합니다.
- 마지막으로 함수는 번역된 텍스트를 반환합니다.
add_translation_note
함수
다음으로, add_translation_note
함수가 있습니다. 이 함수는 문서에 번역 노트를 추가합니다. 이 함수는 OpenAI 클라이언트 객체 및 인수를 매개변수로 받아들입니다. 작동 방식은 다음과 같습니다:
- 함수는
translation_note_fr
변수를 사용하여 프랑스어로 번역 노트를 만듭니다. - 그런 다음 함수는
translate_with_openai
함수를 사용하여 OpenAI API를 통해 번역 노트를 번역합니다.translate_with_openai
에 전달되는 인수에는 프랑스어 번역 노트 및 기타 인수가 포함됩니다. - 함수는 서식 문자를 추가하여 번역된 번역 노트를 포맷합니다.
- 마지막으로 함수는 포맷된 번역 노트를 반환합니다.
translate_markdown_file
함수
다음으로, translate_markdown_file
함수가 있습니다. 이 함수는 입력 마크다운 파일 경로, 출력 파일 경로, OpenAI 클라이언트 객체 및 인수를 매개변수로 받아들입니다. 이 함수는 OpenAI 번역 API를 사용하여 마크다운 파일의 내용을 번역하고, 번역된 내용을 출력 파일에 씁니다.
이 스크립트는 제 블로그 게시물의 접근성을 개선했을 뿐만 아니라 다국어 콘텐츠 제작 분야에서 새로운 자동화 가능성을 열어주었습니다. 이는 더 넓고 더 포용적인 지식 공유를 위한 한 걸음입니다. ## 사용 경험 및 처리 시간
사용 예제
# 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é.
처리 시간
- 영어: 약 4분 (248.70초)
- 스페인어: 약 4.7분 (284.05초)
- 총 합계: 약 8.7분 (532.75초) 이 시간들은 스크립트의 효율성과 속도를 보여줍니다.
결과
다음 링크에서 번역된 콘텐츠의 결과를 지금 바로 확인할 수 있습니다:
이 블로그 포스트는 AI를 사용한 번역 자동화에 대한 제 경험을 간략히 정리한 것입니다. 이는 프로그래밍과 인공지능을 결합하면 거의 무한한 가능성을 가지고 있으며 지식 공유와 콘텐츠 접근성 분야에서 새로운 흥미로운 지평을 열 수 있음을 입증합니다.
이 문서는 gpt-4o 모델을 사용하여 fr 버전에서 ko 언어로 번역되었습니다. 번역 과정에 대한 자세한 내용은 https://gitlab.com/jls42/ai-powered-markdown-translator 를 참조하십시오.