16. Februar 2023
Ein Auswahlmenü, auch IVR-Menü (Interactive Voice Response) genannt, ist eine automatisierte Telefonanwendung, die es dem Anrufer ermöglicht, durch Drücken von Tasten auf seiner Telefontastatur eine gewünschte Option auszuwählen. Es bietet dem Anrufer eine einfache Möglichkeit, auf eine bestimmte Abteilung oder Dienstleistung zuzugreifen, indem er eine bestimmte Tastenkombination drückt, die mit der entsprechenden Funktion oder Person verbunden ist. Es wird oft in Unternehmen und Organisationen eingesetzt, um den Anrufer direkt an die richtige Stelle zu leiten und Wartezeiten und Übertragungen zu reduzieren.
Auswahlmenüs für Asterisk-Telefonsysteme lassen sich direkt mit den Wahlregeln in der extensions.conf definieren. Ich finde es jedoch eleganter sie mit AGI-Skripten in Python zu programmieren. Wenn man einmal das Prinzip verstanden hat, ist es sogar einfacher. Die extensions.conf gestaltet sich zudem kompakter.
Hier ein Beispiel, das als Vorlage dienen kann. Das Skript ist in der auswahlmenue.py untergebracht. Alles weitere steht im Kommentar:
#!/usr/bin/python # auswahlmenue.py läuft auf Python 2.7 und sicherlich auf 3.0 ######### Nachfolgendes erspart den Einsatz von pyst ####################### import sys import re import time # Read and ignore AGI environment (read until blank line) env = {} tests = 0; while 1: line = sys.stdin.readline().strip() if line == '': break key,data = line.split(':') 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(" -- %s = %s\n" % (key, env[key])) sys.stderr.flush() def checkresult (params): params = params.rstrip() if re.search('^200',params): result = re.search('result=(\d+)',params) if (not result): sys.stderr.write("FAIL ('%s')\n" % params) sys.stderr.flush() return -1 else: result = result.group(1) #debug("Result:%s Params:%s" % (result, params)) sys.stderr.write("PASS (%s)\n" % result) sys.stderr.flush() return result else: sys.stderr.write("FAIL (unexpected result '%s')\n" % params) sys.stderr.flush() return -2 def sayit (params): sys.stderr.write("STREAM FILE %s \"\"\n" % str(params)) sys.stderr.flush() sys.stdout.write("STREAM FILE %s \"\"\n" % str(params)) sys.stdout.flush() result = sys.stdin.readline().strip() checkresult(result) def saynumber (params): sys.stderr.write("SAY NUMBER %s \"\"\n" % params) sys.stderr.flush() sys.stdout.write("SAY NUMBER %s \"\"\n" % params) sys.stdout.flush() result = sys.stdin.readline().strip() checkresult(result) def getnumber (prompt, timelimit, digcount): sys.stderr.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount)) sys.stderr.flush() sys.stdout.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount)) sys.stdout.flush() result = sys.stdin.readline().strip() result = checkresult(result) sys.stderr.write("digits are %s\n" % result) sys.stderr.flush() if result: return result else: result = -1 ################### Ab hier beginnt das eigentliche Skript ##################### limit=5 # nicht definiert digitcount=1 # Der Nutzer kann nur eine Ziffer eingeben und danach beginnt die Vermittlung ttanswer=5000 # Der Nutzer hat 5000 ms ( 5 Sekunden ) die Ziffer oder Ziffern einzugeben time_duration = 1 # Ein Sekunde Pause eingebaut, damit der Nutzer den Anfang time.sleep(time_duration) # der Ansage mitbekommt. # Nachfolgend erfolgt das Abspielen eines WAV- oder GSM-Soundfiles, dass den Nutzer # informiert welche Ziffer er zu wählen hat. Der Nutzer kann während des Abspielens # der Sounddatei die gewünschte Ziffer wählen. Sogleich wird er weiterverbunden. # Die Sounddateien lassen sich z.B. mit Text to Speech auf https://ttsmp3.com/ als MP3 erstellen # und anschließend auf https://g711.org/ mit der Standardeinstellung in das g.711-Format # als Wav-Datei umwandeln, die für Asterisk geeignet ist. number = getnumber("/usr/share/asterisk/sounds/eigene/auswahl_menue_ansage",ttanswer,digitcount); # number ist die Ziffer oder die Zahl, die vom Nutzer in die Tastatur des Telefons eingetippt # wurde. # In der if-elif-else Anweisung wird sie in eine Ganzzahl umgewandelt. Diese If-Aweisung # bestimmt, welche Nummern (Extensions) gewählt werden, wenn man # eine Ziffer oder Zahl eintippt. # Tippt man die z.B. die 2 ein, dann wird mit Print ein String ausgedruckt, # der die Variable EXTNEW auf 675 setzt. Diese wird an Asterisk # übergeben, wie nachfolgend noch erklärt wird. if int(number) == 1: print("SET VARIABLE EXTNEW " + "3898") elif int(number) == 2: print("SET VARIABLE EXTNEW " + "675") elif int(number) == 3: print("SET VARIABLE EXTNEW " + "656778") elif int(number) == 4: print("SET VARIABLE EXTNEW " + "878") elif int(number) == 5: print("SET VARIABLE EXTNEW " + "487") elif int(number) == 6: print("SET VARIABLE EXTNEW " + "67856") else: sayit("/usr/share/asterisk/sounds/en_US_f_Allison/beep") time_duration = 2 time.sleep(time_duration) # Wenn der Nutzer die 5 Sekunden verstreichen lässt oder eine # nicht definierte Zahl eintippt, springt das Skript zu # else, es wird eine Sounddatei abgespielt die Piep macht # und dann geht es wieder von vorne los. # # exampel in extensions.conf # #exten => 500,1,Answer() # Hier im Demo die 500 wählen, um ins Menue zu kommen # same => n,AGI(vermittlung.py) # eventuell absolute Pfadangabe notwendig # same => n,NoOP(from script vermittlung.py dialing ${EXTNEW}) # same => n,Goto(telefone,${EXTNEW},1) # Hier wird die Nummer gewählt # same => n,Hangup()
Man muss also im Prinzip nur die If-Schleife und ein Soundfile anpassen. Der Rest kann bleiben.
Selbstverständlich ließen sich zur Schaffung Untermenüs die IF-Anweisungen verschachteln, so dass sich If-Anweisungen innerhalb von If-Anweisungen befinden. Übersichtlicher ist es aber weitere AGI-Skripte zu schreiben, die über Extensions („interne Astersik-Nummern“) aufgerufen werden können.
Aufruf des AGI-Skripts in der Extensions.conf:
[telefone] ; Im Beispiel sollte die Wahlregel im Context telefone stehen exten => 500,1,Answer() # same => n,AGI(auswahlmenue.py) # same => n,NoOP(from script auswahlmenue.py dialing ${EXTNEW}) # same => n,Goto(telefone,${EXTNEW},1) # same => n,Hangup()
Was grundsätzlich bei AGI-Skripten zu beachten ist: Besonders wenn man sie in Windows editiert, ist einiges zu beachten.
AGI-Skripte für Asterisk unter Windows editieren – Was ist zu beachten? – 9. März 2023: Windows ist weit verbreitet. Deshalb schreiben nicht wenige ihre AGI-Skripte auf Windows, um sie dann in ihren Raspberry Pi zu kopieren. Wer einige Dinge nicht beachtet, wird die Skripte nicht zum Laufen bekommen. Hier sind die Fallstricke beschrieben, die mich viel Zeit gekostet haben. Die Beispiele beziehen sich auf Python. Sie haben für andere Programmiersprachen die entsprechende Gültigkeit. – weiter – |
Sound-Dateien mit Text to Speech erstellen:
Erzeugen von Telefon-Ansagen in verschiedenen Sprachen – 3.11.2022: Für einen Anrufbeantworter oder meinen Asterisk-Server benötige ich Sprach-Ansagen in verschiedenen Sprachen. Die weiblichen oder männlichen Stimmen sollten professionell und deutlich klingen. Wie mache ich das für private Zwecke ohne einen Cent dafür zu zahlen? Und alles soll möglichst online erstellt werden können. – weiter – |
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 – |