Ejemplo n.º 1
0
def getattributes(uinput, context, attributes):
  '''This function marks the entities in user input, and updates
  the attributes dictionary'''
  # Can use context to to context specific attribute fetching
  if context.name.startswith('IntentComplete'):
    return attributes, uinput
  else:

    files = os.listdir('./entities/')
    entities = {}
    for fil in files:
      lines = open('./entities/' + fil).readlines()
      for i, line in enumerate(lines):
        lines[i] = line[:-1]
      entities[fil[:-4]] = '|'.join(lines)

    for entity in entities:
      for i in entities[entity].split('|'):
        if i.lower() in uinput.lower():
          attributes[entity] = i
    for entity in entities:
      uinput = re.sub(entities[entity], r'$' + entity, uinput, flags=re.IGNORECASE)

    if context.name == 'num_passengers' and context.active:
      match = re.search('[0-9]+', uinput)
      if match:
        if int(match[0]) > 0:
          uinput = re.sub('[0-9]+', '$num_passengers', uinput)
          attributes['num_passengers'] = match.group()
          context.active = False
      else:
        num = text2int(uinput)
        if num > 0:
          uinput = '$num_passengers'
          attributes['num_passengers'] = num
          context.active = False

    elif context.name == 'luggage' and context.active:
      match = re.search('[0-9]+', uinput)
      if match:
        uinput = re.sub('[0-9]+', '$luggage', uinput)
        attributes['luggage'] = match.group()
        context.active = False
      else:
        num = text2int(uinput)
        uinput = '$luggage'
        attributes['luggage'] = num
        context.active = False

    return attributes, uinput
Ejemplo n.º 2
0
    def parse(self, doc):
        sides, count = None, None

        for word in doc:
            if "d" in str(word).lower() or word.lemma_ == "coin":
                d_spl = str(word).lower().split("d")
                if word.lemma_ == "coin":
                    sides = 2
                else:
                    if word.lemma_ in ["die", "dice"]:
                        sides = 6
                    else:
                        # get sides and count
                        sides = int(d_spl[1])

                if "d" in str(word).lower() and d_spl[0]:
                    count = int(d_spl[0])
                else:
                    # get count from previous token
                    count_token = word.nbor(-1)
                    if str(count_token) == "a":
                        count = 1
                    else:
                        try:
                            count = int(str(count_token))
                        except ValueError:
                            count = utils.text2int(str(count_token))
        return sides, count
Ejemplo n.º 3
0
		def _to_num(text):
			if text == "to":
				return 2
			elif text == "for":
				return 4
			try:
				return int(text)
			except ValueError:
				return utils.text2int(text)
Ejemplo n.º 4
0
 def run(self, doc):
     sentence = next(doc.sents)
     expression = ""
     if str(sentence.root) == "divide":
         for child in sentence.root.children:
             if child.dep_ == "dobj":
                 try:
                     value = int(str(child))
                     expression += str(value)
                 except Exception as e:
                     expression += str(utils.text2int(str(child)))
                 expression += "/"
             elif child.dep_ == "prep" and str(child) == "by":
                 try:
                     value = int(str(next(child.children)))
                     expression += str(value)
                 except Exception as e:
                     expression += str(
                         utils.text2int(str(next(child.children))))
     else:
         for token in sentence:
             print("{} - {}, {}".format(str(token), token.pos_, token.dep_))
             if token.pos_ == "NUM":
                 try:
                     value = int(str(token))
                     expression += str(value)
                 except Exception as e:
                     expression += str(utils.text2int(str(token)))
             elif token.pos_ in ["CONJ", "VERB"
                                 ] or token.dep_ == "quantmod":
                 if str(token) == "plus":
                     expression += "+"
                 elif str(token) == "minus":
                     expression += "-"
                 elif str(token) == "times":
                     expression += "*"
                 elif str(token.lemma_) == "divide" or str(token) == "over":
                     expression += "/"
             elif token.pos_ == "SYM":
                 expression += str(token)
     print("expression: {}".format(expression))
     solution = eval(expression)  # FIXME: potential security exploit here
     print("solution: {}".format(solution))
     feedback.ShowNotify("{} = {}".format(expression, solution))
