From 3159c5f081f24b8acfdbe72b768a532891932fb5 Mon Sep 17 00:00:00 2001 From: maxkahan Date: Mon, 13 Jan 2025 17:31:17 +0000 Subject: [PATCH] add final voice snippets --- .env.dist | 1 + voice/connect-an-inbound-call.py | 2 +- voice/connect-callers-to-a-conference.py | 35 +++++----- voice/handle-user-input-with-asr.py | 83 ++++++++++++------------ voice/handle-user-input.py | 72 ++++++++++---------- voice/join-outbound-calls.py | 31 --------- voice/play-tts-into-call.py | 4 +- voice/record-a-call.py | 2 +- voice/record-a-message.py | 2 +- voice/track-ncco.py | 79 ++++++++++------------ voice/transfer-a-call.py | 24 ++++--- voice/transfer-call-inline-ncco.py | 56 +++++----------- 12 files changed, 163 insertions(+), 228 deletions(-) delete mode 100755 voice/join-outbound-calls.py diff --git a/.env.dist b/.env.dist index a77d5b4..d03d4b4 100644 --- a/.env.dist +++ b/.env.dist @@ -81,6 +81,7 @@ CONFERENCE_NAME='NAME_OF_YOUR_CONFERENCE' YOUR_SECOND_NUMBER='YOUR_SECOND_NUMBER' RECORDING_URL='RECORDING_URL' CALL_UUID='CALL_UUID' +LANGUAGE='en-US' # Numbers COUNTRY_CODE='GB' diff --git a/voice/connect-an-inbound-call.py b/voice/connect-an-inbound-call.py index 3583719..d0290d0 100755 --- a/voice/connect-an-inbound-call.py +++ b/voice/connect-an-inbound-call.py @@ -12,7 +12,7 @@ app = FastAPI() -@app.get('/answer') +@app.get('/webhooks/answer') async def inbound_call(): ncco = [ Connect( diff --git a/voice/connect-callers-to-a-conference.py b/voice/connect-callers-to-a-conference.py index c689914..7708ca0 100644 --- a/voice/connect-callers-to-a-conference.py +++ b/voice/connect-callers-to-a-conference.py @@ -1,29 +1,24 @@ -#!/usr/bin/env python3 -from flask import Flask, jsonify +import os from os.path import join, dirname from dotenv import load_dotenv -import os +from fastapi import FastAPI +from vonage_voice.models import Conversation, NccoAction, Talk -app = Flask(__name__) - -dotenv_path = join(dirname(__file__), "../.env") +dotenv_path = join(dirname(__file__), '../.env') load_dotenv(dotenv_path) +VONAGE_NUMBER = os.environ.get('VONAGE_NUMBER') +YOUR_SECOND_NUMBER = os.environ.get('YOUR_SECOND_NUMBER') CONFERENCE_NAME = os.environ.get("CONFERENCE_NAME") -@app.route("/webhooks/answer") -def answer_call(): - ncco = [ - { - "action": "talk", - "text": "Please wait while we connect you to the conference" - }, - { - "action": "conversation", - "name": CONFERENCE_NAME - }] - return jsonify(ncco) +app = FastAPI() + +@app.get('/webhooks/answer') +async def answer_call(): + ncco: list[NccoAction] = [ + Talk(text="Please wait while we connect you to the conference"), + Conversation(name=CONFERENCE_NAME), + ] -if __name__ == '__main__': - app.run(port=3000) + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] diff --git a/voice/handle-user-input-with-asr.py b/voice/handle-user-input-with-asr.py index 1744a74..8f71f87 100644 --- a/voice/handle-user-input-with-asr.py +++ b/voice/handle-user-input-with-asr.py @@ -1,44 +1,47 @@ -#!/usr/bin/env python3 -from flask import Flask, request, jsonify - -app = Flask(__name__) - - -@app.route("/webhooks/answer", methods=["POST", "GET"]) -def answer_call(): - ncco = [ - {"action": "talk", "text": "Please, tell me something",}, - { - "action": "input", - "type": ["speech"], - "eventUrl": [ - "{host}{endpoint}".format( - host=request.host_url, endpoint="webhooks/asr" - ) - ], - "speech": { - "endOnSilence": 1, - "language": "en-US", - "uuid": [request.args.get("uuid")], # Change to request.json.get("uuid") if using POST-JSON webhook format - }, - }, +import os +from os.path import join, dirname +from dotenv import load_dotenv +from fastapi import FastAPI, Body, Request +from vonage_voice.models import Input, NccoAction, Speech, Talk + +dotenv_path = join(dirname(__file__), '../.env') +load_dotenv(dotenv_path) + +VONAGE_NUMBER = os.environ.get('VONAGE_NUMBER') +RECIPIENT_NUMBER = os.environ.get('RECIPIENT_NUMBER') + +app = FastAPI() + + +@app.get('/webhooks/answer') +async def answer_call(request: Request): + ncco: list[NccoAction] = [ + Talk(text=f'Please tell me something.'), + Input( + type=['speech'], + speech=Speech( + endOnSilence=1, + language='en-US', + uuid=[request.query_params.get('uuid')], + ), + eventUrl=[str(request.base_url) + '/webhooks/asr'], + ), ] - return jsonify(ncco) - -@app.route("/webhooks/asr", methods=["POST", "GET"]) -def answer_asr(): - body = request.get_json() - if body is not None and "speech" in body: - speech = body["speech"]["results"][0]["text"] - ncco = [ - {"action": "talk", "text": "Hello ,you said {speech}".format(speech=speech)} - ] - else: - ncco = [{"action": "talk", "text": "Sorry, i don't undertand. Bye"}] - - return jsonify(ncco) + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] -if __name__ == "__main__": - app.run(port=3000) +@app.post('/webhooks/asr') +async def answer_asr(data: dict = Body(...)): + if data is not None and 'speech' in data: + speech = data['speech']['results'][0]['text'] + return [ + Talk(text=f'Hello ,you said {speech}').model_dump( + by_alias=True, exclude_none=True + ) + ] + return [ + Talk(text=f'Sorry, I didn\'t understand your input.').model_dump( + by_alias=True, exclude_none=True + ) + ] diff --git a/voice/handle-user-input.py b/voice/handle-user-input.py index 2059606..7f88986 100755 --- a/voice/handle-user-input.py +++ b/voice/handle-user-input.py @@ -1,42 +1,36 @@ -#!/usr/bin/env python3 -from pprint import pprint -from flask import Flask, request, jsonify - -app = Flask(__name__) - - -@app.route("/webhooks/answer") -def answer_call(): - for param_key, param_value in request.args.items(): - print("{}: {}".format(param_key, param_value)) - input_webhook_url = request.url_root + "webhooks/dtmf" - ncco = [ - { - "action": "talk", - "text": "Hello, please press any key to continue." - }, - { - "action": "input", - "type": ["dtmf"], - "maxDigits": 1, - "eventUrl": [input_webhook_url] - } - ] - return jsonify(ncco) - - -@app.route("/webhooks/dtmf", methods=['POST']) -def dtmf(): - data = request.get_json() - pprint(data) - ncco = [ - { - "action": "talk", - "text": "You pressed {}, goodbye".format(data['dtmf']) - } +import os +from os.path import join, dirname +from dotenv import load_dotenv +from fastapi import FastAPI, Body, Request +from vonage_voice.models import Input, NccoAction, Talk + +dotenv_path = join(dirname(__file__), '../.env') +load_dotenv(dotenv_path) + +VONAGE_NUMBER = os.environ.get('VONAGE_NUMBER') +RECIPIENT_NUMBER = os.environ.get('RECIPIENT_NUMBER') + +app = FastAPI() + + +@app.get('/webhooks/answer') +async def answer_call(request: Request): + ncco: list[NccoAction] = [ + Talk(text=f'Please enter a digit.'), + Input( + type=['dtmf'], + maxDigits=1, + eventUrl=[str(request.base_url) + '/webhooks/dtmf'], + ), ] - return jsonify(ncco) + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] -if __name__ == '__main__': - app.run(port=3000) + +@app.post('/webhooks/dtmf') +async def answer_dtmf(data: dict = Body(...)): + return [ + Talk(text=f'Hello, you pressed {data['dtmf']}').model_dump( + by_alias=True, exclude_none=True + ) + ] diff --git a/voice/join-outbound-calls.py b/voice/join-outbound-calls.py deleted file mode 100755 index e2dcf0d..0000000 --- a/voice/join-outbound-calls.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 -from flask import Flask, jsonify - -app = Flask(__name__) - - -@app.route("/webhooks/answer") -def answer_call(): - ncco = [ - { - "action": "connect", - "from": "NEXMO_NUMBER", - "endpoint": [{ - "type": 'phone', - "number": "RECIPIENT_NUMBER_1" - }] - }, - { - "action": "connect", - "from": "VONAGE_NUMBER", - "endpoint": [{ - "type": 'phone', - "number": "RECIPIENT_NUMBER_2" - }] - } - ] - return jsonify(ncco) - - -if __name__ == '__main__': - app.run(port=3000) diff --git a/voice/play-tts-into-call.py b/voice/play-tts-into-call.py index d443dbe..cddbc23 100644 --- a/voice/play-tts-into-call.py +++ b/voice/play-tts-into-call.py @@ -12,6 +12,7 @@ ) CALL_UUID = os.environ.get('CALL_UUID') +LANGUAGE = os.environ.get('LANGUAGE') from vonage import Auth, Vonage from vonage_voice.models import CallMessage, TtsStreamOptions @@ -25,7 +26,8 @@ ) response: CallMessage = client.voice.play_tts_into_call( - uuid=CALL_UUID, tts_options=TtsStreamOptions(text='Hello from Vonage.') + uuid=CALL_UUID, + tts_options=TtsStreamOptions(text='Hello from Vonage.', language=LANGUAGE), ) pprint(response) diff --git a/voice/record-a-call.py b/voice/record-a-call.py index d6ab479..2cee9dc 100755 --- a/voice/record-a-call.py +++ b/voice/record-a-call.py @@ -28,7 +28,7 @@ async def inbound_call(): ), ] - return [step.model_dump(by_alias=True, exclude_none=True) for step in ncco] + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] @app.post('/webhooks/recordings') diff --git a/voice/record-a-message.py b/voice/record-a-message.py index a22057e..227e4c1 100755 --- a/voice/record-a-message.py +++ b/voice/record-a-message.py @@ -18,7 +18,7 @@ async def answer_call(request: Request): Talk(text='Thank you for your message.'), ] - return [step.model_dump(by_alias=True, exclude_none=True) for step in ncco] + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] @app.post('/webhooks/recordings') diff --git a/voice/track-ncco.py b/voice/track-ncco.py index 829516d..9251667 100644 --- a/voice/track-ncco.py +++ b/voice/track-ncco.py @@ -1,43 +1,36 @@ -from flask import Flask, request, jsonify - -app = Flask(__name__) - - -@app.route("/webhooks/answer") -def answer_call(): - ncco = [{ - "action": "talk", - "text": "Thanks for calling the notification line" - }, - { - "action": "notify", - "payload": { - "foo": "bar" - }, - "eventUrl": [ - "{url_root}webhooks/notification".format(url_root=request.url_root) - ] - }, - { - "action": "talk", - "text": "You will never hear me as the notification URL will return an NCCO " - }] - return jsonify(ncco) - - -@app.route("/webhooks/notification", methods=['POST']) -def notification(): - ncco = [{ - "action": "talk", - "text": "Your notification has been received, loud and clear" - }] - return jsonify(ncco) - - -@app.route("/webhooks/event", methods=['POST']) -def event(): - return "OK" - - -if __name__ == '__main__': - app.run(host="localhost", port=3000) +import os +from os.path import join, dirname +from dotenv import load_dotenv +from fastapi import FastAPI, Body, Request +from vonage_voice.models import NccoAction, Notify, Talk + +dotenv_path = join(dirname(__file__), '../.env') +load_dotenv(dotenv_path) + +VONAGE_NUMBER = os.environ.get('VONAGE_NUMBER') +RECIPIENT_NUMBER = os.environ.get('RECIPIENT_NUMBER') + +app = FastAPI() + + +@app.get('/webhooks/answer') +async def inbound_call(request: Request): + ncco: list[NccoAction] = [ + Talk(text=f'Thanks for calling the notification line.'), + Notify( + payload={"foo": "bar"}, + eventUrl=[str(request.base_url) + '/webhooks/notification'], + ), + Talk(text=f'You will never hear me as the notification URL will return an NCCO.'), + ] + + return [action.model_dump(by_alias=True, exclude_none=True) for action in ncco] + + +@app.post('/webhooks/notification') +async def on_notification(): + return [ + Talk(text=f'Your notification has been received, loud and clear').model_dump( + by_alias=True, exclude_none=True + ) + ] diff --git a/voice/transfer-a-call.py b/voice/transfer-a-call.py index 0f1dc1b..ea92179 100755 --- a/voice/transfer-a-call.py +++ b/voice/transfer-a-call.py @@ -1,22 +1,26 @@ -#!/usr/bin/env python3 import os from os.path import join, dirname -from pprint import pprint -import vonage from dotenv import load_dotenv dotenv_path = join(dirname(__file__), "../.env") load_dotenv(dotenv_path) VONAGE_APPLICATION_ID = os.environ.get("VONAGE_APPLICATION_ID") -VONAGE_APPLICATION_PRIVATE_KEY_PATH = os.environ.get("VONAGE_APPLICATION_PRIVATE_KEY_PATH") +VONAGE_APPLICATION_PRIVATE_KEY_PATH = os.environ.get( + "VONAGE_APPLICATION_PRIVATE_KEY_PATH" +) UUID = os.environ.get("UUID") -client = vonage.Client( - application_id=VONAGE_APPLICATION_ID, - private_key=VONAGE_APPLICATION_PRIVATE_KEY_PATH, +from vonage import Auth, Vonage + +client = Vonage( + Auth( + application_id=VONAGE_APPLICATION_ID, + private_key=VONAGE_APPLICATION_PRIVATE_KEY_PATH, + ) ) -dest = {"type": "ncco", "url": ["https://raw.githubusercontent.com/nexmo-community/ncco-examples/gh-pages/text-to-speech.json"]} -response = client.voice.update_call(UUID, action="transfer", destination=dest) -pprint(response) +client.voice.transfer_call_answer_url( + UUID, + 'https://raw.githubusercontent.com/nexmo-community/ncco-examples/gh-pages/text-to-speech.json', +) diff --git a/voice/transfer-call-inline-ncco.py b/voice/transfer-call-inline-ncco.py index 6858805..3957e9f 100644 --- a/voice/transfer-call-inline-ncco.py +++ b/voice/transfer-call-inline-ncco.py @@ -1,52 +1,26 @@ -# Import dependencies import os from os.path import join, dirname -import vonage from dotenv import load_dotenv -import time -# Load the environment -envpath = join(dirname(__file__), './.env') -load_dotenv(envpath) +dotenv_path = join(dirname(__file__), "../.env") +load_dotenv(dotenv_path) -# Init the client - -client = vonage.Client( - application_id=os.getenv('VONAGE_APPLICATION_ID'), - private_key=os.getenv("VONAGE_PRIVATE_KEY") +VONAGE_APPLICATION_ID = os.environ.get("VONAGE_APPLICATION_ID") +VONAGE_APPLICATION_PRIVATE_KEY_PATH = os.environ.get( + "VONAGE_APPLICATION_PRIVATE_KEY_PATH" ) +UUID = os.environ.get("UUID") -response = client.voice.create_call({ - "to": [{"type": "phone", "number": os.getenv('TO_NUMBER')}], - "from": {"type": "phone", "number": os.getenv('FROM_NUMBER')}, - "ncco": [ - { - "action": "talk", - "text": "This is just a text whilst you tranfer to another NCCO" - }, - # Play hold music until the call is transferred - { - "action": "stream", - "streamUrl": [ - "https://example.com/hold-music.mp3" - ], - "loop": "0" - } - ] -}) - -# Give the recipient time to answer -time.sleep(5) +from vonage import Auth, Vonage +from vonage_voice.models import Talk -response = client.voice.update_call( - response["uuid"], { - "action": "transfer", - "destination": { - "type": "ncco", - "ncco": [{"action": "talk", "text": "hello world"}] - } - } +client = Vonage( + Auth( + application_id=VONAGE_APPLICATION_ID, + private_key=VONAGE_APPLICATION_PRIVATE_KEY_PATH, + ) ) +ncco = [Talk(text='Your call has been transferred to a new NCCO.')] -print(response) +client.voice.transfer_call_ncco(UUID, ncco)