How to create a fallback intent in Amazon Lex or call a Lamda when error is triggered? - amazon-lex

I have a small bot on amazon lex, I am unable to figure out a way to define a default intent or a fallback intent.

As of now, Amazon Lex does not support any fallback intent or default intent. However I have found a workaround. Here's what I did.
Setup an API Gateway and Lambda function in between your chat-client and the Lex.
Your chat-client will send request to API Gateway, API Gateway will forward this to Lambda function and Lambda function will forward the request to Lex (Lex will have one more lambda function). While returning the response from Lex, you can check in the Lambda function if it's an error message and trigger some action.
In the Lambda function we can use something like this:
import logging
import boto3
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
client_run = boto3.client('lex-runtime')
client_model = boto3.client('lex-models')
def lambda_handler(event, context):
response = client_run.post_text(
botName='name_of_your_bot',
botAlias='alias_of_your_bot',
userId='some_id',
sessionAttributes={
'key1': 'value1'
},
inputText=event['user_query']
)
bot_details = client_model.get_bot(
name='name_of_your_bot',
versionOrAlias='$LATEST'
)
for content in bot_details['clarificationPrompt']['messages']:
if response["message"] == content['content']:
return error_handling_method(event)
for content in bot_details['abortStatement']['messages']:
if response["message"] == content['content']:
return error_handling_method(event)
return response["message"]
Hope it helps.

Related

Access session value in gatling checks

I use gatling to send data to an ActiveMQ. The payload is generated in a separate method. The response should also be validated. However, how can I access the session data within the checks
check(bodyString.is()) or simpleCheck(...)? I have also thought about storing the current payload in a separate global variable, but I don't know if this is the right approach. My code's setup looks like this at the moment:
val scn = scenario("Example ActiveMQ Scenario")
.exec(jms("Test").requestReply
.queue(...)
.textMessage{ session => val message = createPayload(); session.set("payload", payload); message}
.check(simpleCheck{message => customCheck(message, ?????? )})) //access stored payload value, alternative: check(bodystring.is(?????)
def customCheck(m: Message, string: String) = {
// check logic goes here
}
Disclaimer: providing example in Java as you don't seem to be a Scala developper, so Java would be a better fit for you (supported since Gatling 3.7).
The way you want to do things can't possibly work.
.textMessage(session -> {
String message = createPayload();
session.set("payload", payload);
return message;
}
)
As explained in the documentation, Session is immutable, so in a function that's supposed to return the payload, you can't also return a new Session.
What you would have to do it first store the payload in the session, then fetch it:
.exec(session -> session.set("payload", createPayload()))
...
.textMessage("#{payload}")
Regarding writing your check, simpleCheck doesn't have access to the Session. You have to use check(bodyString.is()) and pass a function to is, again as explained in the documentation.

How does Kong detect connection timeout?

Currently, whenever an upstream service is down, kong will throw
"{"message":"failure to get a peer from the ring-balancer"}"
I am trying to create a custom plugin that detects the connection time out and return a customized message to the client, the blocker I am facing right now is writing lua codes in my custom plugin to detect the timeout. I have tried using
if(kong.response.get_source() == "error")
but that does not seem to detect timeout either.
Does anyone have any idea what I should do to detect connection timeout in when writing a custom kong plugin?
Sorry, I didn't catch you. Because I don't know what your function will return
If kong.response.get_source() returns a string {"message":"failure to get a peer from the ring-balancer"}
You need to use the JSON library to parse it.
local json = require("json")
local res = json.deceode(kong.response.get_source())
if res.message == "xxx" then
end
But your message is a little long. You can add a new key-value to the JSON string to represent the state.
For example:"{"status":"error","message":"failure to get a peer from the ring-balancer"}"
Then you can write code like this.
local json = require("json")
local res = json.deceode(kong.response.get_source())
if res.status == "error" then
end
I just looked at the Kong API Docs.
I find that the return value of kong.response.get_source() is HTTP status code, such as 200/500.
You can try print(kong.response.get_source()) and see the results.

How to send a speech to text request using google_speech1 in Rust?

