可以回顧: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; 閃爍