I have a ChoicePrompt with two options.
[ {
value: 'credit',
synonyms: ['titanium', 'world', 'credit', 'mastercard'],
},
{
value: 'visaPrepaid',
synonyms: ['platinium', 'visa', 'prepaid', 'prepaid card', 'visa prepaid']
},]
The user can either click on the suggested action or type directly on the textbot "I want a credit card"
I wish to run on a Luis query recognition on this text and extract whether the user wanted a credit or a prepaid card. However, I don't know how to interect that string.
I use a WaterfallDialog to show the prompt
There are a couple different ways to build a ChoicePrompt. I use ChoiceFactory.forChannel() to do so. I'm then using imBack which returns the choice as a user text input. Alternatively, you could do a postBack, which would act as more of a trigger, and capture the sent value.
In my case, since the choice is returned as a user text input, I grab the text value from the activity and send that to LUIS. I'm matching on the Greeting intent which, if successful, then returns the intent found.
Hope of help!
async choiceStep ( stepContext ) {
const stepResult = stepContext.context.activity.text;
if ( stepResult ) {
const message = ChoiceFactory.forChannel(
stepContext.context, [
{ value: 'Hello', action: { type: 'imBack', title: 'Hello', value: 'Hello' } },
{ value: 'What is the date?', action: { type: 'imBack', title: 'What is the date?', value: 'What is the date?' } }
], `Which do you choose?`
);
await stepContext.context.sendActivity( message );
}
return { status: DialogTurnStatus.waiting };
}
async choiceLuisStep ( stepContext ) {
if ( stepContext.context.activity.text ) {
const stepResults = stepContext.context.activity.text;
await stepContext.context.sendActivity( `You said: ${ stepResults }` );
const recognizerResult = await this.recognizer.recognize( stepContext.context );
let intent = await LuisRecognizer.topIntent( recognizerResult );
if ( intent === 'Greeting' ) {
await stepContext.context.sendActivity( `Luis recognized: ${ intent }` );
return stepContext.next();
} else {
await stepContext.context.sendActivity( 'No LUIS intent was found.' );
return stepContext.next();
}
} else {
await stepContext.context.sendActivity( 'Thanks for visiting!' );
return stepContext.next();
}
}
Related
Here is the request type:
interface IgetProductsByGenderRequest extends express.Request {
readonly params: Readonly<{ gender: string; }>;
}
When I'm using req.params.gender I get undefined.
When I'm using req.params I get the param but in object and I want to get it in a var.
My backend controller:
const getProductsByGender = async (
req: IgetProductsByGenderRequest,
res: IgetProductsByGenderResponse
) => {
console.log(req.params)
ServerGlobal.getInstance().logger.info(
`<getProductsByGender>: Start processing request filtered by and gender ${req.params.gender}`
);
if (
!ServerGlobal.getInstance().isValidGenderValue(+req.params.gender)
) {
ServerGlobal.getInstance().logger.error(
`<getProductsByGender>: Failed to get products because of invalid gender filtered by gender ${req.params.gender}`
);
res.status(400).send({
success: false,
message: "Please provide valid gender",
});
return;
}
try {
const products = await ProductDB.find({ gender: +req.params.gender });
ServerGlobal.getInstance().logger.info(
`<getProductsByGender>: Successfully got the products filtered by gender ${req.params.gender}`
);
res.status(200).send({
success: true,
message: "Successfully retrieved products",
data: products.map((product) => ({
id: product.id as string,
gender: {
value: product.gender,
label: ServerGlobal.getInstance().getGenderLabel(product.gender)!,
},
title: product.title,
description: product.description,
price: product.price,
imageFilename: product.imageFilename,
})),
});
return;
} catch (e) {
ServerGlobal.getInstance().logger.error(
`<getProductsByGender>: Failed to get products filtered by gender ${req.params.gender} because of server error: ${e}`
);
res.status(500).send({
success: false,
message: "Server error",
});
return;
}
};
How can I access the gender param?
I suggest reading the documentation regarding routing and regarding query parameters.
You have req.query, which is for query parameters, e.g. /some/path?myVariable=test would have req.query.myVariable === 'test'.
You also have req.params which is when you're using URL parameters, e.g. /some/path/:id would have req.params.id === 'test' when the user visits /some/path/test.
Make sure you are using/accessing the correct one, as it's easy to make mistakes in this regards. And of course watch out for typos, although you should've spotted that with your console.log(req.params) statement.
I'm trying to make the bot basically edit the message of any specific case mentioned for example if i do -case 5 test it will look for case 5 and it's message. So far when i do it, it basically changes the recent case number message, instead of the one i want it to change. like if i do case 5 test and the latest case is #9, it will change 9 instead of 5.
This is how i send the message:
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { $inc: { 'caseID': 1 } }, { new: true }, async function (err, doc) {
if (err) throw err;
if (!doc) return;
if (doc.modLog.enabled) {
if (msg.channel.guild.channels.get(doc.modLog.channelID)) {
let m = await msg.channel.guild.channels.get(doc.modLog.channelID).createMessage({
embed: {
title: `${action} | Case #${doc.caseID}`,
color: colour,
fields: [
{
name: 'User',
value: user,
inline: true
},
{
name: 'Moderator',
value: moderator ? moderator : 'No issuer.',
inline: true
},
{
name: 'Reason',
value: reason ? reason : 'No reason.'
}
]
}
});
doc.messageID = m.id;
doc.type = action;
doc.caseID = doc.caseID;
//doc.caseID = m.id
doc.moderatorID = moderator,
doc.targetID = user
doc.save();
}
}
})
that is how i send my message. And you can see i'm storing the things so when someone changes a specific case's reason, for example: case 5 spamming, i would want it to look for caseID 5, and then edit the message through it's ID. but i'm not sure how am i doing it wrong. I'm trying to make each case store it's own message ID and i would really appreciate any help. This is what i use to look for the case and edit's reason.
Modlog.findOne({ guildID: msg.guildID }, async (err, doc) => {
if (err) throw err;
if (!doc.modLog.enabled) return msg.channel.createMessage(`Modlog is not enabled in this server! ${this.emoji.cross}`);
if (isNaN(Number(caseID))) return msg.channel.createMessage(`Case \`#${caseID}\` was not a number! ${this.emoji.cross}`);
if (doc.caseID === undefined) return msg.channel.createMessage(`Couldn\'t find case \`#${caseID}\`! ${this.emoji.cross}`);
const moderator = this.bot.users.get(doc.moderatorID) || {
username: 'Unknown User',
discriminator: '0000'
}
const target = this.bot.users.get(doc.targetID) || {
username: 'Unknown User',
discriminator: '0000'
}
let embed = {
title: `${doc.type} | Case #${doc.caseID}`,
fields: [
{
name: 'User',
value: `${target.username}#${target.discriminator} (${target.id})`,
inline: true
},
{
name: 'Moderator',
value: `${moderator.username}#${moderator.discriminator} (${moderator.id})`,
inline: true
},
{
name: 'Reason',
value: reason
}
]
};
try {
await this.bot.editMessage(doc.modLog.channelID, doc.messageID, { embed: embed });
await msg.channel.createMessage(`Case **#${caseID}** has been updated. ${this.emoji.tick}`);
} catch (e) {
await msg.channel.createMessage(`I\'m unable to edit that case or it has been deleted. ${this.emoji.cross}`);
}
});```
Solution: Search for Case ID
It seems you didn't look for the case ID, and only looked for the guild's ID in the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { ... }, { ... }, ... {
...
}
In your code, only guildID was passed into the filter parameter. This causes Mongoose to look for the most recently initialized document for the server. For your case, you should also pass caseID into the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id, caseID: caseIDArg }, { ... }, { ... }, ... {
...
}
Replace caseIDArg with your supposed caseID argument in the message's content. For example, args[1] or however you programmed your argument handler to work.
Hope this helped to answer your question!
So what I am trying to do here is when the command is used, the new channel is created, then the user mentions the channel and puts their word, then the hangman is sent within the channel they mentioned. But I get lost cause rn it's running everything at once, how do I make it listen for a new "command"?
const { hangman } = require('reconlx')
module.exports = {
name : 'hangman',
description: "Wanna play hangman?",
aliases: ['hang'],
execute(client, message, args, Discord) {
if(!message.member.hasPermission("MANAGE_MESSAGES")) return message.channel.send('You need manage messages permission.')
const channel = message.mentions.channels.first() || message.guild.channels.cache.get(args[0])
message.guild.channels.create(`HangMan`, {
type: 'text',
permissionOverwrites: [
{
id: message.guild.id,
deny: ['VIEW_CHANNEL']
},
{
id: message.author.id,
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ADD_REACTIONS', 'ATTACH_FILES']
}
]
}).then(async channel => {
channel.send("Please mention a channel, then add your word. It should look something like this `#the game channel (your word)`")
message.reply(`Scroll to the very top of the server to add your word! <#${channel.id}>`)
})
if(message.content.includes('#')) {
message.reply('Hangman has started!')};
if(!channel) return message.channel.send('Please specify a channel')
const word = args.slice(1).join(" ")
if(!word) return message.channel.send('Please specify a word to guess.')
const hang = new hangman({
message: message,
word: word,
client: client,
channelID: channel.id,
})
hang.start();
}
}
How to add multiple embeds to the code below? I am not asking for you to write to code for me I just need some tips and points on how to add embeds. Because I would like to make it so that the new channel is created then you will get 2 or 3 embeds posted to that channel. One embed will have reactions on there and I would like for then the bot to pair 2 random players so they can have a lvl battle again.
if (
guild.channels.cache.find((channel) => channel.name === "t5-battle-channel")
)
return;
if (reaction.emoji.name === "5️⃣") {
let guild = reaction.message.guild;
guild.channels.create("T5 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400016736780338",
allow: ["VIEW_CHANNEL"],
},
],
});
}
if (
guild.channels.cache.find((channel) => channel.name === "t5-battle-channel")
)
return;
if (reaction.emoji.name === "5️⃣") {
let guild = reaction.message.guild;
guild.channels
.create("T5 Battle Channel", {
//Creating the channel
type: "text", //Make sure the channel type is text
permissionOverwrites: [
//Set overwrites
{
id: guild.id,
deny: "VIEW_CHANNEL",
},
{
id: "788400016736780338",
allow: ["VIEW_CHANNEL"],
},
],
})
.then((channel) => {
channel.send(embed).then((embedMessage) => {
embedMessage.react("👍");
embedMessage.react("👎");
});
});
}
let embed = new Discord.MessageEmbed()
.setColor("#0099ff")
.setTitle("⚔️ T5 Battles! ⚔️")
.setDescription(
"Please react with a Thumbs up if you want to be paired with you opponent!"
)
.setTimestamp()
.setFooter("⚔️ 1657 Battles! ⚔️ | ⚔️ Managed by Ukzs⚔️");
I'm trying to create a prompt dialog with hero card list as the choices.
I've created a function that will return the herocard list and use it as the dialog prompt choice.
How can i achieved this? or there is a better way to implement it.
Note: I need to put it in the dialog prompt because I need to implement a sequential conversation. I also put the herocard list in a separate function because I will use it in other dialog prompt.
async selectProduct(stepContext){
return await stepContext.prompt(CHOICE_PROMPT, {
prompt: 'Select Product:',
choices: this.productChoices()
});
}
productChoices(){
const productSeriesOptions = [
CardFactory.heroCard(
'Title 1',
CardFactory.images(['image URL 1']),
CardFactory.actions([
{
type: ActionTypes.ImBack,
title: 'Title 1',
value: 'Value 1'
}
])
),
CardFactory.heroCard(
'Title 2',
CardFactory.images(['image URL 2']),
CardFactory.actions([
{
type: ActionTypes.ImBack,
title: 'Title 2',
value: 'Value 2'
}
])
)
];
return productSeriesOptions;
}
I've included a sample Dialog that demonstrates presenting a carousel of HeroCards to the user (below). The HeroCard has a single button that when clicked results in the next Waterfall step being run.
I originally pulled this dialog from the 'using-cards' sample. So if you wanted to give it a run, you could replace the mainDialog.js in that project and run it in the emulator.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActionTypes, AttachmentLayoutTypes, CardFactory } = require('botbuilder');
const { ChoicePrompt, ComponentDialog, DialogSet, DialogTurnStatus, WaterfallDialog, ChoiceFactory } = require('botbuilder-dialogs');
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';
class MainDialog extends ComponentDialog {
constructor() {
super('MainDialog');
// Define the main dialog and its related components.
this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.showProductChoicesStep.bind(this),
this.showCardSelectionStep.bind(this)
]));
// The initial child Dialog to run.
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a TurnContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} turnContext
* #param {*} accessor
*/
async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
/**
* Send a carousel of HeroCards for the user to pick from.
* #param {WaterfallStepContext} stepContext
*/
async showProductChoicesStep(stepContext) {
console.log('MainDialog.showProductChoicesStep');
await stepContext.context.sendActivity({
attachments: this.productChoices(),
attachmentLayout: AttachmentLayoutTypes.Carousel
});
return { status: DialogTurnStatus.waiting };
}
async showCardSelectionStep(stepContext) {
console.log('MainDialog.showCardSelectionStep');
await stepContext.context.sendActivity('You picked ' + stepContext.context.activity.value);
// Give the user instructions about what to do next
await stepContext.context.sendActivity('Type anything to see another card.');
return await stepContext.endDialog();
}
// ======================================
// Helper functions used to create cards.
// ======================================
productChoices(){
const productSeriesOptions = [
CardFactory.heroCard(
'Product 1',
CardFactory.images(['https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg']),
CardFactory.actions([
{
type: 'messageBack',
title: 'Pick Me',
value: 'product1'
}
])
),
CardFactory.heroCard(
'Product 2',
CardFactory.images(['https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg']),
CardFactory.actions([
{
type: 'messageBack',
title: 'Pick Me',
value: 'product2'
}
])
),
CardFactory.heroCard(
'Product 3',
CardFactory.images(['https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg']),
CardFactory.actions([
{
type: 'messageBack',
title: 'Pick Me',
value: 'product3'
}
])
),
CardFactory.heroCard(
'Product 4',
CardFactory.images(['https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg']),
CardFactory.actions([
{
type: 'messageBack',
title: 'Pick Me',
value: 'product4'
}
])
)
];
return productSeriesOptions;
}
}
module.exports.MainDialog = MainDialog;