I am trying to use google_speech1 for Rust, but the documentation provides incomplete examples, which makes it very hard for me, being both new at Rust and at using Google Speech Api, to figure out how to do send a speech to text request.
More specifically, I would like to be able to send a local audio file, indicate the source language and retrieve the transcription.
Here is the closest I could find in the official documentation(https://docs.rs/google-speech1/1.0.8+20181005/google_speech1/struct.SpeechRecognizeCall.html):
use speech1::RecognizeRequest;
// As the method needs a request, you would usually fill it with the desired information
// into the respective structure. Some of the parts shown here might not be applicable !
// Values shown here are possibly random and not representative !
let mut req = RecognizeRequest::default();
// You can configure optional parameters by calling the respective setters at will, and
// execute the final call using `doit()`.
// Values shown here are possibly random and not representative !
let result = hub.speech().recognize(req)
.doit();
UPDATE
Taking a step back, even simple examples provided on the website don't seem to run properly. Here is some sample very basic code:
pub mod speech_api_demo {
extern crate google_speech1 as speech1;
extern crate hyper;
extern crate hyper_rustls;
extern crate yup_oauth2 as oauth2;
use oauth2::{ApplicationSecret, Authenticator, DefaultAuthenticatorDelegate, MemoryStorage};
use speech1::Speech;
use speech1::{Error, Result};
use std::fs::File;
use std::io::Read;
#[derive(Deserialize, Serialize, Default)]
pub struct ConsoleApplicationSecret {
pub web: Option<ApplicationSecret>,
pub installed: Option<ApplicationSecret>,
}
pub fn speech_sample_demo() {
/*
Custom code to generate application secret
*/
let mut file =
File::open("C:\\Users\\YOURNAME\\.google-service-cli\\speech1-secret.json").unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();
use serde_json as json;
let my_console_secret = json::from_str::<ConsoleApplicationSecret>(&data);
assert!(my_console_secret.is_ok());
let unwrappedConsoleSecret = my_console_secret.unwrap();
assert!(unwrappedConsoleSecret.installed.is_some() && unwrappedConsoleSecret.web.is_none());
let secret: ApplicationSecret = unwrappedConsoleSecret.installed.unwrap();
/*
Custom code to generate application secret - END
*/
// Instantiate the authenticator. It will choose a suitable authentication flow for you,
// unless you replace `None` with the desired Flow.
// Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about
// what's going on. You probably want to bring in your own `TokenStorage` to persist tokens and
// retrieve them from storage.
let auth = Authenticator::new(
&secret,
DefaultAuthenticatorDelegate,
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
<MemoryStorage as Default>::default(),
None,
);
let mut hub = Speech::new(
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
auth,
);
let result = hub.operations().get("name").doit();
match result {
Err(e) => match e {
// The Error enum provides details about what exactly happened.
// You can also just use its `Debug`, `Display` or `Error` traits
Error::HttpError(_)
| Error::MissingAPIKey
| Error::MissingToken(_)
| Error::Cancelled
| Error::UploadSizeLimitExceeded(_, _)
| Error::Failure(_)
| Error::BadRequest(_)
| Error::FieldClash(_)
| Error::JsonDecodeError(_, _) => (println!("{}", e)),
},
Ok(res) => println!("Success: {:?}", res),
}
}
}
Running this code (calling speech_sample_demo) gives the following error:
Token retrieval failed with error: Invalid Scope: 'no description
provided'
I also tried some very ugly code to force the scope into the request, but it did not make any difference. I am having a hard time understanding what this error means. Am I missing something in my request or is it something else getting in the way at the other end? Or maybe that api code library is just broken?
Please also note that client id and client secret provided by default don't work anymore, when I was using those it would say that account is deleted.
I then set up an OAuth 2.0 client and generated the json file which I copied over to default location and then started getting the error above. Maybe it is just me not setting Google Api account properly, but in any case would be great if someone else could try it out to see if I am the only one having those issues.
Once I get over running such a simple request, I have some more code ready to be tested that sends over an audio file, but for now it fails very early on in the process.
The error you get originates from here and means that the OAuth scope you used when generating your credentials file doesn't allow you to access the Google speech API. So the problem is not in your Rust code, but instead in the script you used to generate your OAuth access tokens.
Basically, this means that when you generated your OAuth json file, you requested access to the Google API in a general way, but you didn't say which specific APIs you meant to use. According to this document, you need to request access to the https://www.googleapis.com/auth/cloud-platform scope.
You are missing the flow param to Authenticator. This is how you get the access token. You create an Enum using FlowType.
example:
use oauth2::{ApplicationSecret, Authenticator, DefaultAuthenticatorDelegate, MemoryStorage,FlowType};
let Flo = FlowType::InstalledInteractive;
let auth = Authenticator::new(
&secret,
DefaultAuthenticatorDelegate,
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
<MemoryStorage as Default>::default(),
None,)
See here: https://docs.rs/yup-oauth2/1.0.3/yup_oauth2/enum.FlowType.html
Not exactly easy to figure out.
I made this work via service accounts by doing this
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.build();
let service_account_key: oauth2::ServiceAccountKey = oauth2::read_service_account_key(
&"PATH_TO_SERVICE_ACCOUNT.json".to_string(),
)
.await
.unwrap();
let auth = oauth2::ServiceAccountAuthenticator::builder(service_account_key)
.build()
.await
.unwrap();
let hub = Speech::new(hyper::Client::builder().build(https), auth);

Can't make custom Twilio Call with TwiML Bin and Assets

I am trying to make a twilio call with hosting an xml file on Twilio TwiMl Bins and hosting an mp3 file in Assets:
I just want to say a simple sentence and then play a 5-10 second clip. Currently when I run my code:
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client
# Your Account Sid and Auth Token from twilio.com/console
account_sid = "stuff"
auth_token = "stuff"
client = Client(account_sid, auth_token)
call = client.calls.create(
url="https://handler.twilio.com/twiml/EHdff1ba57cc168191864794c6c44c1723",
from_="+1mytwilionumber",
to="+1mynumber"
)
print(call.sid)
I just get a call - the trial message and then silence and then the call is concluded. Any tips?
Never Mind! So this worked:
https://support.twilio.com/hc/en-us/articles/223132187--Not-Authorized-error-when-trying-to-view-TwiML-Bin-URL
But your twilio call will only run once after you "sign" the HTTP request with hmac authentication. The script is
const crypto = require('crypto')
, request = require('request')
const url = process.argv[2] + '?AccountSid=' + process.env.TWILIO_ACCOUNT_SID
const twilioSig = crypto.createHmac('sha1', process.env.TWILIO_AUTH_TOKEN).update(new Buffer(url, 'utf-8')).digest('Base64')
request({url: url, headers: { 'X-TWILIO-SIGNATURE': twilioSig }}, function(err, res, body) {
console.log(body)
})
Make sure to have node, npm, and request module installed.
npm install request --save
and you are good to go! Run this script right before your python calling script.
Just an fyi you can also make TWIML/robocalls on the fly by uploading your TWIML to a bin, just before you make the call. It just needs a public URL. This project that I found actually demonstrates the technique by uploading the TWIML/XML on the fly, getting the new URL (for the newly generated TWIML), and then makes the Twilio call. That restwords.com site is pretty handy for this purpose.

Amazon Api gateway integration with Twilio

Am trying to Create a SMS bot using help of Twilio, Aws API gateway and AWS lambda.
I ve setup the twilio phone number, AWS API for and lambda. I configured twilio to call my API for every sms i send.
I can see that twilio calling my API Gateway with below details.
URL: https://XXXXXXX.execute-api.us-west-2.amazonaws.com/latest/
Parameters::
ApiVersion=2010-04-01&SmsSid=SM446302f23feac00bdd980eb94af16431&SmsStatus=received&SmsMessageSid=SM446302f23feac00bdd980eb94af16431&NumSegments=1&From=%2B18563135226&ToState=NJ&MessageSid=SM446302f23feac00bdd980eb94af16431&AccountSid=AC056ba4aedfd58f83ad1f8d1827351d3b&ToZip=08057&FromCountry=US&ToCity=MOORESTOWN&FromCity=MOORESTOWN&To=%2B18569246402&FromZip=08057&Body=Hello&ToCountry=US&FromState=NJ&NumMedia=0
Message Text::
Msg=Bad+Request&sourceComponent=14100&ErrorCode=11200&EmailNotification=false&httpResponse=400&LogLevel=ERROR&url=https%3A%2F%2Fzwnu2wzf07.execute-api.us-west-2.amazonaws.com%2Flatest%2F
The API Gateway is not able to process the message.Below is the response from API Gateway.
{"message": "Could not parse request body into json: Unrecognized token \'ToCountry\': was expecting (\'true\', \'false\' or \'null\')\n at [Source: [B#6cbe391e; line: 1, column: 11]"}
Thanks for all the Comments Above. Twilio Sends Request in the format of "application/www-x-form-urlencoded" So we need to have below in the Api Gateway Integration Request.
On the Response Side Twilio accepts "application/xml" Below needs to be configured in the Integration Response of Api Gateway. I have just hardcoded my response but we can configure more in the response box
I am a bit late to the party, but I used following mapping template:
{
#foreach( $token in $input.body.split('&') )
#set( $keyVal = $token.split('=') )
#set( $keyValSize = $keyVal.size() )
#if( $keyValSize >= 1 )
#set( $key = $util.urlDecode($keyVal[0]) )
#set($key = $key.substring(0,1).toLowerCase() + $key.substring(1))
#if( $keyValSize >= 2 )
#set( $val = $util.urlDecode($keyVal[1]) )
#else
#set( $val = '' )
#end
"$key": "$util.escapeJavaScript($val)"#if($foreach.hasNext),#end
#end
#end
}
The request body will be url decoded and submitted as JSON to your Lambda. In case you are using Java you only have to create a POJO to use the actual values.
I just had this problem when going through the Lambda - API Gateway tutorial and using $input.path('$') in the Integration Response as they mention there.
I switched the Integration Response to the following after seeing what was in this tutorial and it worked.
#set($inputRoot = $input.path('$'))
$inputRoot.body

Resources