rasa框架學習二(slots,entities,actions,component)


可以回顧:rasa框架學習一(domain.yml、nlu.md、stories.md)

rasa框架響應消息的基本步驟:

一、插槽:slots

slots可以充當鍵值存儲。在domain.yml文件里設置slot的鍵及其類型,我們可以在action.py通過get_slo(“slot_key”)方法來獲取slot的值,或者用SlotSet("slot_key","value")的方法來給slot設置值。

在domain.yml文件里進行插槽設置如下圖:

 1. slot類型

# text:存儲文本信息;
slots:
  country:
    type: text
    initial_value: "China"

# bool:存儲布爾值,True or False;
slots:
  AKeyWord:
    type: bool
    initial_value: false

# categorical:指定接收枚舉所列的一個值
slots:
  weather:
    type: categorical
    values:
      - sun
      - rain
      - cloudy
# float:存儲浮點連續值,其中,max_value=1.0, min_value=0.0為默認值,當要存儲的值大於max_value,那么slot只會存儲max_value;當要存儲的值小於min_value,那么slot只會存儲min_value。
slots:
   result:
      type: float
      min_value: 0.0
      max_value: 100.0
# list:存儲列表數據
slots:
   shopping_items:
      type: list
# unfeaturized:該插槽不會具有任何特征,因此其值不會影響對話流程,在預測機器人應執行的下一個動作時會被忽略。
slots:
  name:
    type: unfeaturized

2. 自定義插槽

自定義插槽我還沒用過,下面是官方文檔的例子:

from rasa.core.slots import Slot

class GetData(Slot):

    def feature_dimensionality(self):
        return 2

    def as_feature(self):
        r = [0.0] * self.feature_dimensionality()
        if self.value:
            if self.value <= 6:
                r[0] = 1.0
            else:
                r[1] = 1.0
        return r

二、實體:entities

實體和插槽是差不多的,是可以存在於用戶消息中的,用戶傳過來一句:“我要吃()”,這個括號里面的東西是可變的,我們需要加個實體來代替,獲取用戶的消息時,也把實體的值給獲取到。所以實體的效果是和插槽相同的,總的來說插槽是包括實體的。

 在domain.yml里設置一個實體:menu_name

entities:
  - menu_name

nlu.md里面我們就可以用這個實體來占位置

## intent:which_menu
- 我想吃[](menu_name) - 我要吃[](menu_name) - 我喜歡吃[](menu_name) - 我們點[](menu_name) 這道菜吧

在actions.py里獲取這個值可以用get_slot("實體名或插槽名")。在下面的actions里會說到。

三、actions

在action.py里自定義action,除了要在domain和stories里面添加上進行訓練后,還有就是要先運行下面的命令,再rasa shell,自定義的action才可以生效。

如果rasa已經安裝,請運行以下命令以啟動動作服務器:

rasa run actions

否則,如果尚未安裝rasa,請運行以下命令:

python -m rasa_sdk --actions actions

 ******我們來展示一個對用戶的一句話進行解析的完整例子:*******

 nlu.md文件:

## intent:which_menu
- 我想吃[](menu_name) 
- 我要吃[](menu_name) 
- 我喜歡吃[](menu_name) 
- 我們點[](menu_name) 這道菜吧

stories.md文件

## which_menu
* which_menu
  - action_which_menu

domain.yml文件

設置了倆插槽,一個是context,context設置了倆值:Success和Failure,用來記錄菜是否被記下;第二個插槽是which_menu_times,用來記錄which_menu這個意圖被問了多少次。

slots:
  context:
    type: categorical
    values:
      - Success
- Failure which_menu_times: type: unfeaturized entities:
- menu_name actions: - utter_which_menu - action_which_menu - utter_three_times
templates: utter_which_menu:
- text: "好的我已記下,還需要什么嗎?"

actions.py文件

1. 自定義的action必須要繼承Action類,AllSlotsReset, Restarted是設置此次對話結束並重啟對話,我們常用在結束語境的action里。

2. dispatcher用來回復消息:dispatcher.utter_template和dispatcher.utter_message

  dispatcher.utter_template("utter_which_menu",tracker)是從domain的template里讀取文本信息,我們一般都這樣使用這種形式

  dispatcher.utter_message(“不好意思。。。”)這個直接在actions里進行文本設置回復,一般不這樣用。

3. tracker是用來獲取slot和entities的值,tracker還有個方法是tracker.current_state()結果是一個字典,里面有個latest_message鍵,tracker.current_state()["latest_message"]里的value有很多信息,比如intent,entities等等,可以看看下面的源碼:

4. domain,我沒用過,打印過一次,只記得里面的東西很多,想自己了解的可以print出來看看是什么

from rasa_sdk import Action
from rasa_sdk.events import SlotSet,AllSlotsReset, Restarted
class ActionWhichMenu(Action):
    def name(self):
        # action的名字
        return "action_which_menu"

    def run(
        self,
        dispatcher,  # type: CollectingDispatcher
        tracker,  # type: Tracker
        domain,  # type:  Dict[Text, Any]
    ):
        # 獲取是which_menu這個意圖被識別了多少次,也就是這個問題被問了多少遍
        which_menu_times = tracker.get_slot("which_menu_times") or 0
        which_menu_times = int(which_menu_times) + 1
        # 若是同個問題重復問三次及以上,則點餐失敗
        if which_menu_times >=3:
            dispatcher.utter_message("不好意思,你的問題我無法回答,此次點餐失敗")
            # 點餐失敗返回的參數:點餐結果(context)
            # AllSlotsReset(), Restarted()表示此次對話結束,重啟對話
            return [AllSlotsReset(), Restarted(), SlotSet("context", "Failure")]
        else:
            # 獲取實體menu_name的值
            menu_name = tracker.get_slot("menu_name")
            # 若是菜名存在
            if menu_name:
                dispatcher.utter_template("utter_which_menu", tracker)
                # 返回參數:意圖識別次數(which_menu_times),點餐結果(context)
                return [SlotSet("which_menu_times", which_menu_times), SlotSet("context", "Success")]
            else:
                dispatcher.utter_message("我沒聽清,您需要重新點一下啊")
                # 點餐失敗返回的參數:點餐結果(context)
                # AllSlotsReset(), Restarted()表示此次對話結束
                return [AllSlotsReset(), Restarted(), SlotSet("context", "Failure")]

        