Ejemplo n.º 5
0
 def parse_target_time(
     self, doc, now=datetime.datetime.now()) -> datetime.datetime:
     if utils.find_word(doc, ["hour", "minute", "second"]):
         all_time_ents = [
             ent for ent in doc.ents if ent.label_ in ["TIME", "CARDINAL"]
         ]
         if len(all_time_ents) > 0:
             start_i = all_time_ents[0][0].i
             end_i = all_time_ents[-1][-1].i + 1
             if end_i < len(doc):
                 additional = utils.find_word(doc,
                                              ["hour", "minute", "second"],
                                              min_idx=end_i)
                 while additional:
                     # the entity parser didn't quite get all the tokens
                     end_i = additional.i + 1
                     additional = utils.find_word(
                         doc, ["hour", "minute", "second"], min_idx=end_i)
         else:
             time_word = utils.find_word(doc, ["hour", "minute", "second"])
             start_i = utils.select_number_bleedy(time_word.nbor(-1))[0].i
             while time_word:
                 end_i = time_word.i + 1
                 time_word = utils.find_word(doc,
                                             ["hour", "minute", "second"],
                                             min_idx=end_i)
         seconds = utils.parse_duration_to_seconds(doc[start_i:end_i])
         return now + datetime.timedelta(seconds=seconds)
     else:
         all_time_ents = [
             ent for ent in doc.ents
             if ent.label_ == "CARDINAL" or ent.label_ == "TIME"
         ]
         if len(all_time_ents) > 0:
             start_i = all_time_ents[0][0].i
             end_i = all_time_ents[-1][-1].i + 1
         else:
             num_tokens = [
                 token for token in doc
                 if token.like_num or token.text in ["am", "pm"]
             ]
             start_i = num_tokens[0].i
             end_i = num_tokens[-1].i + 1
         if utils.find_word(doc, ["am", "pm"]):
             target_time, _ = cal.parseDT(doc[start_i:end_i].text,
                                          sourceTime=now)
         else:
             target_time = now.replace(
                 hour=(utils.text2int(doc[start_i:end_i].text) + 12 *
                       (now.hour < 12)) % 24,
                 minute=0,
                 second=0,
                 microsecond=0)
         if target_time < now:
             target_time += datetime.timedelta(days=1)
         return target_time
Ejemplo n.º 6
0
						def _to_string_num_filtered(s):
							s = str(s).replace(":", "").replace("-", "")
							if not s:
								return s
							if s == "to":
								return "2"
							if s == "for":
								return "4"
							if s in ["point", "dot"]:
								return "."
							try:
								float(s)
								return s
							except ValueError:
								return str(utils.text2int(str(s)))
Ejemplo n.º 7
0
 def get_the_number(self, doc):
     answers = ["Nice, would you like to add something?",
                "Perfect, anything else?",
                "Well done, do you wish to add something else?"]
     num = 0
     for j in doc:
         if j.text == 'a':
             num = 1
         if j.pos_ == 'NUM' or (j.tag_ == 'LS' and j.pos_ == 'PUNCT'):
             try:
                 num = int(j.lemma_)
             except ValueError:
                 num = text2int(j.lemma_)
             break
     if num == 0:
         return "Please, specify a number!"
     else:
         self.orders[self.bar.get_drink(self.suggested_drink.name)] = num
         self.suggested_drink = None
         self.state = self.States.WAITING_ORDER
         return random.choice(answers)
Ejemplo n.º 8
0
def getTimeInSeconds(token):
    log.debug("orth: {}".format(token.orth_))
    multiplier = 1
    if "second" in token.orth_.lower():
        multiplier = 1
    elif "minute" in token.orth_.lower():
        multiplier = 60
    elif "hour" in token.orth_.lower():
        multiplier = 60 * 60
    elif "day" in token.orth_.lower():
        multiplier = 60 * 60 * 24
    elif str(token) in ["beginning", "start"]:
        multiplier = 0
    #return int(str(token).split(" ")[0])
    num = 0
    for child in token.children:
        log.debug(f"{token} child: {child}")
        if child.like_num or child.text == "a":
            try:
                num = int(child.text)
            except ValueError:
                num = utils.text2int(child.text)
    return int(num) * multiplier
