I have a function outside of the async function which needs to send messages (ctx.send), add reactions (msg.add_reaction) and do something on reaction added. The problem is that I can't use await to do this stuff. I looked online and found bot.loop.create_task() and put every await code I had into it. bot.loop.create_task(bot.get_channel(confirmationsChannel).send(embed=embed)) to send an embed it looks like this and it works but when I want to add a reaction bot.loop.create_task(confirmationEmbed.add_reaction("✅")) it shows an error "AttributeError: '_asyncio.Task' object has no attribute 'add_reaction'". Can someone explain to me how would I achieve that?
Related
Im trying to figure out how to make a discord bot say something a specific user says. For example, if i say something in general the bot says what i said in the text channel. I want it to be user specific but i dont know how to make this in the bot. Thanks to whoever answers this.
You use the on_message(ctx) event. For example:
#client.event
async def on_message(ctx):
message = ctx.content.lower()
if 'hello' in message and ctx.author.id == MY_ID:
await ctx.channel.send('Hey there!')
await client.process_commands(ctx)
Note: await client.process_commands(ctx) is very important, without it, all your commands won't work.
MY_ID is your your Discord ID (an integer value), so the bot will only respond if the author's ID equals your ID.
I am trying to implement a bot which uses Qna services and Azure search.
I am taking help of the C# QnA Maker sample github code.
It is using a BotServices.cs class which is taking a QnA service in its constructor. This Botservice object is being passed to the QnABot class constructor.
I want to use Dialog set in QnABot's constructor which need accessors to be added. I really didn't understand how to add accessor class and use them in the startup.cs
I tried to copy some code from other samples but didn't work.
Please help me to add an accessor to the BotServices constructor so that I can use dialog sets inside of it.
I would like to extend the QnA sample for my purpose.
Can you tell us why you want to pass a dialog set tot the botservices class? this class is only used to reference external services such as QnAMaker and LUIS. If you want to start a Dialog, do so in the OnTurnAsync method of the QnABot.cs class. keep in mind that the this method as it is created in this specific sample will send a response on every message the user sends even if they are working through a dialog. You could change the OnTurnAsync in such a way that the first step in the dialog is to check the QnAMaker. See the enterpriseBot sample to see how to start a dialog as well as adding an accessor to a child Dialog. see the following snipped from the MainDialog.cs class how they added the accessor:
protected override async Task OnStartAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
var onboardingAccessor = _userState.CreateProperty<OnboardingState>(nameof(OnboardingState));
var onboardingState = await onboardingAccessor.GetAsync(innerDc.Context, () => new OnboardingState());
var view = new MainResponses();
await view.ReplyWith(innerDc.Context, MainResponses.Intro);
if (string.IsNullOrEmpty(onboardingState.Name))
{
// This is the first time the user is interacting with the bot, so gather onboarding information.
await innerDc.BeginDialogAsync(nameof(OnboardingDialog));
}
}
I am having trouble creating a reproducible example so bear with me.
I have a library I created that wraps async API responses in an Observable. Simplifying greatly, the library has functions like lib.ask("end-point") that return an Observable with the response of the API call to that end point.
I want to run that API call every time another event happens. I'm attempting to model that with some version of mergeMap/switchMap/concatMap, depending on the situation. Let's use mergeMap as an example.
If I use map + mergeAll, it works just fine. I am writing it like so:
var responses$ = event$.pipe(
map(()=>lib.ask("end-point")),
mergeAll()
);
When I subscribe to responses$, I get my response!
However, if I rewrite the same chain with mergeMap instead, it does not work:
var responses$ = event$.pipe(
mergeMap(()=>lib.ask("end-point"))
);
In this case, when I subscribe I do not get any results. It almost appears as if the inner subscription never gets made.
Like I said, I am struggling to create a reproducible example. I have attempted to debug what RxJS does to try to find where this thing is failing, but have not been able to figure it out. If anyone can think of why or in what situations mergeMap would behave differently than map + mergeAll, that might help me figure out where my problem is.
Quick question about Pusher.js.
I've started working on a notifications functionality today and wanted to do this with Pusher.js, since I used it for my chat.
I'm working in Laravel. What I want to achieve is an application wide subscription to a channel. When a user registrates a channel is being made for him "notifications_channel", which I store in the database. I know how to register a user to a channel, but once he leaves that page, the room vacates. That's not really what I'm looking for, since I'd like to send the user notifications no matter where he is on the platform.
I couldn't really find anything like this in the documentation, so I thought maybe one of you guys know how to do so.
Here are some snippets of what I do:
When the user registrates I fire this:
$generateChannel = User::generateNotificationsChannel($request['email']);
This corresponds to this in my model:
public static function generateNotificationsChannel($email){
$userID = User::getIdByMail($email);
return self::where('email', $email)->update(['notifications_channel' => $userID."-".str_random(35)]);
}
It's fairly basic, but for now that's all I need.
So for now, when the user logs in the Index function of my HomeController is being fired, which gathers his NotificationsChannel from the database and sends it to the view.
public function index()
{
$notificationsChannel = User::getUserNotificationsChannel(\Auth::user()->id);
return view('home', compact('notificationsChannel', $notificationsChannel));
}
Once we get there I simply subscribe the user to that channel and bind him to any events linked to the channel:
var notifications = pusher.subscribe('{{$notificationsChannel}}');
channel.bind('new-notification', notifyUser);
function notifyUser(data){
console.log(data);
}
So as you can see, for now it's pretty basic. But my debug console shows me that the channel vacates as soon as the user leaves /home.
So the question is, how do I make him subscribed to the channel, no matter where he is on the platform?
Any and all help would be deeply appreciated!
Thanks in advance.
I've found a fix to this issue, I've decided to send the notifications-channel to my Master layout, which I use to extend all views after the user has logged in. In my master layout I subscribe the user to his own notifications channel.
For people who might be interested in how I did it:
I altered the boot function of my AppServiceProvider which you can find in \app\Providers\AppServiceProvider. The code looks like this:
public function boot()
{
view()->composer('layouts.app', function($view){
$channel = User::getUserNotificationsChannel(\Auth::user()->id);
$view->with('data', array('channel' => $channel));
});
}
In my Master layout I simply subscribed the user by grabbing the channel name.
I'm building a LuisDialog and have LUIS integration working well.
In the cases where LUIS doesnt fill in all the gaps I need, what is the best approach for disambiguation?
Right now, I use PromptDialog callbacks - So inside a Dialog method (decorated with the LuisIntent attribute), when I need to get more details/disambiguate i'd have:
PromptDialog.Choice<string>(context, EnsureTimeOfDayChosen, new[] { "Morning (AM)", "Afternoon (PM)", "Any" }, "What time of day would you like us to book the appointment? (AM/PM/Any)", "Please choose AM or PM. Alternatively, if you don't mind which, just say Any.");
And the delegate's body (EnsureTimeOfDayChosen):
string AmPmOrAny = await result;
context.PerUserInConversationData.SetValue<string>("TimeOfDay", AmPmOrAny);
BookAppointment(context);
The problem with this approach is the last line of the delegate - it doesn't feel right. I can't easily call back into the place I was in the initially called, LuisIntent decorated method and resume.
Instead, I have to deal with the LUIS info up front, and call the BookAppointment method after gathering more info, and storing it in PerUserInConversationData.
Am I doing it wrong?
Any help would be greatly appreciated - Kind Regards,
Matt.
Given current implementation of the Dialog model, I cannot think of a better way of implementing your logic. Currently anytime that you are waiting on an async response from the user, your code will be resumed on the callback you provided upon response. You can think of it as Begin/End model for async programing