|
| 1 | +--- |
| 2 | +title: Wie man Posts mit der Claude 3.5 Sonnet API automatisch übersetzt (2) - Erstellung und Implementierung von Automatisierungsskripten |
| 3 | +description: >- |
| 4 | + Dieser Artikel behandelt den Prozess der Gestaltung von Prompts für die mehrsprachige Übersetzung von Blogbeiträgen, sowie die Automatisierung der Arbeit mit Python unter Verwendung des von Anthropic erhaltenen API-Schlüssels und der erstellten Prompts. Dies ist der zweite Teil der Serie und stellt die API-Integration und Python-Skripterstellung vor. |
| 5 | +categories: |
| 6 | +- Blogging |
| 7 | +tags: |
| 8 | +- Jekyll |
| 9 | +- LLM |
| 10 | +--- |
| 11 | +## Einführung |
| 12 | +Kürzlich habe ich die Claude 3.5 Sonnet API von Anthropic für die mehrsprachige Übersetzung von Blogbeiträgen eingeführt. In dieser Serie werden die Gründe für die Wahl der Claude 3.5 Sonnet API, die Methoden des Prompt-Designs und die Implementierung der API-Integration sowie Automatisierung durch Python-Skripte behandelt. |
| 13 | +Die Serie besteht aus zwei Artikeln, und dieser Artikel ist der zweite Teil der Serie. |
| 14 | +- Teil 1: [Vorstellung des Claude 3.5 Sonnet Modells, Auswahlgründe und Prompt Engineering](/posts/how-to-auto-translate-posts-with-the-claude-3.5-sonnet-api-1) |
| 15 | +- Teil 2: Erstellung und Implementierung von Python-Automatisierungsskripten mit der API (dieser Artikel) |
| 16 | + |
| 17 | +## Bevor wir beginnen |
| 18 | +Dieser Artikel ist eine Fortsetzung von [Teil 1](/posts/how-to-auto-translate-posts-with-the-claude-3.5-sonnet-api-1). Falls Sie diesen noch nicht gelesen haben, empfehle ich, zuerst den vorherigen Artikel zu lesen. |
| 19 | + |
| 20 | +## Claude API Integration |
| 21 | +### Claude API-Schlüssel erhalten |
| 22 | + |
| 23 | +> Hier wird erklärt, wie man einen neuen Claude API-Schlüssel erhält. Wenn Sie bereits einen API-Schlüssel haben, können Sie diesen Schritt überspringen. |
| 24 | +{: .prompt-tip } |
| 25 | + |
| 26 | +Besuchen Sie <https://console.anthropic.com> und melden Sie sich an. Falls Sie noch kein Konto haben, müssen Sie sich zunächst registrieren. Nach der Anmeldung sehen Sie das folgende Dashboard. |
| 27 | + |
| 28 | + |
| 29 | +Klicken Sie auf der Seite auf die Schaltfläche 'Get API keys', um den folgenden Bildschirm zu sehen. |
| 30 | + Da ich bereits einen Schlüssel erstellt habe, wird ein Schlüssel mit dem Namen `yunseo-secret-key` angezeigt. Wenn Sie gerade erst ein Konto erstellt haben und noch keinen API-Schlüssel besitzen, werden Sie wahrscheinlich keine vorhandenen Schlüssel sehen. Klicken Sie oben rechts auf die Schaltfläche 'Create Key', um einen neuen Schlüssel zu erstellen. |
| 31 | + |
| 32 | +> Nach der Schlüsselerstellung wird Ihr API-Schlüssel angezeigt. Da dieser Schlüssel später nicht mehr eingesehen werden kann, müssen Sie ihn unbedingt an einem sicheren Ort separat aufbewahren. |
| 33 | +{: .prompt-warning } |
| 34 | + |
| 35 | +### (Empfohlen) Claude API-Schlüssel in Umgebungsvariablen registrieren |
| 36 | +Um die Claude API in Python- oder Shell-Skripten zu verwenden, muss der API-Schlüssel geladen werden. Man könnte den API-Schlüssel direkt im Skript speichern, aber diese Methode ist nicht geeignet, wenn das Skript auf GitHub hochgeladen oder anderweitig mit anderen geteilt werden soll. Auch wenn Sie nicht vorhaben, das Skript zu teilen, besteht das Risiko, dass bei unbeabsichtigtem Durchsickern des Skripts auch der API-Schlüssel kompromittiert wird. Daher wird empfohlen, den API-Schlüssel in den Umgebungsvariablen des eigenen Systems zu registrieren und ihn im Skript aus diesen Variablen zu laden. Im Folgenden wird die Methode zur Registrierung des API-Schlüssels in Systemumgebungsvariablen für UNIX-Systeme vorgestellt. Für Windows konsultieren Sie bitte andere Online-Ressourcen. |
| 37 | + |
| 38 | +1. Öffnen Sie im Terminal je nach verwendeter Shell `nano ~/.bashrc` oder `nano ~/.zshrc`. |
| 39 | +2. Fügen Sie `export ANTHROPIC_API_KEY='your-api-key-here'` zum Dateiinhalt hinzu. Ersetzen Sie 'your-api-key-here' durch Ihren API-Schlüssel und beachten Sie, dass er von Anführungszeichen umschlossen sein muss. |
| 40 | +3. Speichern Sie die Änderungen und beenden Sie den Editor. |
| 41 | +4. Führen Sie im Terminal `source ~/.bashrc` oder `source ~/.zshrc` aus, um die Änderungen zu übernehmen. |
| 42 | + |
| 43 | +### Erforderliche Python-Pakete installieren |
| 44 | +Wenn das anthropic-Paket in Ihrer Python-Umgebung noch nicht installiert ist, installieren Sie es mit folgendem Befehl: |
| 45 | +```bash |
| 46 | +pip3 install anthropic |
| 47 | +``` |
| 48 | +Außerdem werden die folgenden Pakete für das später vorgestellte Übersetzungsskript benötigt. Installieren oder aktualisieren Sie sie mit diesem Befehl: |
| 49 | +```bash |
| 50 | +pip3 install -U argparse tqdm |
| 51 | +``` |
| 52 | + |
| 53 | +### Python-Skripte erstellen |
| 54 | +Das hier vorgestellte Übersetzungsskript besteht aus drei Python-Skriptdateien und einer CSV-Datei. |
| 55 | + |
| 56 | +- `compare_hash.py`: Berechnet SHA256-Hash-Werte der koreanischen Originalbeiträge im Verzeichnis `_posts/ko`{: .filepath} und vergleicht sie mit den bestehenden Hash-Werten in der `hash.csv`-Datei, um eine Liste der geänderten oder neu hinzugefügten Dateien zurückzugeben |
| 57 | +- `hash.csv`: CSV-Datei mit den SHA256-Hash-Werten der bestehenden Beitragsdateien |
| 58 | +- `prompt.py`: Empfängt filepath, source_lang, target_lang Werte und lädt den Claude API-Schlüssel aus den Systemumgebungsvariablen. Ruft die API auf und verwendet den zuvor erstellten Prompt als Systemprompt und den Inhalt des zu übersetzenden Beitrags aus 'filepath' als Benutzerprompt. Empfängt dann die Antwort (Übersetzungsergebnis) vom Claude 3.5 Sonnet Modell und speichert sie als Textdatei unter `'../_posts/' + language_code[target_lang] + '/' + filename`{: .filepath} |
| 59 | +- `translate_changes.py`: Enthält die String-Variable source_lang und die Liste 'target_langs', ruft die Funktion `changed_files()` aus `compare_hash.py` auf und erhält die Liste changed_files zurück. Wenn es geänderte Dateien gibt, führt eine Doppelschleife über alle Dateien in der changed_files Liste und alle Elemente in der target_langs Liste aus und ruft dabei die Funktion `translate(filepath, source_lang, target_lang)` aus `prompt.py` auf, um die Übersetzung durchzuführen. |
| 60 | + |
| 61 | +Der vollständige Inhalt der Skriptdateien kann auch im GitHub-Repository [yunseo-kim/yunseo-kim.github.io](https://github.com/yunseo-kim/yunseo-kim.github.io/tree/main/tools) eingesehen werden. |
| 62 | + |
| 63 | +#### compare_hash.py |
| 64 | + |
| 65 | +```python |
| 66 | +import os |
| 67 | +import hashlib |
| 68 | +import csv |
| 69 | + |
| 70 | +def compute_file_hash(file_path): |
| 71 | + sha256_hash = hashlib.sha256() |
| 72 | + with open(file_path, "rb") as f: |
| 73 | + for byte_block in iter(lambda: f.read(4096), b""): |
| 74 | + sha256_hash.update(byte_block) |
| 75 | + return sha256_hash.hexdigest() |
| 76 | + |
| 77 | +def load_existing_hashes(csv_path): |
| 78 | + existing_hashes = {} |
| 79 | + if os.path.exists(csv_path): |
| 80 | + with open(csv_path, 'r') as csvfile: |
| 81 | + reader = csv.reader(csvfile) |
| 82 | + for row in reader: |
| 83 | + if len(row) == 2: |
| 84 | + existing_hashes[row[0]] = row[1] |
| 85 | + return existing_hashes |
| 86 | + |
| 87 | +def update_hash_csv(csv_path, file_hashes): |
| 88 | + # Sort the file hashes by filename (the dictionary keys) |
| 89 | + sorted_file_hashes = dict(sorted(file_hashes.items())) |
| 90 | + |
| 91 | + with open(csv_path, 'w', newline='') as csvfile: |
| 92 | + writer = csv.writer(csvfile) |
| 93 | + for file_path, hash_value in sorted_file_hashes.items(): |
| 94 | + writer.writerow([file_path, hash_value]) |
| 95 | + |
| 96 | +def changed_files(): |
| 97 | + posts_dir = '../_posts/ko/' |
| 98 | + hash_csv_path = './hash.csv' |
| 99 | + |
| 100 | + existing_hashes = load_existing_hashes(hash_csv_path) |
| 101 | + current_hashes = {} |
| 102 | + changed_files = [] |
| 103 | + |
| 104 | + for root, _, files in os.walk(posts_dir): |
| 105 | + for file in files: |
| 106 | + if not file.endswith('.md'): # Process only .md files |
| 107 | + continue |
| 108 | + |
| 109 | + file_path = os.path.join(root, file) |
| 110 | + relative_path = os.path.relpath(file_path, start=posts_dir) |
| 111 | + |
| 112 | + current_hash = compute_file_hash(file_path) |
| 113 | + current_hashes[relative_path] = current_hash |
| 114 | + |
| 115 | + if relative_path in existing_hashes: |
| 116 | + if current_hash != existing_hashes[relative_path]: |
| 117 | + changed_files.append(relative_path) |
| 118 | + else: |
| 119 | + changed_files.append(relative_path) |
| 120 | + |
| 121 | + update_hash_csv(hash_csv_path, current_hashes) |
| 122 | + return changed_files |
| 123 | + |
| 124 | +if __name__ == "__main__": |
| 125 | + initial_wd = os.getcwd() |
| 126 | + os.chdir(os.path.abspath(os.path.dirname(__file__))) |
| 127 | + |
| 128 | + changed_files = changed_files() |
| 129 | + if changed_files: |
| 130 | + print("Changed files:") |
| 131 | + for file in changed_files: |
| 132 | + print(f"- {file}") |
| 133 | + else: |
| 134 | + print("No files have changed.") |
| 135 | + |
| 136 | + os.chdir(initial_wd) |
| 137 | +``` |
| 138 | + |
| 139 | +#### prompt.py |
| 140 | +Da die Datei den zuvor erstellten Prompt enthält und daher recht lang ist, wird sie durch einen Link zur Quelldatei im GitHub-Repository ersetzt. |
| 141 | +<https://github.com/yunseo-kim/yunseo-kim.github.io/blob/main/tools/prompt.py> |
| 142 | + |
| 143 | +> In der `prompt.py`-Datei unter dem obigen Link ist `max_tokens` eine Variable, die die maximale Ausgabelänge unabhängig von der Context-Window-Größe festlegt. Während die Context-Window-Größe bei der Claude API-Nutzung 200k Token (etwa 680.000 Zeichen) beträgt, hat jedes Modell eine festgelegte maximale Ausgabe-Token-Anzahl. Es wird empfohlen, diese vor der API-Nutzung in der [offiziellen Anthropic-Dokumentation](https://docs.anthropic.com/en/docs/about-claude/models) zu überprüfen. Die bisherigen Claude 3-Modelle konnten maximal 4096 Token ausgeben, was bei den meisten Blogbeiträgen ausreichte. Bei einigen längeren Beiträgen mit über 8000 koreanischen Zeichen wurde die 4096-Token-Grenze jedoch in manchen Zielsprachen überschritten, wodurch der hintere Teil der Übersetzung abgeschnitten wurde. Claude 3.5 Sonnet verdoppelt die maximale Ausgabe-Token-Anzahl auf 8192, wodurch solche Probleme praktisch nicht mehr auftreten. In der `prompt.py` im obigen GitHub-Repository ist `max_tokens=8192` entsprechend eingestellt. |
| 144 | +{: .prompt-tip } |
| 145 | + |
| 146 | +#### translate_changes.py |
| 147 | + |
| 148 | +```python |
| 149 | +import sys |
| 150 | +import os |
| 151 | +from tqdm import tqdm |
| 152 | +import compare_hash |
| 153 | +import prompt |
| 154 | + |
| 155 | +posts_dir = '../_posts/ko/' |
| 156 | +source_lang = "Korean" |
| 157 | +target_langs = ["English", "Spanish", "Brazilian Portuguese", "Japanese", "French", "German"] |
| 158 | + |
| 159 | +if __name__ == "__main__": |
| 160 | + initial_wd = os.getcwd() |
| 161 | + os.chdir(os.path.abspath(os.path.dirname(__file__))) |
| 162 | + |
| 163 | + changed_files = compare_hash.changed_files() |
| 164 | + if not changed_files: |
| 165 | + sys.exit("No files have changed.") |
| 166 | + print("Changed files:") |
| 167 | + for file in changed_files: |
| 168 | + print(f"- {file}") |
| 169 | + |
| 170 | + print("") |
| 171 | + print("*** Translation start! ***") |
| 172 | + for changed_file in changed_files: |
| 173 | + print(f"- Translating {changed_file}") |
| 174 | + filepath = os.path.join(posts_dir, changed_file) |
| 175 | + for target_lang in tqdm(target_langs): |
| 176 | + prompt.translate(filepath, source_lang, target_lang) |
| 177 | + |
| 178 | + os.chdir(initial_wd) |
| 179 | +``` |
| 180 | + |
| 181 | +### Verwendung der Python-Skripte |
| 182 | +Für Jekyll-Blogs erstellen Sie im Verzeichnis `/_posts`{: .filepath} Unterverzeichnisse nach [ISO 639-1](https://www.loc.gov/standards/iso639-2/php/code_list.php) Sprachcodes wie `/_posts/ko`{: .filepath}, `/_posts/en`{: .filepath}, `/_posts/pt-BR`{: .filepath}. Platzieren Sie die oben vorgestellten Python-Skripte und die CSV-Datei im Verzeichnis `/tools`{: .filepath} und führen Sie dort im Terminal folgenden Befehl aus: |
| 183 | + |
| 184 | +```bash |
| 185 | +python3 translate_changes.py |
| 186 | +``` |
| 187 | + |
| 188 | +Das Skript wird ausgeführt und zeigt folgende Bildschirme: |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +## Praxiserfahrung |
| 193 | +Wie oben beschrieben, nutze ich die automatische Beitragsübersetzung mit der Claude 3.5 API seit etwa zwei Monaten für diesen Blog. In den meisten Fällen liefert sie ohne zusätzlichen menschlichen Eingriff Übersetzungen von hervorragender Qualität. Nach der mehrsprachigen Veröffentlichung der Beiträge konnte ich tatsächlich organischen Suchverkehr aus Ländern außerhalb Koreas wie Brasilien, Kanada, den USA und Frankreich feststellen. Neben dem Blogverkehr gibt es auch zusätzliche Vorteile für das Lernen des Autors selbst: Da Claude sehr flüssige englische Texte erstellt, kann ich beim Überprüfen der Beiträge vor dem Push in das GitHub Pages Repository sehen, wie bestimmte Begriffe oder Ausdrücke aus meinem koreanischen Original auf natürliche Weise auf Englisch ausgedrückt werden. Auch wenn dies allein nicht für umfassendes Englischlernen ausreicht, ist es für einen Ingenieurstudenten aus einem nicht-englischsprachigen Land wie Korea durchaus vorteilhaft, ohne zusätzlichen Aufwand regelmäßig natürliche englische Ausdrücke und Fachbegriffe anhand des eigenen, vertrauten Texts zu lernen. |
0 commit comments