Пример #1
0
 def user_transition(self, natural_language: str, state: Union[Enum, str, tuple], debugging=False):
     """
     :param state:
     :param natural_language:
     :param debugging:
     :return: the successor state representing the highest score user transition
              that matches natural_language, or None if none match
     """
     if '__gate__' in self._vars:
         del self._vars['__gate__']
     if '__user_utterance__' in self.vars() and self.vars()['__user_utterance__'] is not None:
         natural_language = self.vars()['__user_utterance__']
     else:
         natural_language = ''.join([c.lower() for c in natural_language if c.isalpha() or c == ' '])
     state = module_state(state)
     self._error_transitioned = False
     ti = time()
     if state is None:
         state = self.state()
     else:
         state = State(state)
     transition_options = []
     transition_items = []
     for transition in self.transitions(state, Speaker.USER):
         natex = self.transition_natex(*transition)
         score = self.transition_settings(*transition).score
         transition_items.append((natex, transition, score))
     while self._transitions:
         natex, transition, score = self._transitions.pop()
         transition_items.append((natex, transition, score))
     ngrams = Ngrams(natural_language, n=10)
     for natex, transition, score in transition_items:
         self._potential_transition = transition
         if not self.is_module() and isinstance(transition[1], tuple):
             continue
         t1 = time()
         if debugging:
             print('Evaluating transition {}'.format(transition[:2]))
         vars = HashableDict(self._vars)
         try:
             match = natex.match(natural_language, vars, self._macros, ngrams, debugging)
         except Exception as e:
             print()
             print('Transition {}: {} failed'.format(str(transition), natex))
             traceback.print_exc(file=sys.stdout)
             print()
             match = None
         source, target, speaker = transition
         if '__source__' in vars:
             source = State(module_state(vars['__source__']))
             del vars['__source__']
         if '__target__' in vars:
             target = State(module_state(vars['__target__']))
             del vars['__target__']
         transition = source, target, speaker
         if self.is_module() and isinstance(target, tuple):
             enter_natex = self.composite_dialogue_flow().state_settings(*target).enter
         else:
             enter_natex = self.state_settings(target).enter
         enter_natex_pass = True
         if enter_natex is not None:
             try:
                 enter_natex_pass = enter_natex.generate(vars=vars, macros=self._macros, debugging=debugging)
             except Exception as e:
                 print()
                 print(e)
                 print('Enter Natex {}: {} failed'.format(str(target), enter_natex))
                 print()
                 enter_natex_pass = None
         if match and enter_natex_pass is not None:
             if debugging:
                 print('Transition {} matched "{}"'.format(transition[:2], natural_language))
             if '__score__' in vars:
                 score = vars['__score__']
                 del vars['__score__']
             gate_closed = False
             gate_var_config = None
             gate_target_id = None
             if '__gate__' in vars:
                 gate_var_config = vars['__gate__']
                 gate_target_id = (self.namespace(), target) if (
                             not isinstance(target, tuple) and self.is_module()) else target
                 for vc in self.gates()[gate_target_id]:
                     if gate_var_config == vc:
                         gate_closed = True
                 del vars['__gate__']
             if not gate_closed:
                 transition_options.append((score, natex, transition, vars, gate_var_config, gate_target_id))
         t2 = time()
         if debugging:
             print('Transition {} evaluated in {:.5f}'.format(transition, t2-t1))
         while self._transitions:
             natex, transition, score = self._transitions.pop()
             transition_items.append((natex, transition, score))
     self._transitions.clear()
     if transition_options:
         if debugging:
             print('Transition options: ------------')
             for option in transition_options:
                 print('{} {}: {}'.format(option[0], option[2][1], option[1]))
             print('--------------------------------')
         score, natex, transition, vars, gate_var_config, gate_target_id = random_max(transition_options, key=lambda x: x[0])
         if gate_var_config is not None:
             self.gates()[gate_target_id].append(gate_var_config)
         if debugging:
             updates = {}
             for k, v in vars.items():
                 if k not in self._vars or v != self._vars[k]:
                     updates[k] = v
             if updates:
                 print('Updating vars:')
                 for k, v in updates.items():
                     if k in self._vars:
                         print('  {} = {} -> {}'.format(k, self._vars[k], v))
                     else:
                         print('  {} = None -> {}'.format(k, v))
         self.update_vars(vars)
         next_state = transition[1]
         if debugging:
             print('User transition in {:.5f}'.format(time() - ti))
             print('Transitioning {} -> {}'.format(self.state(), next_state))
         return next_state
     else:
         self._error_transitioned = True
         next_state = self.error_successor(self.state())
         if debugging:
             print('User transition in {:.5f}'.format(time() - ti))
             print('Error transition {} -> {}'.format(self.state(), next_state))
         return next_state