代碼都已完成我們來分析一下啊

 “我想吃酸菜魚”---》進入nlu.md匹配---》匹配意圖成功后進入stories.md找到對應的意圖觸發action行為---》進入actions.py找到對應的actions類然后走邏輯代碼走完后給用戶返回消息(dispatcher)

四、component

component是在意圖識別之前的一個過程,如下圖

所以我們可以在意圖識別之前在component里可以對獲取的消息進行處理

我在components里用到的是設置intent和entities

 這里要說一下,nlu和core這兩個文件可以在你python安裝下的包site-packages里的rasa里找到,拷貝到你的項目里。

 

1. 設置意圖inent

 若是用戶說的是“嗯”,“好”,“好的”等信息,我們把意圖強制改成affirm

class SortIntent(Component):

    name = "sort_intent"  # 組件名字
    provides = ["intent"]  # 當前組件能夠計算出什么

    print("enter SortIntent Component")

    def __init__(self, component_config=None):
        super(SortIntent, self).__init__(component_config)

    def process(self, message, **kwargs):
        text = message.text                   # 獲取用戶信息
        intent = message.get("intent")
        print("SortIntent text:", text)
        print("intent:", intent)
        intent_ranking = []

        if text == "" or text == "" or text == "好的":
            intent = {"name": "affirm", "confidence": 1.0}
            intent_ranking.append(intent)
            message.set("intent", intent, add_to_output=True)
            message.set("intent_ranking", intent_ranking, add_to_output=True)

2. 在組件里設置實體entities

 我在這里面設置實體的值是一個電話號碼phonenumber,因為我之后要在actions里用到

class DealMessage(Component):
    """處理反饋消息"""
    text = message.text  # text/phonenumber/str 或者 text
        text_list = text.split("/")  # ["text", "phonenumber", "str"] 或者["text"]

        # text_list = ["華為"]  微信端口傳過來的數據
        # text_list = ["text","13100000000", "str"]  電話端口傳來的數據

        entities = message.get("entities")
        if len(text_list) > 1:
            message.text = text_list[0]  # 把用戶說的話賦值給message.text
            print("message.text", message.text)
            print("是電話")
            self.phonenumber = text_list[1]
        elif len(text_list) == 1:
            self.phonenumber = None
            print("是微信")
       
        # 設置實體的電話號碼值
        entities = [{
            'start': 0,
            'end': 4,
            'value': phonenumber,
            'entity': 'phonenumber',
            'confidence': 1,
            'extractor': 'CRFEntityExtractor'
        }]

        message.set("entities", entities, add_to_output=True) 

 注意:寫完自定義組件后一定要注冊、配置再訓練,不然用不了。

1. 注冊:

進入nlu文件下的registry.py

 

 

 導入這兩個類

 再找到component_classes列表在后面追加寫上類的名字,就算注冊完成了

2. 配置:

進入config.yml進行配置,這里要注意一下順序,你寫的組件,需要先用到哪個就排到前面,我這里需要先用到DealMessage所以就把它寫到了SortIntent前面。

 3. 一定要訓練,不然沒有用

rasa train

五、啟動項目

運行服務器:

首先actions:

rasa run actions
nohup rasa run actions & # 加上nohup &使后台一直運行這個項目

然后rasa 

rasa run -m models --port 5002 --credentials credentials.yml --endpoints endpoints.yml
nohup rasa run -m models --port 5002 --credentials credentials.yml --endpoints endpoints.yml &

查看進程 

ps -ef  # 產看所有進程
lsof -i:5055 #查看端口號為5055的進程

殺死進程

kill -9 2895  # 殺死pid為2895的進程

 查看日志

# 查看日志
tail -f 日志

# 單個關鍵詞高亮顯示:
tail -f 日志文件 | perl -pe 's/(關鍵詞)/\e[1;顏色$1\e[0m/g'
tail -f catalina.out | perl -pe 's/(DEBUG)/\e[1;34m$1\e[0m/g'

多個關鍵詞高亮顯示:
tail -f catalina.out | perl -pe 's/(關鍵詞1)|(關鍵詞2)|(關鍵詞3)/\e[1;顏色1$1\e[0m\e[1;顏色2$2\e[0m\e[1;顏色3$3\e[0m/g' 
tail -f catalina.out | perl -pe 's/(DEBUG)|(INFO)|(ERROR)/\e[1;34m$1\e[0m\e[1;33m$2\e[0m\e[1;31m$3\e[0m/g' 
字體顏色設置: 
30m:黑     31m:紅     32m:綠     33m:黃 
34m:藍     35m:紫     36m:青     37m:白

背景顏色設置:40-47 黑、紅、綠、黃、藍、紫、青、白 

其他參數說明 
[1; 設置高亮加粗 
[4; 下划線  
[5; 閃爍

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM