10. Januar 2025
Eine neue Ansage für deine Asterisk-Telefonanlage wird gebraucht, und schon beginnt die Suche nach der passenden Datei – oder noch schlimmer, du musst sie selbst aufnehmen. Das geht viel einfacher! Mit Google Text-to-Speech (gTTS) und ein bisschen Python kannst du Texte in natürlich klingende Sprachansagen umwandeln und direkt in Asterisk nutzen.
Die beiden neuen Funktionen, mit denen du Texte in gesprochene Sprache umwandeln kannst, habe ich in einem Modul untergebracht. Diese Modul vereinfacht das Schreiben von AGI-Skripten mit Python.
Testumgebung: Asterisk 18.10.0, Python 3.10.0, Ubuntu Mate (also Linux Debian), 10 Jahre alter Laptop.
In diesem Beitrag zeige ich dir also zwei praktische Funktionen, mit denen du dynamische Sprachansagen ganz leicht erstellen und einfügen kannst. Unter
AGI-Entwicklung für Asterisk mit einem Python-Modul vereinfacht – 29.12.2024: Wenn du dich bereits mit der Telefonsoftware Asterisk auskennst und etwas Erfahrung mit Python mitbringst, hast du den perfekten Startpunkt, um AGI (Asterisk Gateway Interface) zu erkunden. In diesem Beitrag stelle ich dir mein Python-Modul `asterisk_agi.py` vor. Es ist das Herzstück für die einfache und effektive Entwicklung von AGI-Skripten und ermöglicht dir, dynamische und interaktive Funktionen in Asterisk zu integrieren. – weiter – |
habe ich bereits ein Asterisk-Modul vorgestellt, dass viele wiederkehrende Funktionen enthält, die immer wieder vorkommen, um mit Hilfe von Python AGI-Skripte für Asterisk zu schreiben. Dieses Modul habe ich nun erweitert und asterisk2_agi.py genannt:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Asterisk AGI Python Module with gTTS Integration Place this file in the same directory as your main script. Ensure the file has execution permissions using: chmod +x asterisk_agi.py """ import sys import re from gtts import gTTS import os def init_env(): """ Initializes the AGI environment and returns it as a dictionary. """ env = {} while True: line = sys.stdin.readline().strip() if line == '': break key, data = line.split(':', 1) if key[:4] != 'agi_': # Skip input that doesn't begin with agi_ sys.stderr.write("Did not work!\n") sys.stderr.flush() continue key = key.strip() data = data.strip() if key != '': env[key] = data sys.stderr.write("AGI Environment Dump:\n") sys.stderr.flush() for key in env.keys(): sys.stderr.write(f" -- {key} = {env[key]}\n") sys.stderr.flush() return env def checkresult(params): params = params.rstrip() if re.search('^200', params): result = re.search('result=(\d+)', params) if not result: sys.stderr.write(f"FAIL ('{params}')\n") sys.stderr.flush() return -1 else: result = result.group(1) sys.stderr.write(f"PASS ({result})\n") sys.stderr.flush() return int(result) else: error_code = re.search('result=(-?\d+)', params) if error_code: error_code = int(error_code.group(1)) sys.stderr.write(f"FAIL (unexpected result '{params}', error code {error_code})\n") sys.stderr.flush() return error_code else: sys.stderr.write(f"FAIL (unexpected result '{params}')\n") sys.stderr.flush() return -2 def saynumber(params): sys.stderr.write(f"SAY NUMBER {params} \"\"\n") sys.stderr.flush() sys.stdout.write(f"SAY NUMBER {params} \"\"\n") sys.stdout.flush() result = sys.stdin.readline().strip() return checkresult(result) def sayit(params): sys.stderr.write(f"STREAM FILE {str(params)} \"\"\n") sys.stderr.flush() sys.stdout.write(f"STREAM FILE {str(params)} \"\"\n") sys.stdout.flush() result = sys.stdin.readline().strip() checkresult(result) def getnumber(prompt, timelimit, digcount): sys.stderr.write(f"GET DATA {prompt} {timelimit} {digcount}\n") sys.stderr.flush() sys.stdout.write(f"GET DATA {prompt} {timelimit} {digcount}\n") sys.stdout.flush() result = sys.stdin.readline().strip() return checkresult(result) def say_digits(number): """ Says each digit of a number separately. """ for digit in str(number): saynumber(digit) def text_to_speech(text, output_file="output"): """ Converts a given text to speech and saves it as a WAV file. """ try: # Create a gTTS object output_file = f"/usr/share/asterisk/sounds/test/{output_file}" temp_mp3 = f"{output_file}.mp3" temp_wav = f"{output_file}.wav" tts = gTTS(text=text, lang="de") # Save the audio as an MP3 file tts.save(temp_mp3) # Convert MP3 to WAV (requires ffmpeg or similar tool installed) os.system(f"ffmpeg -i {temp_mp3} -ar 8000 -ac 1 -y {temp_wav}") # Cleanup MP3 file os.remove(temp_mp3) sys.stderr.write(f"Text-to-Speech file saved as {temp_wav}\n") sys.stderr.flush() return temp_wav except Exception as e: sys.stderr.write(f"Error during text-to-speech conversion: {e}\n") sys.stderr.flush() return None def play_text_as_audio(text, output_file="output"): """ Converts text to speech, saves the audio, and streams it to Asterisk. """ wav_file = text_to_speech(text, output_file) if wav_file: sayit(wav_file.replace(".wav", "")) # Asterisk expects file path without extension
Es enthält zwei neue Funktionen, die nachfolgend vorgestellt werden.
Neue Funktionen: Text-zu-Sprache im Asterisk AGI: Dieses Python-Modul wurde um zwei leistungsstarke Funktionen erweitert, die die Text-zu-Sprache-Integration für Asterisk erleichtern: text_to_speech und play_text_as_audio. Beide nutzen die Google Text-to-Speech API (gTTS) und ermöglichen es, Texte in gesprochene Sprache umzuwandeln und direkt in Asterisk-Anrufen wiederzugeben.
1. Funktion: text_to_speech: Die Funktion text_to_speech konvertiert einen eingegebenen Text in eine Audiodatei im WAV-Format, die im Asterisk-Sounds-Verzeichnis gespeichert wird. Hier der Code dieser Funktion:
def text_to_speech(text, output_file="output"): """ Converts a given text to speech and saves it as a WAV file. """ try: # Create a gTTS object output_file = f"/usr/share/asterisk/sounds/test/{output_file}" temp_mp3 = f"{output_file}.mp3" temp_wav = f"{output_file}.wav" tts = gTTS(text=text, lang="de") # Save the audio as an MP3 file tts.save(temp_mp3) # Convert MP3 to WAV (requires ffmpeg or similar tool installed) os.system(f"ffmpeg -i {temp_mp3} -ar 8000 -ac 1 -y {temp_wav}") # Cleanup MP3 file os.remove(temp_mp3) sys.stderr.write(f"Text-to-Speech file saved as {temp_wav}\n") sys.stderr.flush() return temp_wav except Exception as e: sys.stderr.write(f"Error during text-to-speech conversion: {e}\n") sys.stderr.flush() return None
Funktionsweise:
-
- Erstellt mit gTTS eine MP3-Datei aus dem eingegebenen Text.
- Konvertiert die MP3-Datei mithilfe von ffmpeg in eine WAV-Datei, die mit Asterisk kompatibel ist.
- Speichert die Datei im Verzeichnis
/usr/share/asterisk/sounds/test
.
Voraussetzungen:
-
ffmpeg
muss installiert sein, um die Konvertierung von MP3 zu WAV durchzuführen.- Das Verzeichnis
/usr/share/asterisk/sounds/test
sollte Schreibrechte für das Skript haben.
2. Funktion: play_text_as_audio: Die Funktion play_text_as_audio kombiniert text_to_speech mit der direkten Wiedergabe der erzeugten Audiodatei über Asterisk. Der Code:
def play_text_as_audio(text, output_file="output"): """ Converts text to speech, saves the audio, and streams it to Asterisk. """ wav_file = text_to_speech(text, output_file) if wav_file: sayit(wav_file.replace(".wav", "")) # Asterisk expects file path without extension
Funktionsweise:
-
- Ruft
text_to_speech
auf, um eine WAV-Datei zu erstellen. - Nutzt die bereits im Modul vorhandene Funktion
sayit
, um die WAV-Datei im Asterisk-System abzuspielen.
- Ruft
Abhängigkeiten installieren: Damit die Funktionen text_to_speech
und play_text_as_audio
einwandfrei funktionieren, sind folgende Abhängigkeiten notwendig:
1. Python-Abhängigkeiten: Das Modul gTTS wird benötigt, um Texte in eine Audiodatei im MP3-Format umzuwandeln. Installation:
pip install gTTS
2. Systemabhängigkeiten: ffmpeg wird verwendet, um die generierte MP3-Datei in eine Asterisk-kompatible WAV-Datei zu konvertieren. Installation:
sudo apt update sudo apt install ffmpeg
Testen, ob ffmpeg funktioniert:
ffmpeg -version
Schreibrechte für das Zielverzeichnis: Die erzeugten Sound-Dateien (WAV-Dateien) müssen in meinem Beispiel im Verzeichnis /usr/share/asterisk/sounds/test gespeichert werden. Das Zielverzeichnis muss noch angelegt werden. Man kann natürlich einen anderen Pfad festlegen. Stelle sicher, dass das Python-Skript Schreibrechte in diesem Verzeichnis hat. Schreibrechte setzen:
sudo mkdir -p /usr/share/asterisk/sounds/test sudo chmod 775 /usr/share/asterisk/sounds/test sudo chown <dein_benutzername>:asterisk /usr/share/asterisk/sounds/test
Ich habe jedoch die Zugriffsrechte mit der GUI (Grafischen Benutzeroberfläche) von Ubuntu Mate gewählt und für den Ordner /usr/share/asterisk/sounds/test folgende Einstellungen gewählt:
Die Python-Skripte scheinen bezüglich der Rechte nicht so kritisch zu sein. Auf jeden Fall müssen sie ausführbar sein. Mit „root“ oder meinem Benutzernamen hat es bei mir funktioniert. So machst du ein Skript ausführbar:
chmod +x asterisk2_agi.py
Die Python-Skripte für AGI sind bei mir alle im Ordner /usr/share/asterisk/agi-bin/untergebracht.
Testen der neuen Funktion: Dieses Python-Skript sagt mit Hilfe der beiden neuen Funktionen einen Text in deutscher Sprache mit einer weiblichen Stimme auf:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Test Script for asterisk2_agi.py Ensure the module 'asterisk2_agi.py' is in the same directory and executable. """ import sys from asterisk2_agi import init_env, play_text_as_audio def main(): # Initialize the AGI environment env = init_env() # Print environment details (for debugging) sys.stderr.write("Initialized AGI Environment:\n") for key, value in env.items(): sys.stderr.write(f"{key}: {value}\n") sys.stderr.flush() # Text-to-Speech Test text_message = ( "Gratulation zu der gelungenen Installation der Sprachsynthese mit Hilfe von Google." "Dies bietet dir ganz neue Möglichkeiten in der Programmierung mit Asterisk." ) output_filename = "test_message" sys.stderr.write(f"Converting text to speech: \"{text_message}\"\n") sys.stderr.flush() # Play the text as audio through Asterisk play_text_as_audio(text_message, output_file=output_filename) if __name__ == "__main__": main()
Dieses Pythonskript zum Testen habe ich test_atsterisk2_agi.py genannt. Im selben Ordner muss sich auch das Python-Modul asterisk2_agi.py befinden, die am Anfang dieses Artikels vorgestellt wurde. In der extensions.conf von Asterisk rufst du die Testnummer wie folgt auf:
exten => 514,1,Noop(Anruf erfolgt von: "${CALLERID(name)}" <${CALLERID(num)}>) same => n,Noop(gtts mp3 test, Sprache: DEUTSCH) same => n,Set(CHANNEL(language)=de) ; Optionale Zeile. Deutsche Voice Prompts verwenden. same => n,Answer() same => n,AGI(test_asterisk2_agi.py) same => n,Hangup()
Rufe die 514 an und du hörst den Text in fast natürlicher Sprachqualität.
Download der beiden Python-Skripte in einer Zip-Datei: AGI-Python-Skripte-gTTS.zip
Datensicherheit: Bitte sei dir bewusst, dass mit GTTS alle Texte zu Google gesendet werden, die Google auf seinen Servern dann zu WAV-Dateien umwandelt und dir zuschickt. Google kennt dadurch einen Teil deiner Aktivitäten und könnte daraus Rückschlüsse ziehen. Dafür ist GTTS kostenlos und bedarf keiner Anmeldung. Du brauchst nur eine halbwegs stabile Internetverbindung und wenig Rechenleistung.
Stell dir vor eine Firma benutzt für sein Auswahlmenü GTTS. Immer wenn ein Kunde oder sonst jemand anruft, bekommt Google mit welche Sounddateien erzeugt werden und weiß somit welche Abteilungen die Kunden aus welchen Gründen zu welcher Zeit anrufen. Daraus lassen sich sehr interessante Rückschlüsse ziehen, die einen Wettbewerbsvorteil für Mitbewerber liefern könnten. Geheimdienste besitzen sicherlich noch mehr Möglichkeiten.
Ausblick: Die hier vorgestellte relativ einfache Technik lässt sich mit einer Spracherkennung, einer noch besseren Sprachausgabe und einer KI wie ChatGPT kombinieren. Damit wäre die telefonische Kundenberatung komplett automatisiert. Schon jetzt ist ChatGPT in der Lage ganz natürlich erscheinende Gespräche in Echtzeit zu führen. Der Anrufer kann nicht mehr unterscheiden, ob es sich um einen echten Menschen oder um eine Künstliche Intelligenz handelt. Die meisten Kunden werden damit meines Erachtens keine Schwierigkeiten haben, da sie sich ohne zwischenmenschliche Interaktion eine schnelle Lösung und eine kompetente Auskunft wünschen. Vielleicht ist ihnen eine KI sogar lieber, die immer hilfbereit und freundlich ist, ohne sich genervt zu fühlen.
Anwendungsbeispiel:
Aktuellen Wetterbericht aus einem RSS-Feed mit Asterisk vorsprechen lassen – 11. Januar 2025: Hast Du Dich jemals gefragt, wie man zum Beispiel automatisch aktuelle Wetterberichte am Telefon wiedergeben kann? In diesem Artikel zeige ich Dir als Beispiel für Unterrichtszwecke, wie ein kleines Python-Skript namens ***.py genau das als fiktives Beispiel ermöglicht. Es nutzt die Kraft von RSS-Feeds und Text-to-Speech-Diensten, um zum Beispiel einen Wetterbericht aus einer XML-Datei zu holen, in eine Audio-Datei zu verwandeln und direkt abzuspielen. – weiter – |
Weiterführend:
Asterisk-Telefonserver auf einem Raspberry Pi – Installation, Konfiguration, Programmierung, SIP, IAX2, AGI-Skripte, Sicherheit und Tipps zum praktischen Betrieb – 2.11.2022: Diese Seite richtet sich an jene, welche einen Asterisk-Telefon-Server auf einem Raspberry Pi betreiben möchten und später ein kleines Netzwerk aus Asterisk-Servern planen, um ein eigenständiges Telefonnetz aufzubauen. Los geht es mit der Installation von Raspbian und Asterisk auf einem Raspberry Pi und dann nach Lust und Laune immer tiefer in die Programmierung von Asterisk. Die Themen werden laufend erweitert.
Selbstverständlich muss es nicht unbedingt ein Raspberry Pi sein. Andere Linux-Rechner gehen auch. – weiter – |