Ejemplo n.º 9
0
    def parse(self, current_volume: float, sentence) -> float:
        """
		current_voiume: The current volume in this context.
		sentence: spaCy parsed sentence

		returns the target volume as float, or a string, either "mute" or "unmute"
		"""
        assert isinstance(current_volume, float)
        assert not isinstance(sentence, str)

        percent = None
        volumeaction = None

        # TODO: rewrite this mess using the new util functions

        for word in sentence:
            if word.lemma_ in ["mute", "unmute"]:
                return word.lemma_
            if word.lemma_ in ["increase", "decrease", "turn", "volume"]:
                for token in sentence:
                    if token.i < word.i:
                        continue
                    if not volumeaction:
                        if token.lemma_ == "up" or word.lemma_ == "increase":
                            volumeaction = "increase"
                        if token.lemma_ == "down" or word.lemma_ == "decrease":
                            volumeaction = "decrease"
                    if token.lemma_ == "to":
                        volumeaction = "set"
                        break
                if not volumeaction:
                    volumeaction = "set"

        if str(sentence.root) == "set" or str(
                sentence.root) == "increase" or str(
                    sentence.root) == "decrease":
            if volumeaction == None: volumeaction = str(sentence.root)
        elif sentence.root.text.lower() == "turn":
            for child in sentence.root.children:
                if child.dep_ == "prt":
                    if str(child) == "up":
                        if volumeaction == None: volumeaction = "increase"
                    elif str(child) == "down":
                        if volumeaction == None: volumeaction = "decrease"
        elif str(sentence.root) == "volume":
            for child in sentence.root.children:
                if str(child) in ["increase", "decrease"]:
                    volumeaction = str(child)

        for child in sentence:
            #print ("child: {0}: {1}".format(child, child.dep_))
            if child.dep_ == "prep":
                if str(child) == "to" or str(child) == "at":
                    volumeaction = "set"
                elif str(child) == "by":
                    pass
                else:
                    continue
                for prepchild in child.children:
                    #print ("prepchild: {0}: {1}".format(prepchild, prepchild.dep_))
                    if prepchild.dep_ == "pobj":
                        #print(str(prepchild))
                        if str(prepchild) == "%" or str(
                                prepchild) == "percent":
                            for n in prepchild.children:
                                #print ("n: {0}: {1}".format(n, n.dep_))
                                if n.dep_ == "nummod":
                                    p = str(n)
                                    break
                        else:
                            if prepchild.like_num and not prepchild.is_digit:
                                numtext = utils.select_number_bleedy(
                                    prepchild).text
                                percent = utils.text2int(numtext) / 100
                            else:
                                p = str(prepchild)

                        if not percent:
                            percent = float(p.rstrip('%')) / 100
                        break
            elif child.is_digit:
                percent = float(child.text.rstrip('%')) / 100

        if volumeaction and volumeaction != "set" and percent == None:
            percent = 0.10
            log.debug(
                "percent unspecified, using arbitrary percentage: {}".format(
                    percent))

        if volumeaction == "increase":
            return round(current_volume + percent, 2)
        elif volumeaction == "decrease":
            return round(current_volume - percent, 2)

        if not percent:
            raise Exception("Unable to parse input")

        return round(percent, 2)
