6. März 2025
Dieses Python-Skript übersetzt Texte automatisch in verschiedene Sprachen und wandelt sie in Sprachdateien um – perfekt für Asterisk-Telefonserver. Die Bedienung erfolgt über eine grafische Oberfläche, und die Sprachausgabe wird mit Google Text-to-Speech erstellt, ganz ohne API-Schlüssel. Unterstützt werden Deutsch, Englisch, Schwedisch, Französisch und Spanisch, wobei die englische Stimme derzeit nur mit britischem Akzent verfügbar ist.

Klangbeispiel als MP3 des Textes, der im oberen Bild zu sehen ist: Der englische Text hat einen kleinen Fehler, denn die Abkürzung KI wurde nicht mit AI übersetzt. Das lässt sich aber im unteren Feld von Hand noch korrigieren.
Klangbeispiel eines deutschen Textes als MP3: Die Stimme ist bei Google gTTS immer weiblich.
Auf jeden Fall sind die Sprachdateien sehr schnell erzeugt. Und die WAV-Dateien liegen in einem Format vor, das für Asterisk geeignet ist.

Das Programm bietet folgende Funktionen:
-
- Eingabe eines beliebigen Textes über eine grafische Oberfläche
- Auswahl der Sprache für die Sprachausgabe (Deutsch, US-Englisch, Britisches Englisch, Schwedisch, Französisch, Spanisch)
- Möglichkeit, den Text vor der Sprachausgabe automatisch in die gewählte Sprache zu übersetzen
- Speicherung der generierten Audiodateien als MP3 und WAV
- Nutzung von Google Text-to-Speech (gTTS) und Google Translate zur Umsetzung
- Keine Notwendigkeit für API-Schlüssel oder Passwörter
Das Skript für Python 3:
import tkinter as tk from tkinter import scrolledtext, messagebox import os import re from gtts import gTTS import subprocess import threading from googletrans import Translator, LANGUAGES class TextToSpeechApp: def __init__(self, root): self.root = root self.root.title("Text zu Sprache Konverter") self.root.geometry("600x620") # Erhöhte Höhe für die neuen Elemente self.root.configure(bg="#e0e5eb") # Übersetzer initialisieren self.translator = Translator() # Farben self.bg_color = "#e0e5eb" # Hellblaugrau self.button_color = "#5d7793" # Mittelblaugrau self.text_bg = "#f0f2f5" # Sehr helles Blaugrau self.text_fg = "#2c3e50" # Dunkelblaugrau # Sprachoptionen mit ISO-Codes für die Übersetzung self.languages = { "de": "Deutsch", "en-us": "US-Englisch", "en-gb": "Britisches Englisch", "sv": "Schwedisch", "fr": "Französisch", "es": "Spanisch" } # Mapping von TTS-Sprachcodes zu googletrans-Sprachcodes und tld-Werten self.tts_to_translate_map = { "de": {"lang": "de", "tld": "de"}, # Deutscher Akzent "en-us": {"lang": "en", "tld": "com"}, # US-Englisch "en-gb": {"lang": "en", "tld": "co.uk"}, # Britisches Englisch "sv": {"lang": "sv", "tld": "se"}, # Schwedischer Akzent "fr": {"lang": "fr", "tld": "fr"}, # Französischer Akzent "es": {"lang": "es", "tld": "es"} # Spanischer Akzent } # Standard Spracheinstellung self.selected_language = tk.StringVar() self.selected_language.set("de") # Option für langsames Sprechen self.slow_speech = tk.BooleanVar() self.slow_speech.set(False) # Option für automatische Übersetzung self.auto_translate = tk.BooleanVar() self.auto_translate.set(False) # Variable für Originaltext speichern self.original_text = "" self.create_widgets() def create_widgets(self): # Frame für Dateinamen filename_frame = tk.Frame(self.root, bg=self.bg_color) filename_frame.pack(pady=10, fill=tk.X, padx=20) # Label und Eingabefeld für Dateinamen tk.Label(filename_frame, text="Dateiname:", bg=self.bg_color, fg=self.text_fg, font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 10)) self.filename_entry = tk.Entry(filename_frame, bg=self.text_bg, fg=self.text_fg, width=30) self.filename_entry.pack(side=tk.LEFT, fill=tk.X, expand=True) self.filename_entry.insert(0, "output") # Standardwert # Frame für Spracheinstellungen language_frame = tk.Frame(self.root, bg=self.bg_color) language_frame.pack(pady=5, fill=tk.X, padx=20) # Label für Sprachauswahl tk.Label(language_frame, text="Sprache:", bg=self.bg_color, fg=self.text_fg, font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 10)) # Radiobuttons für Sprachauswahl language_buttons_frame = tk.Frame(self.root, bg=self.bg_color) language_buttons_frame.pack(pady=0, fill=tk.X, padx=20) col = 0 row = 0 for lang_code, lang_name in self.languages.items(): rb = tk.Radiobutton(language_buttons_frame, text=lang_name, value=lang_code, variable=self.selected_language, bg=self.bg_color, fg=self.text_fg, command=self.on_language_change) rb.grid(row=row, column=col, sticky=tk.W, padx=5, pady=2) col += 1 if col > 2: # 3 Sprachen pro Zeile col = 0 row += 1 # Frame für Checkboxen option_frame = tk.Frame(language_buttons_frame, bg=self.bg_color) option_frame.grid(row=row+1, column=0, columnspan=3, sticky=tk.W, padx=5, pady=5) # Checkbox für langsames Sprechen slow_check = tk.Checkbutton(option_frame, text="Langsames Sprechen", variable=self.slow_speech, bg=self.bg_color, fg=self.text_fg) slow_check.pack(side=tk.LEFT, padx=(0, 15)) # Checkbox für automatische Übersetzung translate_check = tk.Checkbutton(option_frame, text="Automatisch übersetzen", variable=self.auto_translate, bg=self.bg_color, fg=self.text_fg) translate_check.pack(side=tk.LEFT) # Textfeld mit Scrollbar tk.Label(self.root, text="Text eingeben:", bg=self.bg_color, fg=self.text_fg, font=("Arial", 10, "bold")).pack(anchor="w", padx=20) self.text_area = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, width=60, height=12, bg=self.text_bg, fg=self.text_fg) self.text_area.pack(padx=20, pady=10, fill=tk.BOTH, expand=True) # Textfeld für die Übersetzung tk.Label(self.root, text="Übersetzter Text:", bg=self.bg_color, fg=self.text_fg, font=("Arial", 10, "bold")).pack(anchor="w", padx=20) self.translated_text_area = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, width=60, height=5, bg=self.text_bg, fg="#4a6fa5") self.translated_text_area.pack(padx=20, pady=10, fill=tk.X) # Frame für Buttons button_frame = tk.Frame(self.root, bg=self.bg_color) button_frame.pack(pady=15, padx=20) # Buttons self.translate_button = tk.Button(button_frame, text="Text übersetzen", command=self.translate_text, bg=self.button_color, fg="white", font=("Arial", 10, "bold"), activebackground="#49617a", width=15, height=2) self.translate_button.pack(side=tk.LEFT, padx=(0, 10)) self.convert_button = tk.Button(button_frame, text="MP3 und WAV erzeugen", command=self.start_conversion, bg=self.button_color, fg="white", font=("Arial", 10, "bold"), activebackground="#49617a", width=20, height=2) self.convert_button.pack(side=tk.LEFT, padx=(0, 10)) self.clear_button = tk.Button(button_frame, text="Text löschen", command=self.clear_text, bg=self.button_color, fg="white", font=("Arial", 10, "bold"), activebackground="#49617a", width=15, height=2) self.clear_button.pack(side=tk.LEFT) # Status Label self.status_label = tk.Label(self.root, text="", bg=self.bg_color, fg=self.text_fg) self.status_label.pack(pady=5) def clean_text(self, text): """Entfernt Sonderzeichen, Bindestriche, Gänsefüßchen und Smileys aus dem Text.""" invalid_chars = r"[\"'""''`´…\-–—:;(){}\[\]<>|@#$%^&*_+=/\\😊😂👍]" cleaned_text = re.sub(invalid_chars, ' ', text) return cleaned_text def on_language_change(self): """Wird aufgerufen, wenn die Sprache geändert wird.""" if self.auto_translate.get() and self.original_text: self.translate_text() def translate_text(self): """Übersetzt den Text in die ausgewählte Sprache.""" # Text aus dem Textfeld holen text = self.text_area.get("1.0", tk.END).strip() if not text: self.status_label.config(text="Fehler: Kein Text eingegeben!") return # Originaltext speichern self.original_text = text # Ausgewählte Sprache holen und zum Übersetzen anpassen selected_lang = self.selected_language.get() translate_lang = self.tts_to_translate_map[selected_lang]["lang"] # Nur den 'lang'-Teil verwenden # Übersetzung in einem separaten Thread durchführen self.translate_button.config(state=tk.DISABLED) self.status_label.config(text="Übersetze...") threading.Thread(target=self.perform_translation, args=(text, translate_lang), daemon=True).start() def perform_translation(self, text, dest_lang): """Führt die eigentliche Übersetzung durch.""" try: # Übersetzung durchführen translation = self.translator.translate(text, dest=dest_lang) # Übersetzten Text anzeigen self.translated_text_area.delete("1.0", tk.END) self.translated_text_area.insert("1.0", translation.text) self.status_label.config(text=f"Übersetzung von {LANGUAGES.get(translation.src, 'Unbekannt')} " f"nach {LANGUAGES.get(translation.dest, 'Unbekannt')} abgeschlossen") except Exception as e: self.status_label.config(text=f"Fehler bei der Übersetzung: {str(e)}") self.translated_text_area.delete("1.0", tk.END) self.translated_text_area.insert("1.0", "Übersetzungsfehler. Bitte erneut versuchen.") finally: # Button wieder aktivieren self.translate_button.config(state=tk.NORMAL) def convert_to_speech(self): # Text aus dem korrekten Textfeld holen if self.auto_translate.get(): text = self.translated_text_area.get("1.0", tk.END).strip() if not text: self.translate_text() # Falls noch keine Übersetzung vorliegt text = self.translated_text_area.get("1.0", tk.END).strip() else: text = self.text_area.get("1.0", tk.END).strip() if not text: self.status_label.config(text="Fehler: Kein Text eingegeben!") return # Dateinamen aus dem Eingabefeld holen filename = self.filename_entry.get().strip() if not filename: filename = "output" # Dateipfade im selben Verzeichnis wie das Skript script_dir = os.path.dirname(os.path.abspath(__file__)) output_mp3 = os.path.join(script_dir, f"{filename}.mp3") output_wav = os.path.join(script_dir, f"{filename}.wav") try: # Text bereinigen cleaned_text = self.clean_text(text) if not cleaned_text: self.status_label.config(text="Fehler: Der Text ist nach der Bereinigung leer!") return # Ausgewählte Sprache und Sprechgeschwindigkeit holen selected_lang = self.selected_language.get() lang_settings = self.tts_to_translate_map[selected_lang] is_slow = self.slow_speech.get() # Debug-Ausgabe, um die verwendeten Werte zu überprüfen debug_msg = f"Erzeuge TTS mit lang={lang_settings['lang']}, tld={lang_settings['tld']}, slow={is_slow}" print(debug_msg) # In der Konsole sichtbar self.status_label.config(text=debug_msg) # Text in Sprache umwandeln mit entsprechendem tld tts = gTTS( text=cleaned_text, lang=lang_settings["lang"], tld=lang_settings["tld"], slow=is_slow ) # MP3 speichern tts.save(output_mp3) # MP3 zu WAV konvertieren (benötigt ffmpeg) try: subprocess.run( ["ffmpeg", "-i", output_mp3, "-ar", "8000", "-ac", "1", "-y", output_wav], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) # Sprachname für die Statusanzeige ermitteln lang_name = self.languages[selected_lang] speed_text = "langsam" if is_slow else "normal" translate_text = "übersetzt" if self.auto_translate.get() else "original" self.status_label.config( text=f"Erfolgreich erstellt: {output_mp3} und {output_wav} ({lang_name}, {speed_text}, {translate_text})" ) except subprocess.CalledProcessError: self.status_label.config( text=f"MP3 erstellt, aber Fehler bei WAV-Konvertierung. Ist ffmpeg installiert?" ) except Exception as e: self.status_label.config(text=f"Fehler: {str(e)}") finally: # Buttons wieder aktivieren self.convert_button.config(state=tk.NORMAL) def start_conversion(self): # Button deaktivieren während der Konvertierung self.convert_button.config(state=tk.DISABLED) self.status_label.config(text="Konvertiere...") # Wenn Übersetzung aktiviert ist und noch keine Übersetzung vorliegt if self.auto_translate.get() and not self.translated_text_area.get("1.0", tk.END).strip(): self.translate_text() # Konvertierung in einem separaten Thread ausführen threading.Thread(target=self.convert_to_speech, daemon=True).start() def clear_text(self): self.text_area.delete("1.0", tk.END) self.translated_text_area.delete("1.0", tk.END) self.original_text = "" self.status_label.config(text="Text gelöscht") def main(): root = tk.Tk() app = TextToSpeechApp(root) root.mainloop() if __name__ == "__main__": main()
Folgende Python-Bibliotheken müssen eventuell installiert werden:
pip install tkinter # Wird oft mit Python mitgeliefert, aber falls nicht, installieren pip install gtts # Google Text-to-Speech für die Sprachsynthese pip install googletrans==4.0.0-rc1 # Google Übersetzungsbibliothek (spezielle Version empfohlen)
Hier kannst du dir das Skript herunterladen: Es ist mit ZIP gepackt. Entpacke die es und probiere die py-Datei aus mit „python3 text-to-speech-translate02.py“ im Linux-Terminal (Ubuntu)
text-to-speech-translate02.py.zip
Mit dieser Batchdatei für Linux kannst du das Skript per Mausklick starten: Nenne sie start_tts.sh oder so ähnlich. Mache die Datei ausführbar mit „chmod +x start_tts.sh“.
#!/bin/bash cd "$(dirname "$0")" # Wechselt in das Verzeichnis, in dem das Skript liegt python3 text-to-speech-translate02.py
Wie ist dieses Python Skript entstanden? Vor einigen Wochen hatte ich mir mit einer KI (ich glaube es war ChatGPT) ein einfaches Python-Skript erstellen ohne Oberfläche erstellen lassen, das aus einer Textdatei mit Google gTTS eine MP3- und WAV-Datei, die für Asterisk geeignet ist, erstellt. Mit Hilfe Claude 3.7 Sonnet ließ ich eine Oberfläche dafür erzeugen nach meinen Vorstellungen erzeugen. In einem weiteren Schritt kamen Radio-Buttons hinzu, um Sprachen auswählen zu können. Dann kam mir die Idee, dass die Texte gleich übersetzt werden sollte. Claude schlug mir googletrans vor, da es wie gTTS ohne Anmeldung oder Token auskommt. Diese Erweiterung hatte dann auch auf Anhieb geklappt. Insgesamt lag der Zeitaufwand bei 1 bis 2 Stunden. Die meisten Zeit wurde für das Testen benötigt. Fehler im Code konnte ich nicht finden. Leider kann gTTS offenbar keine us-amerikanische Stimme liefern.

Claude 3.7 Sonnet hat nicht nur eine praktische Oberfläche für das Coding. Man schreibt einen ausführlichen Prompt und diese KI macht das, was man will. In den allermeisten Fällen laufen die Skripte auf Anhieb.