I am trying to do a load test on a chat bot that I deployed on Microsoft Azure bot service, and I am following the blog post on here: https://blog.botframework.com/2017/06/19/load-testing-a-bot/,
I am able to finish the first step, I am able to get auth token and get Mock channel, but for the last step:
it states:
{
"type": "message",
"id": <GUID>,
"channelId" : "test",
"conversation": { "id": <CONVERSATION ID> },
"from": { "id": <USER ID> },
"recipient": { "id": <BOT HANDLE> },
"serviceUrl": <SEE BELOW>
}
I know service URL is the endpoint of the mock channel. but for all other Id, I don't know where can I get it?
Can anyone help me with this? give me some guidance on how to get all those ids?
Thanks a lot.
Node.js
You can get all these by inspecting an activity from your bot, then plugging in valid values in your mock channel for sending the activity. You can get these values by setting a breakpoint at any other point in your process that sends/receives or handles an activity. Just inspect the values and use them accordingly. Remember to do things like switch the from and recipient where needed.
I know you are asking for JavaScript but this is an example of how I am constructing and activity in my mock channel using c#:
Activity a = new Activity
{
Type = ActivityTypes.Message,
Id = "9dn3fa6lh4hd9dn3fa6lh4hd",
ChannelId = Microsoft.Bot.Builder.Dialogs.ChannelIds.Console,
Conversation = new ConversationAccount(id: "9dn3fa6lh4hd"),
From = new ChannelAccount(id: "user", name: "username"),
Recipient = new ChannelAccount(id: "bot", name: "botname"),
Text = "Mock Channel",
ServiceUrl = #"http://localhost:55086/api/values",
MembersAdded = new List<ChannelAccount>(),
MembersRemoved = new List<ChannelAccount>(),
Locale = "en-US",
Attachments = new List<Attachment>(),
ReplyToId = "nii4344blg42",
TextFormat = "plain",
Timestamp = DateTime.Now,
ChannelData = JsonConvert.SerializeObject(new { clientActivityId = "1506483656068.11949484894092266.2" })
};
Related
Hello I'm trying to create a flow in dialogflow cx, where in case of multiple options I want my user to select 1 option where all the options are buttons.
I have used the default payload but not sure how can I send back which button got clicked to my webhook and return respective info, currently if I click on button it simply open example.com, if I exclude the link it opens same page in new tab.
{
"type": "button",
"icon": {
"type": "chevron_right",
"color": "#FF9800"
},
"text": "Button text 1",
"link" : "www.example.com",
"event": {
"name": "some name",
"languageCode": "en",
"parameters": {}
}
}
For your use case, since the button response type always redirects to a page when clicked, you can consider using suggestion chips instead.
{
"richContent": [
[
{
"options": [
{
"text": "Chip 1"
},
{
"text": "Chip 2"
}
],
"type": "chips"
}
]
]
}
Suggestion chips act like a user text query when the user clicks on it, therefore, you can just create a route that can be triggered by text of the chip and get the text query from the webhook request sent to your webhook to return the respective information. For example:
Intent:
Route:
Then in your webhook, you can get the parameter value in the text field of the webhook request which you will refer to in order to create a webhook response with the respective information.
Here’s an example in Node.js using Express:
app.post("/webhook", (req, res) => {
let option = req.body.text;
let jsonResponse = {
fulfillment_response: {
messages: [
{
text: {
//fulfillment text response to be sent to the agent
text: [`You've chosen the ${option} option`]
}
}
]
}
};
res.json(jsonResponse);
});
Alternatively, you can also use entity types and assign the selected chip into a parameter that will be also sent to your webhook.
To assign the text of the chip to a parameter, the intent of the route should contain training phrases that are annotated to an entity type containing all of the options. For example:
Intent:
Entity Type:
Then in your webhook, you can get the parameter value in the intentInfo.parameters.parameter_id.resolvedValue field of the webhook request which you will refer to in order to create a webhook response with the respective information.
Here’s an example in Node.js using Express:
app.post("/webhook", (req, res) => {
let option = req.body.intentInfo.parameters.options.resolvedValue;
let jsonResponse = {
fulfillment_response: {
messages: [
{
text: {
//fulfillment text response to be sent to the agent
text: [`You've chosen the ${option} option`]
}
}
]
}
};
res.json(jsonResponse);
});
Results:
There is a simple albeit hacky way I have discover possible (tested in es). Which is to make a chip and get its element then force clicking it
We can listen to button click and I detect that it was empty button with just text. Then I use renderCustomCard to make a chip. Everything inside dialogflow messenger are hidden deep inside nested shadowRoot. But as of now its structure allow us to get the chip out to call click() on it. In effect it make it seem very the same as user manually click the chip
const dfMessenger = document.querySelector('df-messenger');
dfMessenger.addEventListener('df-button-clicked',function(event) {
if(event.detail.element.event || event.detail.element.link)
return;
dfMessenger.renderCustomCard([
{
"type": "chips",
"options": [
{
"text": event.detail.element.text
}
]
}
]);
var messageList = dfMessenger.shadowRoot.querySelector("df-messenger-chat").shadowRoot.querySelector("df-message-list").shadowRoot;
var chips = [...messageList.querySelectorAll("df-chips")].flatMap((chips) => [...chips.shadowRoot.querySelectorAll(".df-chips-wrapper>a")]).filter((a) => a.innerHTML.indexOf(event.detail.element.text) > -1);
if(chips.length > 0)
chips.slice(-1)[0].click();
});
Working for today. No guarantee they will block this method in the future. But I actually guess they would implement actual postback button in similar manner later after beta version
I am currently trying to create a waterfall that starts with an adaptive card.
Originally I had the waterfall working with ChoicePrompt on every step, but on step 1 I wanted 2 choices to openUrl - so changed to an adaptive card to start (is this required or is there a way to openUrl from a specific response in ChoicePrompt the user gives?)
The issue here is that every response (that isn't the openUrl buttons) leads to the adaptive card to repeat itself rather than pass the non-openUrl choice to the next step of the dialog.
I am also storing each dialog response (currently in an array, which I clear at the end of the dialog) to perform a certain action based on all responses combined (is there a better way to save user responses than pushing into an array?)
var answers = [];
async firstStep(stepContext) {
var send = {
text: 'question',
attachments: [
{
"contentType": "application/vnd.microsoft.card.hero",
"content": {
"text": null,
"buttons": [
{
"type": "imBack",
"title": "one",
"value": "one"
},
{
"type": "openUrl",
"title": "two",
"value": "https://example.com"
},
{
"type": "openUrl",
"title": "three",
"value": "https://example.com"
},
]
}
}
]
}
return await stepContext.context.sendActivity(send);
}
async secondStep(stepContext) {
const resp = stepContext.result.value;
answers.push(resp);
return await stepContext.prompt('ChoicePrompt', {
prompt: questions[1],
choices: ChoiceFactory.toChoices(options[1]),
style: ListStyle.suggestedAction
});
}
async thirdStep(stepContext) {
const resp = stepContext.result.value;
answers.push(resp);
return await stepContext.prompt('ChoicePrompt', {
prompt: questions[2],
choices: ChoiceFactory.toChoices(options[2]),
style: ListStyle.suggestedAction
});
}
async finalStep(stepContext) {
const resp = stepContext.result.value;
answers.push(resp);
// get func
var fun = await this.func(answers);
//do stuff with what function returns
// reset quiz
answers = [];
return await stepContext.endDialog();
}
So to summarise, the initial adaptive card, I would like it to continue to repeat itself if anything other than one is returned, but if one is returned I would like it to move onto the next part of the dialog with that value, and save that value (maybe better than I do above).
Lastly, if there is an easy way to openUrl in the current tab and not a new one that would be great.
Any insight here on how to work with hero cards would be really helpful.
Thanks in advance.
Note: I'm using the 'classic' experience because the new interface doesn't have a way for a template to set up required fields for future signers.
The workflow:
have a template with a bunch of fields
using the api:
create an envelope/document from the template, and assign a new user to sign (this document is going to be an agreement for signing up for a service)
create new role
set roleName to fake signer on template (because I can't configure fields without at least one signer on the template)
add textTabs to try to perfill some of the fields.
retrieve the recipients
create a recipient view so that I get the URL to put in an iframe
This is kind of obnoxious, because I don't care about having a first signer that isn't the user signing up for the service. I would however, like to have the the document be copied to someone after signing, but docusign doesn't appear to support this (that I've found anyway).
Here is the node.js code for the creation of the envelope (where I think my API usage is going wrong):
function createEnvelopeDefinition(templateId, userData) {
var envDef = new docusign.EnvelopeDefinition();
envDef.setEmailSubject('Signup Agreement');
envDef.setTemplateId(templateId);
var tRole = new docusign.TemplateRole();
tRole.setRoleName('RoleOne');
tRole.setName(userData.fullName);
tRole.setEmail(userData.email);
tRole.setClientUserId('2');
tRole.setTabs(new docusign.Tabs());
tRole.getTabs().setTextTabs([]);
const fieldsToPreFill = [
'field1',
'field2',
'field3',
'field4'];
fieldsToPreFill.forEach(fieldName => {
let textTab = new docusign.Text();
let value = userData[fieldName];
if (value === null || value === undefined) { value = 'not null'; }
textTab.setTabLabel(fieldName);
textTab.setValue(value);
tRole.getTabs().getTextTabs().push(textTab);
});
tRole = removeNulls(tRole);
envDef.setTemplateRoles([tRole]);
// send the envelope by setting |status| to 'sent'.
// To save as a draft set to 'created'
// sent is required for getting view URLs
envDef.setStatus('sent');
return envDef;
}
In the template editor on docusign, the Data Field Tag Properties show the label of each of the corresponding fields as field1, field2, etc.
These fields are now filled out with the provided values when I throw the new envelope in an iframe.
just for reference here is the rest of the code that creates the api connection, and gets the view URL
import ENV from 'environment/backend';
const accountId = ENV.docusign.accountId;
var Promise = require('bluebird');
var docusign = require('docusign-esign');
export function newApiClient() {
let apiClient = new docusign.ApiClient();
apiClient.setBasePath(ENV.docusign.endpoint);
// create JSON formatted auth header
let creds = JSON.stringify({
Username: ENV.docusign.email,
Password: ENV.docusign.password,
IntegratorKey: ENV.docusign.integratorKey
});
apiClient.addDefaultHeader('X-DocuSign-Authentication', creds);
// assign api client to the Configuration object
// this probably doesn't need to be set every time...
docusign.Configuration.default.setDefaultApiClient(apiClient);
return apiClient;
}
const defaultApiClient = newApiClient();
const envelopesApi = new docusign.EnvelopesApi();
const createEnvelope = Promise.promisify(envelopesApi.createEnvelope, { context: envelopesApi });
const listRecipients = Promise.promisify(envelopesApi.listRecipients, { context: envelopesApi });
const createRecipientView = Promise.promisify(envelopesApi.createRecipientView, { context: envelopesApi });
export default defaultApiClient;
// promise resolves to the view URL, envelopeId for the user.
// returns a recipientView
export function setupDocumentForEmbeddedSigning(templateId, userData) {
let envDefinition = createEnvelopeDefinition(templateId, userData);
return createEnvelope(accountId, envDefinition, null)
.then(envelopeSummary => {
const envelopeId = envelopeSummary.envelopeId;
return createViewFromEnvelope(envelopeId);
});
}
export function createViewFromEnvelope(envelopeId) {
return getRecipients(envelopeId).then(recipients => {
// the last signer is the one we added in the
// createEnvelopeDefinition step
let signers = recipients.signers;
let lastSigner = signers[signers.length - 1];
return createView(envelopeId, lastSigner)
.then(recipientView => [recipientView.url, envelopeId]);
});
}
function getRecipients(envelopeId) {
return listRecipients(accountId, envelopeId);
}
function createView(envelopeId, signerData) {
var viewRequest = new docusign.RecipientViewRequest();
viewRequest.setReturnUrl(ENV.host);
viewRequest.setAuthenticationMethod('email');
// recipient information must match embedded recipient info
// from the createEnvelopeDefinition method
viewRequest.setEmail(signerData.email);
viewRequest.setUserName(signerData.name);
viewRequest.setRecipientId('2');
viewRequest.setClientUserId('2');
return createRecipientView(accountId, envelopeId, viewRequest);
}
// bug with the api wrapper
// https://github.com/docusign/docusign-node-client/issues/47
const removeNulls = function(obj) {
var isArray = obj instanceof Array;
for (var k in obj) {
if (obj[k] === null) isArray ? obj.splice(k, 1) : delete obj[k];
else if (typeof obj[k] == 'object') removeNulls(obj[k]);
if (isArray && obj.length == k) removeNulls(obj);
}
return obj;
};
So, I may not fully understand where you're stuck, but I'll take a crack at this anyway...
Let's say I create a Template using the DocuSign UI and define two Recipient roles:
Signer1 (which will be the person who is signing up for your service) -- Action = "Sign"
CarbonCopy1 (which will be the person who gets a copy of the completed/signed documents once Signer1 signs) -- Action = "Receive a Copy"
(Note: these roles can be named whatever you want to name them -- I named them "Signer1" and "CarbonCopy1" so it'd be clear who each role represents.)
Assuming the above scenario, your Template's Recipient Roles (in the DocuSign UI) will look like this:
Next, let's assume that you define some fields (tabs) in the Template's document(s) (i.e., using the DocuSign UI) that the Signer1 recipient will need to populate when they sign the document(s). For this example, let's assume that the label (name) of one of those Text tabs is field1. Notice that the field is assigned to the Signer1 recipient:
Now, if I want to create an Envelope via the API that uses this Template, and pre-fill fields for one or more of the recipients, the key to doing that is using the "Composite Templates" structure in the API request. (See the Composite Templates section of this page for details.) In the example described above, your compositeTemplates object in the API request would contain a single serverTemplate object (which specifies the templateId and sequence=1), and a single inlineTemplate object (which specifies sequence=2 and the recipient info, including values for any tabs (fields) that you want to pre-fill).
In the example described above, the JSON API request to create the Envelope would look like this (assuming we're just pre-filling a single field for Signer1 -- obviously you could pre-fill additional fields by simply including them in the tabs object of the request along with field1):
POST https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes
{
"emailSubject": "Test Pre-fill Tabs",
"emailBlurb": "This is a test.",
"compositeTemplates": [{
"serverTemplates": [{
"sequence": "1",
"templateId": "CD0E6D53-3447-4A9E-BBAF-0EB2C78E8310"
}],
"inlineTemplates":[{
"sequence": "2",
"recipients": {
"signers": [
{
"roleName": "Signer1",
"recipientId": "1",
"name": "John Doe",
"email": "johndoe#test.com",
"clientUserId": "1234",
"tabs": {
"textTabs": [
{
"tabLabel": "field1",
"value": "TEST-123"
}
]
}
},
{
"roleName": "CarbonCopy1",
"recipientId": "2",
"name": "Jane Doe",
"email": "janedoe#test.com"
}
]
}
}]
}],
"status": "sent"
}
Once I create the Envelope using the above request, I execute a "POST Recipient View" request to get the signing URL for the first recipient (https://{{env}}.docusign.net/restapi//v2/accounts/{{accountId}}/envelopes/{{envelopeId/views/recipient).
Then, when I subsequently use the URL that's returned in that response to launch the signing session for Signer1 (John Doe), I see that the field1 tab is indeed pre-filled with the value that I specified in the "Create Envelope" API request (TEST-123):
Furthermore, once John Doe (Signer1) finishes signing and submits the completed documents, Jane Doe (CarbonCopy1) will be sent a copy.
I'm not familiar with the DocuSign Node SDK, but imagine you can figure out the syntax to use composite templates as shown in the above example. Hope this helps!
In telegram API documentation I see: "You can either pass a file_id as String to resend a photo that is already on the Telegram servers", but I can't find ways to get file_id of uploaded file. How can I get it?
Its depended to your content_types ,for example:
Video:
message.video.file_id
Audio:
message.audio.file_id
Photo:
message.photo[2].file_id
For more see this link.
This is the easiest way I've found to do it.
Upload your file to any chat and forward the message to #RawDataBot. It will return something like this:
{
"update_id": 754677603,
"message": {
"message_id": 403656,
"from": {
"id": xxx,
"is_bot": false,
"first_name": "xxx",
"username": "xxx",
"language_code": "en"
},
"chat": {
"id": xxx,
"first_name": "xxx",
"username": "xxx",
"type": "private"
},
"date": 1589342513,
"forward_from": {
"id": xxx,
"is_bot": false,
"first_name": "xxx",
"username": "xxx",
"language_code": "en"
},
"forward_date": 1589342184,
"document": {
"file_name": "filename.pdf",
"mime_type": "application/pdf",
"file_id": "This_Is_The_Thing_You_Need",
"file_unique_id": "notthis",
"file_size": 123605
}
}
}
What you need is the string under file_id. Once you have copied that, you can simply the following code to send the message.
context.bot.sendDocument(chat_id=update.effective_chat.id,
document = "Your_FILE_ID_HERE")
Depending on the method (File type) which you chose to send a file, after sending a file to Telegram a response is returned. For example if you send a MP3 file to Telegram using sendAudio method, Telegram returns an Audio object which contains the file ID.
Source: https://core.telegram.org/bots/api#audio
In addition to the answers above, you can log Updates that comes to your bot, Either from https://api.telegram.org/bot'.BOT_TOKEN.'/getUpdates or throw updates that come in your application. there you will find a Json property like below:
{
"update_id" = 1111111,
"message" =
{
"message_id" = 1111111,
"from" =
{
"id" = 111111,
...
}
"chat" =
{
"id" = 111111,
...
}
"date" = 111111,
"photo" =
{
{
"file_id" = HERE IS YOU FILE ID 1,
"file_size" => XXXX,
"width" => XX,
"height" => XX,
}
}
}
}
Say you receive a Message with an array of PhotoSize
https://core.telegram.org/bots/api#photosize
As you can see, there's a file_id, you can use this to send a photo through sendPhoto.
If we assume Update is an object, with in it a Message object, which in turn provides a Chat object with in it a id of the chat where the initial message came from and an array of PhotoSize (excuse me for using PHP here, but that's my main language...)
$update->message->photo is how you can access the array.
Use some kind of For loop to iterate over the items, or just access the first one if the array isn't bigger than 1.
After that, you can use the result(s) to extract the file_id and send it as a string via sendPhoto's photo parameter and the Chat ID via the chat_id parameter.
I hope this helped!
P.S. Here is a diagram of my current implementation of the API, i hope it brings some clarity to you!
if you use PHP:
you can write this line for full size:
$file_id = $updates['message']['photo'][1]['file_id'];
and this line for thumb:
$file_id = $updates['message']['photo'][0]['file_id'];
According to the latest docs (v20.0a6) plenty of classes have been changed. I have found that the easiest way to get started with files is using the effective_attachment property.
async def handle_file(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
media_item = await context.bot.get_file(update.message.effective_attachment[0].file_id)
media_url = media_item.file_path
For declaring the handler there have also been changes to filters, here is a simple way to declare it:
application.add_handler(MessageHandler(filters.ATTACHMENT, handle_file))
I am using paypal REST API to test out express checkout on sandbox environment.
Everything works fine except one thing: order description area is rather empty: no summs, no individual item information, no total order sum amount - I can see only my dummy description" regardless that I do pass order summ amount.
I am passing payment information similar to one used in the example apps:
var ppPayment = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {},
"transactions": [{
"amount": {
"currency": "EUR",
"details": {
"subtotal": 0
}
}
}]
};
ppPayment.transactions[0].amount.total = params.req_order_amount;
ppPayment.redirect_urls.return_url = "http://xxxxxxxxx/confirm?order_id=" + order_id;
ppPayment.redirect_urls.cancel_url = "http://xxxxxxxxx/cancel?order_id" + order_id;
ppPayment.transactions[0].description = "Dummy description";
ppPayment.transactions[0].amount.details.subtotal = params.req_order_amount;
What lines should I add to the payment.create call to user to be able to see the description like displayed here ?
Follow the API
PayPal REST API Reference
You need to create transaction object inside which item_list object consisting of items. Lets name one item object or and go by your screenshot :
paypalItem.name
..until 6. : See API for item object. Some fields only exist in invoice_item object
..until 10. : See API for Invoice object
Good luck
So the explicit answer will be :
ppPayment.transactions[0].amount.total = params.req_order_amount;
ppPayment.redirect_urls.return_url = "http://xxxxxxxxx/confirm?order_id=" + order_id;
ppPayment.redirect_urls.cancel_url = "http://xxxxxxxxx/cancel?order_id" + order_id;
ppPayment.transactions[0].description = "Dummy description";
ppPayment.transactions[0].amount.details.subtotal = params.req_order_amount;
ppPayment.transactions[0].item_list =
{
items: [{quantity: 1, name: 'My stuff', price: params.req_order_amount, currency: "USD"}]
};