Ejemplo n.º 10
0
	def parse(self, doc):
		"""
		Returns a i3-msg command with arguments to complete the action.
		"""
		workspace_token = utils.find_word(doc, ["workspace", "space", "desktop"])
		workspace_number = None
		if workspace_token:
			num_token = workspace_token.nbor(1)

			if num_token.lemma_ == "number":
				num_token = workspace_token.nbor(2)

			# just in case the input filtering doesn't catch these cases
			if num_token.text.lower() in ["to", "for"]:
				workspace_number = { "to": 2, "for": 4 }[num_token.text.lower()]

			try:
				workspace_number = int(num_token.text)
			except:
				try:
					workspace_number = utils.text2int(num_token.text.lower())
				except Exception as e:
					log.debug(f"Failed to parse workspace number: {e}")

		verb_word = utils.find_word(doc, ["switch", "focus", "show", "pull", "go", "move", "put", "kill", "close", "quit", "toggle", "enable", "disable", "make"])

		# target_token indicates the target entity the request is referencing
		# used for requests like "show me steam" or "switch to the web browser"
		# FIXME: do something more robust
		target_token = utils.find_word(doc, ["this", "that", "steam", "browser", "firefox", "discord", "telegram", "calculator", "gedit", "editor", "studio", "blender", "spotify", "vlc"])
		if target_token and target_token.text not in ["this", "that"]:
			matching_windows = self.find_matching_windows_in_tree(self.get_tree(), target_token.text.lower())
			log.info(f"Found {len(matching_windows)} matching windows")

		command = None
		# switching workspaces
		if verb_word.lower_ in ["switch", "focus", "show", "pull", "go"]:
			if target_token:
				if len(matching_windows) > 0:
					command = f'i3-msg \'[con_id="{matching_windows[0]["id"]}"] focus\''
				else:
					raise Exception("Could not find any windows matching query")
			elif workspace_token and workspace_number:
				command = f'i3-msg "workspace {workspace_number}"'
			else:
				# TODO: create Exception specifically for parsing failures
				raise Exception("Failed to parse input for workspace number")
		# moving windows to other workspaces
		elif verb_word.lower_ in ["move", "put"]:
			if workspace_token.nbor(-1).text in ["to", "on"] or (workspace_token.i >= 2 and workspace_token.nbor(-2).text in ["to", "on"]):
				# This means that we are moving a window to the target workspace
				if not workspace_token or not workspace_number:
					# TODO: create Exception specifically for parsing failures
					raise Exception("Unable to parse for target workspace")
				if target_token and target_token.text not in ["this", "that"]:
					if len(matching_windows) > 0:
						command = f'i3-msg \'[con_id="{matching_windows[0]["id"]}"] focus; move container to workspace number {workspace_number}\''
					else:
						raise Exception("Could not find any windows matching query")
				elif target_token and target_token.text in ["this", "that"]:
					command = f'i3-msg "move container to workspace number {workspace_number}"'
				else:
					raise Exception("Failed to parse which program to move")
			else:
				# This means that we are moving the target workspace to a different output
				direction = utils.find_word(doc, ["up", "down", "left", "right", "primary"])
				if not direction:
					raise Exception("Failed to parse which direction to move the current workspace")
				# if workspace_number:
					# NOTE: this is not yet supported by i3
					# command = 'i3-msg "move workspace {} to output {}"'.format(workspace_number, direction.text)
				command = f'i3-msg "move workspace to output {direction.text}"'
		elif verb_word.lower_ in ["kill", "close", "quit"]:
			if target_token and target_token.text not in ["this", "that"]:
				if len(matching_windows) > 0:
					command = f'i3-msg \'[con_id="{matching_windows[0]["id"]}"] focus; kill\''
				else:
					raise Exception("Could not find any windows matching query")
			elif target_token and target_token.text in ["this", "that"]:
				command = 'i3-msg "kill"'
			else:
				raise Exception("Failed to parse which program to kill")
		elif verb_word.lower_ in ["toggle", "enable", "disable", "make"]:
			verb_word = utils.find_word(doc, ["toggle", "enable", "disable", "make"])
			attribute_word = utils.find_word(doc, ["fullscreen", "floating", "full", "float"])
			if verb_word and attribute_word:
				verb = verb_word.text
				if verb == "make":
					verb = "enable"
				attribute = attribute_word.text
				if attribute == "full":
					attribute = "fullscreen"
				elif attribute == "float":
					attribute = "floating"
				if target_token and target_token.text not in ["this", "that"]:
					if len(matching_windows) > 0:
						command = f'i3-msg \'[con_id="{matching_windows[0]["id"]}"] focus; {attribute} {verb}\''
					else:
						raise Exception("Could not find any windows matching query")
				else:
					command = f'i3-msg "{attribute} {verb}"'
			else:
				raise Exception(f"verb_word ({verb_word}) or attribute_word ({attribute_word}) not found")
		else:
			raise Exception(f"Unknown verb {verb_word.text}")

		return command
