Duckling date (or time) only extraction


(André) #1

Is there a way to extract a data only with Duckling?

If an user would want to schedule a meeting on for example next week monday, it would retrieve data+time, which is 2018-08-13T00:00:00.000Z. But I need to extract a time seperatly in case a user only gives a date as input.


(Caleb M Keller) #2

Are you using NLU and Core?

If you are: I would recommend a custom action. Duckling returns a granularity that would be day if the user just said “next Monday” or would be hour if the user said “next Monday at 3pm”. In your custom action you could use the granularity to split the date time returned by duckling and set a date slot and a time slot. But only set the time slot if the grain is hour or minute.

I don’t have the time at the moment to write the custom action, but give it a try and let me know if that works for you.


(André) #3

Awesome, i will give it a try and report back (sorry for the late response, email notification went straight to spam :frowning: )

Edit: Works like a charm thanks! For anyone who’s interested see the example code below: Feedback is always welcome!

class splitdate(Action):
def name(self):
    return 'action_split_date_time'

def run(self, dispatcher, tracker, domain):
    time_slot =  tracker.get_slot('time') #duckling time entity
    date_slot = tracker.get_slot('date_slot') #own date slot
    
    return_slots = []
    
    date = time_slot[0:10]
    time = time_slot[11:19]

    if time_slot == None:
        pass
    else:         
        if date_slot != None:
            pass
        else:
            return_slots.append(SlotSet("date_slot", date))
        
        if time != "00:00:00":
            return_slots.append(SlotSet("time_slot", time))
        else: 
            pass
	
        return_slots.append(SlotSet("time", None))

    return return_slots

(Anders) #4

Nice of you to share your code Andre. Alternatively, you can use dateutil to parse the ISO datetime format.

import dateutil.parser
Class ActionGetDate(Action):

    def name(self):
        return 'custom_act_get_date' #****This is used in the story!****

    def run(self, dispatcher, tracker, domain):

        dictData = next((e for e in tracker.latest_message.entities if
                                   e['entity'] == 'time'), None)
        date = dictData['value']
        datetime_obj = dateutil.parser.parse(date)
        humanDate = datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
        time = datetime_obj.time()
        #dispatcher.utter_message("I got this time: " + time + ". This is the full date: " + humanDate)
        
        return [SlotSet("slot_time", datetime_obj.time()]

(André) #5

Thanks for sharing! I’m not fully aware yet of the possiblities with the tracker (is there any documentation on what i can do with it?). Can you maybe explain what:

next((e for e in tracker.latest_message.entities if e['entity'] == 'time'), None)

does (Still learning python as well).


(Anders) #6

You can look into generators and yield. They use the next() method.

To over-simplify it: tracker.last_message.entities is like a json object we loop over to find the value we are interested in.


(André) #7

Awesome! Thanks :grin: