how to set a slot in a custom action in rasa - rasa-nlu

I'm new to rasa framework. I started developing a simple chatbot and i have created three slots for my chatbot. So my bot need to identify the current location and save it in the slots. My current location is taking from the conversation and i can save it in to the slots in the story.
But then i have a custom action that find the weather weather from an API call and i need to save the weather status and humidity in the relevant slots.
class ActionSomeRespThree(Action):
def name(self) -> Text:
return "action_some_resp_three"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
cityName = tracker.get_slot('city')

You can simply use setSlot method in events.
from rasa_sdk.events import SlotSet
Then in you run method, you can set your value in relevant slot.
Imagine you slot name for humidity is weather_humidity. Then imagine your humidity value from the API is extracted for a variable called humidity. Then in your custom action run method, simply set the slot value with below line.
SlotSet("weather_humidity", humidity)
Make sure that you have defined the slot values in your domain.yml file.

Related

New intent in LUIS for multi turn dialogs

I am going to create a multi-turn dialog. I didn't get how it should be connected with LUIS models. I checked out documentation, but there are samples with only one turn dialogs. Also, I use Virtual Assistant template.
I want to do something like this.
User: I want to book a flight
Bot: What is the destination?
User: London
Bot: When?
User: 21st of September.
Bot: The ticket was bought.
The questions are what happens on the second step? Should I check out dispatcher? Should I add all possible phrases for all steps inside the intent?
General LUIS stuff
For your LUIS model you will need your intents - BookFlight and None. Under your BookFlight intent you will have your Utterances - all the phrases you want to be able to trigger the BookFlight intent.
MyLuisApp
--BookFlight
----I want to book a flight
----Book a flight
----I need a plane ticket
----etc
--None
----Utterances that don't match any of your intents
The none intent is VERY important as per this documentation.
Adding this functionality to a new bot or the core bot template
There are a couple different samples provided on how you could achieve this, but the best way is using Dialogs. What you want is a Waterfall Dialog. Inside this Dialog you can define each stage in the waterfall e.g. Ask for destination, ask for date etc.
In order to trigger the BookFlight waterfall you would have a MainDialog that handled every request, and checks with the LUIS dispatcher link1 and link2 to find out the users intent as per this example. If the intent is BookFlight then you would start the BookFlightDialog which contains the book flight waterfall.
...
// Check dispatch result
var dispatchResult = await cognitiveModels.DispatchService.RecognizeAsync<DispatchLuis>(dc.Context, CancellationToken.None);
var intent = dispatchResult.TopIntent().intent;
if (intent == "BookFlight")
{
// Start BookFlightDialog
await dc.BeginDialogAsync(nameof(BookFlightDialog));
}
General Waterfall Dialog stuff
You'd define your steps as something like:
var waterfallSteps = new WaterfallStep[]
{
AskDestinationAsync,
AskDepartureDateAsync,
ConfirmStepAsync,
FinishDialogAsync,
};
For your scenario there is actually a sample that has already been created with the BookFlight intent available here. There is a full guide on how to get this setup and working in the official documentation. So you can test to see how everything works then modify it as you need.
Other interesting links:
Custom prompt sample - roll your own.
Multi-turn sample - waterfall dialog.
Virtual Assistant stuff
Once you understand how the above works you will be able to modify the Virtual Assistant template to handle the BookFlight intent by taking the following actions:
Adding a BookFlight intent to your existing LUIS DISPATCH app that is connected to your VA template.
Adding utterances to the BookFlight intent.
Save and train your LUIS app.
Publish your LUIS app.
Running the update_cognitive_models.ps1 script as per step 3 of the instructions here which will pull down the changes (your new intent and utterances).
.\Deployment\Scripts\update_cognitive_models.ps1 -RemoteToLocal
NOTE: This command must be run using PowerShell Core and from the root of your project Directory, i.e. inside your Virtual Assistant folder.
The result of running this script should be a bunch of files created locally, as well as the DispatchLuis.cs file being updated to include your new intent. You should also check the Summary.html file that is created to see that your new intent is there. You will now have to update the VA code to actually do something when your new intent is triggered - add another if/case statement inside the RouteAsync method of the MainDialog.cs file - see here for an example.
Something like this:
MainDialog.cs
protected override async Task RouteAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{
// Call to dispatch to get intent
if (intent == DispatchLuis.Intent.bookflight)
{
// Start BookFlightDialog
await dc.BeginDialogAsync(nameof(BookFlightDialog));
}
...
}

How to get only Tweet (only posts) from the timeline?