Ejemplo n.º 11
0
    def delete_item(self, doc):
        # spacy returns verbs at infinity form with .lemma_
        delete_verbs = ["remove", "delete", "drop"]
        ans_remove = ["I have removed [noun1].",
                      "As you wish, so I've deleted [noun1].",
                      "No problem [noun1] successfully removed!"]
        ans_ending = ["Do you wish to add or remove something?",
                      "Do you wish to order or remove something else?",
                      "Would you like to add or remove some other drinks?"]
        ans_donthave = ["You didn't order any [noun1].",
                        "Sorry but you didn't take any [noun1]."]
        ans_not_understood = ["I am not programmed to understand the rest of what you just said.",
                              "My circuits do not provide any info for the other items."]
        ans_recap = ["So far you have ordered [noun1].",
                     "A quick recap of what you've ordered: [noun1],"]

        ans_invalid = ["I couldn't delete [noun1] because you went below zero.",
                       "If I remove [noun1] you would end up with a negative order, so I cannot do it."]

        bad_items = {}  # set()
        deleted_items = {}
        not_understood = False

        print(list(doc.noun_chunks))
        # noun_chunks:  spacy command which divides 'noun plus the words' describing the noun
        for span in doc.noun_chunks:
            root = span.root
            if root.dep_ == 'nsubj':  # ex I or Mary , this noun_chunk is not relevant
                continue

            if (((root.pos_ == 'NOUN' or root.pos_ == "PROPN") and root.dep_ == 'dobj' and
                 root.head.lemma_ in delete_verbs) or
                    (root.dep_ == 'conj' and (root.head.pos_ == 'NOUN' or root.head.pos_ == "PROPN")) or
                    (root.dep_ == 'appos' and (root.head.pos_ == 'NOUN' or root.head.pos_ == "PROPN"))):

                long_name = []
                num = 1
                for child in root.children:
                    if child.dep_ == 'compound':
                        long_name.append(child.text)
                    if child.pos_ == 'NUM' and child.dep_ == 'nummod':
                        try:
                            num = int(child.lemma_)
                        except ValueError:
                            num = text2int(child.lemma_)

                long_name.append(root.lemma_)
                composed_name = ''
                for n, i in enumerate(long_name):
                    if n == len(long_name) - 1:
                        composed_name = composed_name + i
                    else:
                        composed_name = composed_name + i + ' '

                composed_name = composed_name.lower()

                flag = True
                if composed_name in [drink.name for drink in self.orders.keys()]:
                    deleted_items.setdefault(composed_name, 0)
                    deleted_items[composed_name] += num  # works also with unspecified number = 1
                else:
                    for category in Drink.CATEGORY:
                        if composed_name in self.get_drink_list(category):
                            flag = False
                            bad_items[composed_name] = category  # add(composed_name)  # items not in the list
                    if flag:
                        not_understood = True

        answer = []
        # Processing positive part:
        deleted_real = {}
        invalid_delete = {}
        if deleted_items:
            # self.state = self.States.WAITING_ORDER
            for item in deleted_items:

                # self.orders.setdefault(self.bar.get_drink(item), 0)
                old_n = self.orders[self.bar.get_drink(item)]
                if old_n > deleted_items[item]:
                    self.orders[self.bar.get_drink(item)] -= deleted_items[item]
                    deleted_real[item] = deleted_items[item]
                elif old_n == deleted_items[item]:
                    del self.orders[self.bar.get_drink(item)]
                    deleted_real[item] = deleted_items[item]
                else:
                    invalid_delete[item] = deleted_items[item]

            if deleted_real:
                noun1 = join_with_and([str(num) + ' ' + item for item, num in deleted_real.items()])
                part_neg = random.choice(ans_remove)
                part_neg = part_neg.replace('[noun1]', noun1)
                answer.append(part_neg)
            if invalid_delete:
                noun1 = join_with_and([str(num) + ' ' + item for item, num in invalid_delete.items()])
                part_invalid = random.choice(ans_invalid)
                part_invalid = part_invalid.replace('[noun1]', noun1)
                answer.append(part_invalid)

        # Processing bad items part:
        if bad_items:
            part_donthave = random.choice(ans_donthave)
            noun1 = join_with_and(list(bad_items.keys()))
            part_donthave = part_donthave.replace('[noun1]', noun1)
            answer.append(part_donthave)

            # Recap
            part_recap = random.choice(ans_recap)
            noun1 = join_with_and([str(num) + ' ' + drink.name for drink, num in self.orders.items()])
            part_recap = part_recap.replace("[noun1]", noun1)
            answer.append(part_recap)

        # Processing not understood part:
        if deleted_items and not bad_items and not_understood:
            answer.append(random.choice(ans_not_understood))

        if len(answer) == 0:
            return None

        # Adding final question:
        answer.append(random.choice(ans_ending))
        return ' '.join(answer)
