需求

  • 在form(表单)填完以后,把信息返回给用户,询问用户是否确认操作
  • 使用环境: rasa3.6.9-full版

  • 尝试的方案:

1. 在提交表单之前添加对话意图和动作,结果虽然参执行,但是会和提交form一起执行,无法询问

2. 在故事里配置多轮对话的意图和动作,同上,依然在对话后直接提交form.

3. 使用2个表单form, 一个填完激活第二个表单,使用第二个表单作为确认表单,但在第二个表单里无法获取第一个表单的内容。

成功的方案

  • 在表单里多添加一个槽,用作询问用户是否确认(把这个槽放在最后让用户填写)
  • 启用表单验证,验证用户的回复内容
  • 在action提交表单里验证第后一个槽的信息是否确认,是:继续执行,否:清空表单

实例代码

  • domain.yml
forms:
  name_form:
    required_slots:
      - first_name
      - last_name
      - are_you_sure  #确认槽

slots:
  first_name:
    type: text
    influence_conversation: true
    mappings:
      - type: from_text
        conditions:
         - active_loop: name_form
           requested_slot: first_name
  last_name:
    type: text
    influence_conversation: true
    mappings:
      - type: from_text
        conditions:
         - active_loop: name_form
           requested_slot: last_name
  are_you_sure:
    type: text
    influence_conversation: true
    mappings:
      - type: from_text
        conditions:
         - active_loop: name_form
           requested_slot: are_you_sure

responses:  
  .... 
  utter_ask_first_name:
  - text: What is your first name?
  utter_ask_last_name:
  - text: What is your last name?
  utter_ask_are_you_sure:  # 槽访问的模板
  - text: 确认你的名称是  and 
  • rules.yml
rules:
- rule: 激活 form
  steps:
  - intent: request_names
  - action: name_form
  - active_loop: name_form

- rule: 提交 form
  condition:
  - active_loop: name_form
  steps:
  - action: name_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: utter_submit
  - action: action_submit
  • stories.yml
- story: interactive_story_1
  steps:
  - intent: greet
  - action: utter_greet
  - intent: request_names
  - action: name_form
  - active_loop: name_form
  - slot_was_set:
    - requested_slot: first_name
  - slot_was_set:
    - first_name: vincent
  - slot_was_set:
    - requested_slot: last_name
  - slot_was_set:
    - last_name: vincent-mcvincent
  - slot_was_set:  # 最后一个槽询问
      - requested_slot: are_you_sure
  - slot_was_set:
    - requested_slot: null
  - active_loop: null
  - action: utter_submit
  - action: action_submit

actions动作

  • validate_name_form.py
class ValidateNameForm(FormValidationAction):

    def name(self) -> Text:
        return "validate_name_form"

    async def required_slots(
            self,
            domain_slots: List[Text],
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: DomainDict,
    ) -> List[Text]:
        return domain_slots

    def validate_are_you_sure(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        print("验证are_you_sure: ", slot_value)
        return {"are_you_sure": slot_value}

    def validate_first_name(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        print("验证first_name")
        name = clean_name(slot_value)
        if len(name) < 5:
            dispatcher.utter_message(text="first_name必须大于4")    
            return {"first_name": None}
        return {"first_name": name}

    def validate_last_name(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        print("验证last_name")
        name = clean_name(slot_value)
        if len(name) < 4:
            dispatcher.utter_message(text="last_name.必须大于3")
            return {"last_name": None}

        first_name = tracker.get_slot("first_name")
        if len(first_name) + len(name) < 3:
            dispatcher.utter_message(text="That's a very short name. We fear a typo. Restarting!")
            return {"first_name": None, "last_name": None}
        return {"last_name": name}
  • submit_form.py
class ActionSubmitForm(Action):

    def name(self) -> Text:
        return "action_submit"

    def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
        content = tracker.latest_message
        intent = content['intent']['name']
        first_name = tracker.get_slot("first_name")
        last_name = tracker.get_slot("last_name")
        are_you_sure = tracker.get_slot("are_you_sure")
        print("     你的名称是:", first_name, last_name)
        if are_you_sure == 'yes':
            dispatcher.utter_message(text=f"您的名称是:   我们将记下您的名称")
        else:
            dispatcher.utter_message(text=f"我们取消您的所有操作。")
        print("清空槽数据--------------------")
        return [Restarted()]