Whenever tweet is created, it's activity is added to getStream production app.
class Tweet(models.Model, Activity):
user = models.ForeignKey()
text = models.CharField()
class Follow(models.Model, Activity): <- This is adding new activity to the timeline
def follow_feed_lisnner(~)
signal.post_save.connect(~)
class Like(models.Model, Activity): <- Like is adding to activity so timeline automatically shows who liked this post,
My Expectation:
Feed: only shows Tweet on timeline (I don't want to see who started to follow me, or liked any post) - Just Like Instagram!
Notification: Who started to follow me, Who liked my post, Who commented on my post.
views.py
feeds = feed_manager.get_news_feeds(request.user.id)
# get the newsfeed for user.
activities = feeds.get('timeline').get()['results']
activities = enricher.enrich_activities(activities)
Possible Solutions
Use python-stream (more low level) to deal with this problem. (I don't know if it helps)
Maybe I'm missing a cool feature of stream-django
How can we get only Tweet (Not Like, Follow or other activities which should be in notification) on the timeline?
Thank you
UPDATE
If I understood correctly, this should work. Is this valid?
class Follow(models.Model, Activity):
follower =
following
#property
def activity_author_feed(self):
return 'notification'
Activity 1: user A follows user B.
Activity 1 goes to 'user' feed + 'notification' feed (not timeline feed)
//notification feed name already exists so I don't need to create follow feed group
Activity 2: user B creates Post
Activity 2 goes to 'user' feed + 'timeline' feed
Note: I'm assuming your Follow and Like models have a "user" field. If not, best update the question with the full Model classes and also confirm if you're setting up any other following relationships.
The stream-django integration provides an 'Activity' model Mixin and the FeedManager model Manager. They work together to add activities to a Feed Group and Feed whose unique "feed id" is derived from the Model instance.
By default, the feed id is determined by the application wide settings.USER_FEED setting. That should work well for your Tweet model but is probably not what you want for the Follow and Like models. The activities associated with those models ideally belong in separate feeds. This can be setup by overriding the Activity.activity_author_feed property function.
class Follow(models.Model, Activity):
# snipping fields
#property
def activity_author_feed(self):
return 'Follow' # Must match a Feed Group defined in the Stream dashboard
#property
def activity_actor_attr(self):
return self.author
To have to those activities copied into the notification feed, implement the Activity.activity_notify() function to return a list of target feeds.
#property
def activity_notify(self):
return [feed_manager.get_notification_feed(self.user.id)]

Rasa-core, Slots not getting Populated

I am trying to create simple printer support chat bot using rasa-core via nlu interpreter, bot should get the printer model, and printer type and post a issue.
I have used the printermodel and printertype variable in slot and entity, but the slots are not getting populated from the chat string.
Please help me on this.
Not very much information to go off of, but here are several things I would check if my slots weren't being filled correctly:
Is NLU parsing the entities correctly? Slots are usually filled from NLU entities. Send your text direct to the NLU and see if the entities are found.
Entity and Slot names are not consistent? The default method of filling slots without custom programming expects the slot name to match the entity name.
Are the slots defined correctly in the domain information?
If you're still having trouble I encourage you to create an issue or join us on gitter.
For example, we have to design simple conversation
User: I am Shivam
Bot: Hello Shivam
Here, we have to extract name and respond using it.
Step 1: In nlu.md file
## intent:told_name
- i am [shivam](name)
- my name is [shivam](name)
- hi, i am [shivam](name)
Step 2 In domain.yml file
intents:
- told_name
actions:
- utter_greet
entities:
- name
slots:
name:
type: text
templates:
utter_greet:
- text: "Hello {name}"
- text: "Hello {name}, happy to meet you."
Step 3 In stories.md file
# story_01
* told_name{"name": "Mayank"}
- utter_greet
I think, you are missing someting in step 3

How to modify the AppointmentItem.Parent object

I need to set a UserProperty on a master of a recurring Appointment, from an appointment instance.
The scenario is:
a. user opens an instance of a recurring meeting/appointment.
b. my program sets a UserProperty on the master of the appointment series
Getting the master appointment is easy with the Parent property, however it is read-only.
How can I get a modify-able reference to the master appointment?
The code I want to execute is along these lines
Outlook.AppointmentItem masterAppointment = (Outlook.AppointmentItem)(currentAppointment.Parent);
masterAppointment.ItemProperties.Add("xxx", Outlook.OlUserPropertyType.olText);
masterAppointment.ItemProperties["xxx"].Value = aStringValue;
masterAppointment.Save();
What makes you think that AppointmentItem.Parent returns a read-only AppointmentItem?
Do you get an error when you call Save?
If you need to add a custom property, use AppointmentItem.UserProperties.Add.

Designing MVC URL scheme for hierarchical system

So imagine I'm building a Multi User Dungeon system using a MVC web application. To describe the areas the player can explore, the system can contain a number of Maps, which will consist of Rooms and Doors - where doors connect two Rooms.
Consider the authoring part of the system. To create a Map is easy - I need URLs like:
/Author/Maps (an index of my maps)
/Author/Maps/Create (a new Map)
/Author/Maps/Detail/3 (show Map details)
/Author/Maps/Edit/3 (edit map details)
Using a Routing scheme: /Author/{controller}/{action}/{ID}
It's the URLs for the Rooms that I need help with. When creating a new Room, I need to know which Map I'm creating it for.
/Author/Rooms/CreateIn/[mapID] ?
And then for editing a room's details:
/Author/Rooms/Edit/[roomID]
/Author/Rooms/Detail/[roomID]
Would this routing scheme work? And should the view that lists all the Rooms for a Map be an "Index" action on the Rooms controller, with a MapID passed in, or a "Rooms" action on a Map controller?
Thanks.
I don't know if this is best practice, but I would do it like this:
Add a new route: /Author/Maps/{mapID}/Rooms/{action}/{roomID}
Since this is a route that I would only expect to use for the RoomsController, I wouldn't have a {controller} parameter in that route. Just set the controller to "Rooms" in the route's default object.
Then all the actions in your RoomsController would know which map they're working with.
The default Index action for RoomsController could be a list of all the Rooms for the specified map.
The Create action would look like Create(int mapID) and the Details action would look like Details(int mapID, int roomID)
Edit: regarding invalid URLs with a mismatched mapID and roomID, you could just ignore the mapID, but I think the better process would be to validate that the specified mapID is correct and show an error message if it is not.
Edit 2: (additional thoughts regarding the relationship between mapID and roomID)
You could just make roomID unique within the given map. Therefore, map 5, room 3 would be a different room than map 8, room 3.

Resources