Ejemplo n.º 12
0
    def confirmation_suggestion(self, doc):
        positive_simple = ['yes', 'positive', 'okay', 'ok', 'alright', 'right', 'good', 'yeah', 'cool', 'course',
                           'yep', 'certainly', 'sure', 'fine']
        positive_expression = ['of course', 'why not?', 'good idea', 'all right']
        negative_simple = ['no', "nope", "enough", 'finished', 'nope', 'negative', 'modify']

        answers_pos = ["Okay, I've just added it. Would you like to add something else?",
                       "Perfect, anything else?",
                       "You'll see, it's magnificent! Do you wish to add something else?"]
        answer_num = ["Excellent, how many [noun1] do you want?",
                      "Perfect, how many [noun1] should I prepare?"]

        for token in doc:
            if token.text in positive_simple:
                num = 0
                for j in doc:
                    if j.text == 'a':
                        num = 1
                    if j.pos_ == 'NUM':
                        try:
                            num = int(j.lemma_)
                        except ValueError:
                            num = text2int(j.lemma_)
                        break
                if num != 0:
                    self.orders[self.bar.get_drink(self.suggested_drink.name)] = num
                    self.suggested_drink = None
                    self.state = self.States.WAITING_ORDER
                    return random.choice(answers_pos)
                else:
                    self.state = self.States.NUMBER_SUGGESTED
                    # print(self.suggested_drink.name)
                    answer = random.choice(answer_num)
                    answer = answer.replace('[noun1]', self.suggested_drink.name)
                    return answer
            if token.text in negative_simple:
                self.suggested_drink = None
                self.state = self.States.WAITING_ORDER
                return "No problem, so what else would you like?"

        for phrase in positive_expression:
            if phrase in doc.text:
                num = 0
                for j in doc:
                    if j.text == 'a':
                        num = 1
                    if j.pos_ == 'NUM':
                        try:
                            num = int(j.lemma_)
                        except ValueError:
                            num = text2int(j.lemma_)
                        break
                if num != 0:
                    self.orders[self.bar.get_drink(self.suggested_drink.name)] = num
                    self.suggested_drink = None
                    self.state = self.States.WAITING_ORDER
                    return random.choice(answers_pos)
                else:
                    self.state = self.States.NUMBER_SUGGESTED
                    # print(self.suggested_drink.name)
                    answer = random.choice(answer_num)
                    answer = answer.replace('[noun1]', self.suggested_drink.name)
                    return answer