Пример #2
0
 def system_transition(self, state: Union[Enum, str, tuple], debugging=False):
     """
     :param state:
     :param debugging:
     :return: a <state, response> tuple representing the successor state and response
     """
     if '__gate__' in self._vars:
         del self._vars['__gate__']
     state = module_state(state)
     ti = time()
     if state is None:
         state = self.state()
     else:
         state = State(state)
     transition_options = []
     transitions = list(self.transitions(state, Speaker.SYSTEM))
     transition_items = []
     for transition in transitions:
         natex = self.transition_natex(*transition)
         score = self.transition_settings(*transition).score
         transition_items.append((natex, transition, score))
     while self._transitions:
         natex, transition, score = self._transitions.pop()
         transition_items.append((natex, transition, score))
     while self._update_transitions:
         natex, transition, score = self._update_transitions.pop()
         transition_items.append((natex, transition, score))
     for natex, transition, score in transition_items:
         t1 = time()
         transition_transition_enter = None
         vars = HashableDict(self._vars)
         self._potential_transition = transition # MOVED, todo
         try:
             generation = natex.generate(vars=vars, macros=self._macros, debugging=debugging)
         except Exception as e:
             print()
             print('Transition {}: {} failed'.format(str(transition), natex))
             traceback.print_exc(file=sys.stdout)
             print()
             generation = None
         source, target, speaker = transition
         if '__source__' in vars:
             source = State(module_state(vars['__source__']))
             del vars['__source__']
         if '__target__' in vars:
             target = State(module_state(vars['__target__']))
             del vars['__target__']
         transition = source, target, speaker
         # if not self.is_module() and isinstance(target, tuple):
         #     continue
         if '->' in transition[1]:
             _src, _tar = target.split('->')[0], target.split('->')[1]
             _tar = State(module_state(_tar))
             transition = (_src, _tar, speaker)
             try:
                 appended_generation = self.transition_natex(*transition).generate(vars=vars, macros=self._macros, debugging=debugging)
                 if appended_generation is None:
                     generation = None
                 else:
                     generation = generation + ' ' + appended_generation
             except Exception as e:
                 print()
                 print('Transition {}: {} failed'.format(str(transition), natex))
                 traceback.print_exc(file=sys.stdout)
                 print()
                 generation = None
         elif isinstance(transition[1], tuple) and '->' in transition[1][1]:
             namespace = transition[1][0]
             source, target = (namespace, target[1].split('->')[0]), target[1].split('->')[1]
             target = State(module_state(target))
             transition_transition_enter = source
             transition = (source, target, speaker)
             try:
                 appended_generation = self.composite_dialogue_flow().transition_natex(
                     namespace, *transition).generate(vars=vars, macros=self._macros, debugging=debugging)
                 if generation is None or appended_generation is None:
                     generation = None
                 else:
                     generation = generation + ' ' + appended_generation
             except Exception as e:
                 print()
                 print('Transition {}: {} failed'.format(str(transition), natex))
                 traceback.print_exc(file=sys.stdout)
                 print()
                 generation = None
         source, target, speaker = transition
         if '__source__' in vars:
             source = State(module_state(vars['__source__']))
             del vars['__source__']
         if '__target__' in vars:
             target = State(module_state(vars['__target__']))
             del vars['__target__']
         transition = source, target, speaker
         enter_natex_pass = True
         transition_transition_enter_vars = vars
         if transition_transition_enter is not None:
             if self.is_module() and isinstance(transition_transition_enter, tuple):
                 enter_natex = self.composite_dialogue_flow().state_settings(*transition_transition_enter).enter
             else:
                 enter_natex = self.state_settings(transition_transition_enter).enter
             if enter_natex is not None:
                 try:
                     enter_natex_pass = enter_natex.generate(vars=transition_transition_enter_vars, macros=self._macros, debugging=debugging)
                 except Exception as e:
                     print()
                     print(e)
                     print('Enter Natex {}: {} failed'.format(str(transition_transition_enter), enter_natex))
                     print()
                     enter_natex_pass = None
         if enter_natex_pass:
             if self.is_module() and isinstance(target, tuple):
                 enter_natex = self.composite_dialogue_flow().state_settings(*target).enter
             else:
                 enter_natex = self.state_settings(target).enter
             if enter_natex is not None:
                 try:
                     enter_natex_pass = enter_natex.generate(vars=vars, macros=self._macros, debugging=debugging)
                 except Exception as e:
                     print()
                     print(e)
                     print('Enter Natex {}: {} failed'.format(str(target), enter_natex))
                     print()
                     enter_natex_pass = None
         if generation is not None and enter_natex_pass is not None:
             if '__score__' in vars:
                 score = vars['__score__']
                 del vars['__score__']
             gate_closed = False
             gate_var_config = None
             gate_target_id = None
             if '__gate__' in vars:
                 gate_var_config = vars['__gate__']
                 gate_target_id = (self.namespace(), target) if (not isinstance(target, tuple) and self.is_module()) else target
                 for vc in self.gates()[gate_target_id]:
                     if gate_var_config == vc:
                         gate_closed = True
                 del vars['__gate__']
             tt_gate_var_config = None
             tt_gate_target_id = None
             if transition_transition_enter is not None and '__gate__' in transition_transition_enter_vars:
                 tt_gate_var_config = transition_transition_enter_vars['__gate__']
                 tt_gate_target_id = (self.namespace(), transition_transition_enter) if \
                     (not isinstance(transition_transition_enter, tuple) and self.is_module()) else transition_transition_enter
                 for vc in self.gates()[tt_gate_target_id]:
                     if tt_gate_var_config == vc:
                         gate_closed = True
                 del transition_transition_enter_vars['__gate__']
             transition_transition_enter_vars.update(vars)
             vars = transition_transition_enter_vars
             if not gate_closed:
                 transition_options.append((score, natex, generation, transition, vars, gate_var_config, gate_target_id, tt_gate_var_config, tt_gate_target_id))
         t2 = time()
         if debugging:
             print('Transition {} evaluated in {:.5f}'.format(transition, t2-t1))
         while self._transitions:
             natex, transition, score = self._transitions.pop()
             transition_items.append((natex, transition, score))
     self._transitions.clear()
     if transition_options:
         if debugging:
             print('Transition options: ------------')
             for option in transition_options:
                 print('{} {}: {}'.format(option[0], option[3][1], option[1]))
             print('--------------------------------')
         score, natex, response, transition, vars, gate_var_config, gate_target_id, tt_gate_var_config, tt_gate_target_id =\
             random_max(transition_options, key=lambda x: x[0])
         if gate_var_config is not None:
             self.gates()[gate_target_id].append(gate_var_config)
         if tt_gate_var_config is not None:
             self.gates()[tt_gate_target_id].append(tt_gate_var_config)
         if debugging:
             updates = {}
             for k, v in vars.items():
                 if k not in self._vars or v != self._vars[k]:
                     updates[k] = v
             if updates:
                 print('Updating vars:')
                 for k, v in updates.items():
                     if k in self._vars:
                         print('  {} = {} -> {}'.format(k, self._vars[k], v))
                     else:
                         print('  {} = None -> {}'.format(k, v))
         self.update_vars(vars)
         next_state = transition[1]
         if debugging:
             tf = time()
             print('System transition in {:.5f}'.format(tf-ti))
             print('Transitioning {} -> {}'.format(self.state(), next_state))
         if '__response_prefix__' in self.vars() and self.vars()['__response_prefix__'] != 'None':
             response = self.vars()['__response_prefix__'] + ' ' + response
             self.vars()['__response_prefix__'] = 'None'
         return response, next_state
     else:
         if self._default_state is not None:
             self.set_state(self._default_state)
             if debugging:
                 print('No valid system transitions found, going to default state...')
             return self.system_transition(self.state(), debugging=debugging)
         raise AssertionError('dialogue flow system transition found no valid options from state {}'.format(state))