I have added retrySpeak property to builder.prompt.text incase if the user not responds for a while. But only the text in speak property will be spoken and not retrySpeak text. the below is the dialog which I am triggering from default dialog. I am testing this from cortana mobile app. Is there any property I missed here?
bot.dialog("mainServices", [
function(session){
builder.Prompts.text(session, 'How can I help you?', {
speak: 'How can I help you?',
retrySpeak: 'How can I help you,please say something',
inputHint: builder.InputHint.expectingInput
});
}
])
.triggerAction({
// The user can request this at any time.
// Once triggered, it clears the stack and prompts the main services again.
matches: /^start over$|^go back to main services$|^begin again$|start over services/i,
confirmPrompt: "This will cancel your request. Are you sure?"
});
IPrompt Options retrySpeak
This property is actually a re-prompt for if the response from the user was invalid, as opposed to a lack of response. For example, if speak prompted for a time (in my example a number), and the bot receives a string it cannot parse instead, retrySpeak is prompted asking for a valid message. This is where you can tell the user what input type you are expecting, or to enter a value within a set range, etc.
bot.dialog("/", [
function(session){
builder.Prompts.number(session, 'Please enter a time for your reservation', {
speak: 'Please enter a time, 1-4, for your reservation.',
retryPrompt: 'That is not a number!', //what bot types
retrySpeak: 'I\'m sorry. That is not a valid time. Please enter a time between 1:00 and 4:00', //what Cortana says
inputHint: builder.InputHint.expectingInput
});
},
function(session, results){
console.log(results)
session.endConversation();
}
])
If you are particularly looking for a timeout check, take a look at this botbuilder-timeout package, which reprompts after a certain amount of time. Please keep in mind that it's a third party app and I haven't tested it myself. :)
Related
I was trying to automate a text submit form using cypress. The 'Create student' button is disabled even after all the fields have been filled
Please see the cypress error
code :
it('should be able to add a new student and update the details, remove from the class and delete the account', function () {
cy.visit(
'https://readingeggs.blake-staging.com/district_ui#/reading/manage-schools/students/195286/new'
)
cy.findByLabelText('First Name').type('ark')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click()
cy.get('#main')
.findByRole('alert')
.should('include.text', `Successfully created a student`)
})
})
Be careful using click({force:true}) as suggested in the error message, there may be another problem that your test will now ignore!
You can first try an assertion that the button is not disabled.
Sometimes the test can run too quickly, and the web page has not yet enabled the button before the test tries to click it.
Adding .should('not.be.disabled') will retry this check for up to 4 seconds, which should be enough time for the page to complete changes.
cy.get('[data-test-submit-new-student]')
.should('not.be.disabled')
.click()
If using .should('not.be.disabled') does not work (I agree, it should be the first thing to try), try adding a trigger event to each input - in case the .type() command is not triggering the validation change.
cy.findByLabelText('First Name').type('ark').trigger('change')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last').trigger('change')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1').trigger('change')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey').trigger('change')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click()
If still no joy, use .click({force:true})
By the way, cy.get('[data-test-select-grade]').select('1') looks a bit suspicious. The select command can take a display value as a string or a position value as a number. The screenshot shows "K" is selected, so I would expect either of these to work
cy.get('[data-test-select-grade]').select(1) // number passed
// or
cy.get('[data-test-select-grade]').select('K') // string passed
One option would be to use {force: true} with click().
it('should be able to add a new student and update the details, remove from the class and delete the account', function () {
cy.visit(
'https://readingeggs.blake-staging.com/district_ui#/reading/manage-schools/students/195286/new'
)
cy.findByLabelText('First Name').type('ark')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click({force: true})
cy.get('#main')
.findByRole('alert')
.should('include.text', 'Successfully created a student')
})
I have a problem with input password in webchat.I used Sample - Customize Web Chat with Password Input Activity for password input card when I enter wrong password it show a message like wrong password please try again but when i enter password out of form i need to show another message.
I used this code.
if (card.activity.type === 'message') {
if (
card.activity.from.role === 'bot' &&
(card.activity.text === getLoginMessage(this.props.language) ||
card.activity.text === getLoginRetryMessage(this.props.language))
) {
let message = card.activity.text;
if (!this.hasSubmittedPassword && (card.activity.text === getLoginRetryMessage(this.props.language))) {
message = "Please fill the form and click enter in order to complete your request.";
}
return children => (
<ConnectedPasswordInputActivity
promptMessage={message}
passwordPlaceholder={this.props.literals.password}
language={this.props.language}
handlePasswordSubmit={this.handlePasswordSubmit}
>
{next(card)(children)}
</ConnectedPasswordInputActivity>
);
}
Refer to the image please
This is hard to know for certain as there is a lot of hidden code you are referencing, however I suspect the issue is tied to your hasSubmittedPassword function and your check against it.
You are matching on
A message
From a bot
Where the text equals either the getLoginMessage or getLoginRetryMessage return value
These are passing your check (based on the attached image).
You then check against hasSubmittedPassword which (apparently) is passing and then check a second time on getLoginRetryMessage (???). This second check is unnecessary as you wouldn't be in this if statement if the first check (card.activity.text = this.getLoginRetryMessage(this.props.language) hadn't succeeded.
This can be simplified to:
if (!this.hasSubmittedPassword) {
message = "Please fill the form and click enter in order to complete your request.";
}
That being said, your use of if(!this.hasSubmittedPassword) {...} is only checking if there is a returned value or not. This function may or may not be returning the correct value, but your check doesn't care. It only wants to know IF there is a value. If your logic is setup to always return something (i.e. true, false, yes, no, try again), then it will always pass.
From what I can see, if your first three checks pass, then you will always get the secondary message.
Hope of help!
I have a question. What I want is to show two popup alerts during redirection.
what i do is this :
return redirect()->back()->with('success', sprintf('Image was successfully updated.'))->with('info', sprintf('Please confirm your email.'));
What is see is that the second message overwrites the first one. So when it redirects I can see only the second one.
Is there any solution ?
https://laravel.com/api/5.7/Illuminate/Contracts/View/View.html#method_with
return redirect()->back()->with(
['success' => sprintf('Image was successfully updated.'),
'info' => sprintf('Please confirm your email.')]);
Why are you using sprintf with no formatting of the string? You may as well take it out.
I have a Intent where I have a parameter called age and its value I want it to be the user input.
And in the response I would like to responde with the same input as user given ex:
User Input: Hello, haw are you.
Bot: You said: Hello, haw are you.
So I would need the user input first to store in a parameter and from the Text Response section I can call the parameter but I just don't know how to catch the user input at this moment!
So Text response would be like: You said: $input.
Assuming that you are using Javascript, you can find many useful details here.
Depending on the way you get the input, the solution is totally different.
For instance, in this link you get the input via a click (this.button.addEventListener("click", this.handleClick.bind(this))) or in the following code you get the input as a query.
import {ApiAiClient} from "api-ai-javascript";
import {IRequestOptions, IServerResponse, ApiAiConstants} from "api-ai-javascript/ApiAiClient"
const client = new ApiAiClient({accessToken: 'YOUR_ACCESS_TOKEN'})
queryInput.addEventListener("keydown", queryInputKeyDown);
.textRequest('Hello!')
.then((response) => {console.log(queryInput.value);})
Thus, in the above example, you can use:
value = queryInput.value
you can try it in Inline Editor Fulfillment
function userInput(agent) {
let user_input = agent.query;
//test it
agent.add(user_input);
}
I have an intent-A which is triggered by some user input. When the response is given to user I have used ConfirmIntent instead of Close so that I can switch/chain another intent (lets say intent-B).
Ideally if user type "yes" then intent should be triggered and if user type "no" then it should not. Problem is that intent-B is being triggered no matter what I type.
I have read about ConfirmIntent from here, here and here.
Calling Code:
session_attributes = {"confirmationContext": "AutoPopulate"}
return confirm_intent(session_attributes , 'intent-B', slots, 'Do you want to invoke intent-B')
ConfirmIntent Code:
def confirm_intent(session_attributes, intent_name, slots, message):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ConfirmIntent',
'intentName': intent_name,
'slots': slots,
'message': {
'contentType': 'PlainText',
'content': message
}
}
}
In the logs I can see that confirmationStatus': 'Denied' when I type "no" but even then intent-B is being called.
Am I missing something or is it designed this way?
NOTE: For workaround I am adding below code in the DialogCodeHook of intent-B
if 'confirmationStatus' in intent_request['currentIntent'] and intent_request['currentIntent']['confirmationStatus'] == 'Denied':
return close("Ok, let me know if you need anything else.", session_attributes)
You are handling this correctly.
When you are passing intent-B into your confirm_intent request. You are telling Lex to pass the users response to intent-B. When the user responds with "no", the Denied value is correctly passed on.
Alternatively, you could have intent-A in your confirm_intent request. Then when the response hits intent-A you can use Close on denial and Delegate on confirmation to pass the flow to intent-B. This is "more correct" but will result in additional computation, so it's a trade off.
If you have multiple follow up requests, you could consider using ElicitIntent to instead ask the user "What can I help you with?". Having an an intent with utterances such as "nothing", "goodbye" will catch negative responses. This is a slightly different use case and may not be appropriate for you.