Ejemplo n.º 13
0
    def specific_order(self, doc):
        # spacy returns verbs at infinity form with .lemma_
        ordering_verbs = ["order", "like", "have", "take", "make", "give", "want", "get", "buy", "add"]
        ans_pos = ["Ok I will add [noun1] to the list!",
                   "Ok I have added [noun1] to the order.",
                   "Good choice with [noun1]."]
        ans_donthave = ["Unfortunately we don't have [noun1].",
                        "Unfortunately we ran out of [noun1].",
                        "Sorry but we don't have any [noun1]."]
        ans_not_understood = ["I am not programmed to understand the rest of what you just said.",
                              "My circuits do not provide any info for the other items."]
        ans_suggest = ["I can suggest you a fresh [noun1]. Would you like it?"]
        ans_ending = ["Would you like something else?",
                      "Do you wish to order something else?",
                      "Would you like to add some other drinks?"]

        bad_items = {}  # set()
        ordered_items = {}
        not_understood = False

        print(list(doc.noun_chunks))
        # noun_chunks:  spacy command which divides 'noun plus the words' describing the noun
        for span in doc.noun_chunks:
            root = span.root
            if root.dep_ == 'nsubj':  # ex I or Mary , this noun_chunk is not relevant
                continue

            # nome puntato dal verbo di odinazione o nome puntato da un altro nome (puntato da verbo di ordinazione)
            if (((root.pos_ == 'NOUN' or root.pos_ == "PROPN") and root.dep_ == 'dobj' and
               root.head.lemma_ in ordering_verbs) or
               (root.dep_ == 'conj' and (root.head.pos_ == 'NOUN' or root.head.pos_ == "PROPN")) or
               (root.dep_ == 'appos' and (root.head.pos_ == 'NOUN' or root.head.pos_ == "PROPN"))):

                long_name = []
                num = 1
                for child in root.children:
                    if child.dep_ == 'compound':
                        long_name.append(child.text)
                    if child.pos_ == 'NUM' and child.dep_ == 'nummod':
                        try:
                            num = int(child.lemma_)
                        except ValueError:
                            num = text2int(child.lemma_)

                long_name.append(root.lemma_)
                composed_name = ''
                for n, i in enumerate(long_name):
                    if n == len(long_name) - 1:
                        composed_name = composed_name + i
                    else:
                        composed_name = composed_name + i + ' '

                composed_name = composed_name.lower()

                flag = True
                if composed_name in [drink.name for drink in self.bar.get_drinks()]:
                    ordered_items.setdefault(composed_name, 0)
                    ordered_items[composed_name] += num  # works also with unspecified number = 1
                else:
                    for category in Drink.CATEGORY:
                        if composed_name in self.get_drink_list(category):
                            flag = False
                            bad_items[composed_name] = category  # add(composed_name)  # items not in the list
                    if flag:
                        not_understood = True

        answer = []
        # Processing positive part:
        if ordered_items:
            self.state = self.States.WAITING_ORDER
            for item in ordered_items:
                self.orders.setdefault(self.bar.get_drink(item), 0)
                self.orders[self.bar.get_drink(item)] += ordered_items[item]

            if not not_understood and not bad_items:
                noun1 = 'that'
            else:
                noun1 = join_with_and([str(num) + ' ' + item for item, num in ordered_items.items()])

            part_pos = random.choice(ans_pos)
            part_pos = part_pos.replace('[noun1]', noun1)
            answer.append(part_pos)

        # Processing bad items part:
        if bad_items:
            part_donthave = random.choice(ans_donthave)
            noun1 = join_with_and(list(bad_items.keys()))
            part_donthave = part_donthave.replace('[noun1]', noun1)
            answer.append(part_donthave)

            # Giving a suggestion:
            if len(bad_items) > 1 and not ordered_items:
                ordered_categories = list(bad_items.values())
                part_suggest = ''
                for cat in ordered_categories:
                    intro = 'Our list of  ' + cat + 's is the following: '
                    part_suggest = part_suggest + intro + join_with_and([drink.name for
                                                                         drink in self.bar.get_drinks(cat)])
                answer.append(part_suggest)
            elif len(bad_items) == 1:
                self.state = self.States.ACCEPT_SUGGESTION
                bad_item = list(bad_items.keys())[0]
                a = self.suggest(ordered_items, category=bad_items[bad_item])
                self.suggested_drink = a
                part_suggest = random.choice(ans_suggest)
                part_suggest = part_suggest.replace('[noun1]', a.name)
                answer.append(part_suggest)

        # Processing not understood part:
        if ordered_items and not bad_items and not_understood:
            answer.append(random.choice(ans_not_understood))

        if len(answer) == 0:
            return None

        # Adding final question:
        if not len(bad_items) == 1:
            answer.append(random.choice(ans_ending))
        return ' '.join(answer)
Ejemplo n.º 14
0
	def extract_parameters(self, doc):
		"""
		Extracts action and parameters for human_input

		Returns a tuple, a string of the action and a tuple of the parameters.
		"""
		sentence = next(doc.sents)

		inputaction = None

		# extract the action
		for word in sentence:
			if word.lemma_ in ["click", "move", "press", "scroll"]:
				inputaction = word.lemma_
				break
			if word.lemma_ in ["type", "dictate"]:
				inputaction = "type"
				break

		# default parameters
		click_param = "left"
		scroll_direction = "down"
		scroll_amount = 0
		move_direction = ""
		move_amount = 0
		press_param = ""
		type_param = ""

		# extract the parameters
		if inputaction == "click":
			word = utils.find_word(sentence.doc, ["left","middle","right","double","triple"])
			if word:
				click_param = word.lemma_

		elif inputaction == "scroll":
			for word in sentence:
				if str(word) in ["up", "down"]:
					scroll_direction = word.lemma_
					scroll_amount = 8
				elif str(word) in ["top", "bottom"]:
					scroll_direction = {"top":"up", "bottom":"down"}[str(word)]
					scroll_amount = 1000

		elif inputaction == "move":
			unit_size = 10
			for word in sentence:
				numToken = None
				if str(word) in ["up", "down", "left", "right", "center"]:
					move_direction = str(word)
				elif word.dep_ == "prep":
					if str(word) == "by":
						for prepchild in word.children:
							if prepchild.dep_ == "pobj":
								if prepchild.lemma_ in ["pixel", "unit"]:
									if prepchild.lemma_ == "pixel":
										unit_size = 1
									for c in prepchild.children:
										if c.like_num:
											numToken = c
								elif prepchild.like_num:
									numToken = prepchild
				elif word.lemma_ in ["pixel", "unit"]:
					if word.lemma_ == "pixel":
						unit_size = 1
					for c in word.children:
						if c.like_num:
							numToken = c
				elif word.like_num:
					numToken = word
				if numToken:
					try:
						move_amount = int(str(numToken))
					except:
						try:
							move_amount = utils.text2int(str(numToken))
						except Exception as e:
							log.error("could not parse {}".format(numToken))
							break
			move_amount *= unit_size

		elif inputaction == "press":
			word = utils.find_word(sentence.doc, ["press"])
			if word and word.nbor(1):
				press_param = '+'.join(map(str, sentence.doc[word.i + 1:]))

		elif inputaction == "type":
			word = utils.find_word(sentence.doc, ["type", "dictate"])
			if word and word.nbor(1):
				objective_span = sentence.doc[word.i + 1:]
				if len(objective_span) >= 3 and str(objective_span[0:2]).startswith("the word"):
					symbol_to_word = {
						"(": "parenthesis",
						")": "closed parenthesis",
						"[": "square bracket",
						"]": "closed square bracket",
						"&": "ampersand",
					}
					type_param = symbol_to_word[str(objective_span[2])]
				else:
					type_param = ' '.join(map(str, objective_span))
					# remove spaces in front of dollar signs if preceding a number
					dollar_with_num_regex = re.compile(r"(\$) (\d)")
					type_param = re.sub(dollar_with_num_regex, lambda m: m.group(1) + m.group(2), type_param)

					# HACK: quick fix to make dictating longer numbers easier
					broken_num_regex = re.compile(r"((\d+\.?(\d+)?|\d*\.(\d+)).([A-Za-z-:]+| |\d)|for|to)\s?\d+")
					if broken_num_regex.match(type_param):
						def _to_string_num_filtered(s):
							s = str(s).replace(":", "").replace("-", "")
							if not s:
								return s
							if s == "to":
								return "2"
							if s == "for":
								return "4"
							if s in ["point", "dot"]:
								return "."
							try:
								float(s)
								return s
							except ValueError:
								return str(utils.text2int(str(s)))
						type_param = ''.join(map(_to_string_num_filtered, objective_span))

		if inputaction == "click":
			return inputaction, (click_param,)
		elif inputaction == "scroll":
			return inputaction, (scroll_direction, scroll_amount,)
		elif inputaction == "move":
			return inputaction, (move_direction, move_amount)
		elif inputaction == "press":
			return inputaction, (press_param,)
		elif inputaction == "type":
			return inputaction, (type_param,)