RASA2.0搭建中文聊天机器人

环境搭建
# 优先安装这几个python包,后面缺什么补充什么
rasa==2.0.0
rasa-sdk==2.4.1
tensorflow==2.3.2
Flask==1.1.2
开始搭建
  • 初始化项目

    # 命令创建rasa项目所需的所有文件,并根据一些示例数据训练一个简单的机器人
    rasa init
    
  • 初始化后会创建以下文件,介绍几个重要的文件,当然这些文件结构你也可以自己调整

    文件名作用
    config.yml配置NLU和Core的文件
    /data/nlu.ymlNLU的训练语句,意图加包含意图的话术
    /data/stories.yml对话的故事,可以理解为剧本
    domain.yml作用域,里面注册你定义的意图,对话模板,自定义action,槽位等
    endpoints.ymlaction的端口,action对外暴露的接口配置文件
    /models/xxxx.tar,gz训练的模型
  • 我项目的目录结构是这样的,可以作为参考

    .
    ├── actions
    │   ├── action_kn_test.py
    │   ├── action_trademark_analy.py
    │   ├── action_trademark_explain.py
    │   ├── action_trademark_keyword.py
    │   ├── action_weather_query.py
    │   ├── __init__.py
    │   └── __pycache__
    │       ├── action_kn_test.cpython-36.pyc
    │       ├── action_trademark_analy.cpython-36.pyc
    │       ├── action_trademark_explain.cpython-36.pyc
    │       ├── action_trademark_keyword.cpython-36.pyc
    │       ├── action_weather_query.cpython-36.pyc
    │       └── __init__.cpython-36.pyc
    ├── App
    │   ├── def_func.py
    │   ├── def_settings.py
    │   ├── ext.py
    │   ├── __init__.py
    │   ├── models.py
    │   ├── __pycache__
    │   │   ├── ext.cpython-36.pyc
    │   │   ├── __init__.cpython-36.pyc
    │   │   └── views.cpython-36.pyc
    │   ├── settings.py
    │   ├── static
    │   │   ├── css
    │   │   │   └── style2.css
    │   │   ├── images
    │   │   │   ├── ai.png
    │   │   └── js
    │   │       ├── chat.js
    │   │       └── jquery-3.3.1.min.js
    │   ├── templates
    │   │   └── chat.html
    │   └── views.py
    ├── configs
    │   ├── config.yml
    │   ├── credentials.yml
    │   ├── domain.yml
    │   ├── endpoints.yml
    │   ├── zh_jieba_mitie_embeddings_config.yml
    │   └── zh_jieba_supervised_embeddings_config.yml
    ├── data
    │   ├── dict
    │   │   ├── cityname.txt
    │   │   └── userdict.txt
    │   ├── nlu
    │   │   └── nlu.yml
    │   ├── rules.yml
    │   ├── stories
    │   │   ├── stories.yml
    │   │   └── story1.md
    │   └── total_word_feature_extractor_zh.dat
    ├── models
    │   └── 20210420-153935.tar.gz
    ├── __pycache__
    ├── server.py
    ├── shell_diectory
    │   ├── run_shell
    │   └── train_shell
    
开始构建聊天机器人的第一个例子(查天气)
  • 定义你的NLU

    - intent: query_weather
      examples: |
        - 我想查询天气
        - 我想查询[广州]{"entity":"address"}的天气
        - [明天]{"entity":"datetime"}天气怎么样?
        - 我想查询[明天]{"entity":"datetime"}[深圳]{"entity":"address"}的天气
    
  • 准备地名词库

在这里插入图片描述

  • 定义你stories剧本

    ## query_weather(天气查询)
    * query_weather
        - weather_form
        - active_loop{"name":"weather_form"}
    
  • 在domain.yml 注册,注册你定义的意图,实体,槽位,问话模板,表单,自定义的action等

    version: "2.0"
    
    intents:
      - greet
      - goodbye
      - affirm
      - deny
      - mood_great
      - mood_unhappy
      - bot_challenge
      - query_weather  # 意图查天气
    
    
    entities:
      - kn_question_num
      - datetime    # 实体时间
      - address     # 实体地址
    
    actions:
      - action_test
    
    slots:
      kn_question_num:
        type: text
      datetime:
        type: text   # 你需要填入的槽位时间
      address:
        type: text	# 你需要填入的槽位地址	
      requested_slot:
        type: unfeaturized
    
    responses:
      utter_greet:
      - text: "Hey! How are you?"
    
      utter_cheer_up:
      - text: "Here is something to cheer you up:"
        image: "https://i.imgur.com/nGF1K8f.jpg"
    
      utter_did_that_help:
      - text: "Did that help you?"
    
      utter_happy:
      - text: "Great, carry on!"
    
      utter_goodbye:
      - text: "Bye"
    
      utter_iamabot:
      - text: "I am a bot, powered by Rasa."
    
      utter_ask_datetime:
      - text: "请问你要查询什么时候的天气?"   # 自动询问模板
    
      utter_ask_address:
      - text: "请问你要查询哪里的天气?"    #自动询问模板
    
    forms:
      weather_form: {}   #多轮问话表单
    
    session_config:
      session_expiration_time: 60
      carry_over_slots_to_new_session: true
    
  • 自定义action.py

    ‘’‘
    @author: 小帆芽芽
    date: 2021/04/25
    ‘’‘
    from rasa_sdk.types import DomainDict
    from typing import Dict, Text, Any, List, Union
    from flask import jsonify
    from rasa_sdk import Tracker, Action
    from rasa_sdk.events import UserUtteranceReverted, Restarted, SlotSet, EventType
    from rasa_sdk.executor import CollectingDispatcher
    from rasa_sdk.forms import FormAction
    # from actions import ChatApis
    # from actions.WeatherApis import get_weather_by_day
    from requests import (
        ConnectionError,
        HTTPError,
        TooManyRedirects,
        Timeout
    )
    # from test.qachat import get_qa
    from rasa_sdk import ActionExecutionRejection
    from rasa_sdk.events import SlotSet, AllSlotsReset
    from rasa_sdk.executor import CollectingDispatcher
    from rasa_sdk.forms import FormAction, REQUESTED_SLOT
    import requests, random, math
    import re
    import json
    # import jieba
    import logging
    
    logger = logging.getLogger(__name__)
    
    # 查询天气
    class QueryWeather(FormAction):
    	'''
    	心知天气API
    	'''
        def __init__(self):
            super().__init__()
            # 天气查询私钥
            self.KEY = '你的私钥'
            self.LOCATION = 'beijing'  # 所查询的位置,可以使用城市拼音、v3 ID、经纬度等
            self.url = 'https://api.seniverse.com/v3/weather/daily.json'  # API URL,可替换为其他 URL
            self.UNIT = 'c'  # 单位
            self.LANGUAGE = 'zh-Hans'  # 查询结果的返回语言
            self.data={
                'key': self.KEY,
                'location': self.LOCATION,
                'language': self.LANGUAGE,
                'unit': self.UNIT,
                'start': 0,
                'days': 10
            }
            # 0 代表今天,1 代表明天,2代表后天
            self.num = 0
    
        def name(self) -> Text:
            return "weather_form"
    
        @staticmethod
        def required_slots(tracker):
            return ['address','datetime']
            
    	# 槽值映射,不管用户说什么都将填入槽中
        def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict[Text, Any]]]]:
            return {'address':[self.from_text()],'datetime':[self.from_text()]}
    	# 槽值验证
        def validate_address(self,slot_value, dispatcher, tracker, domain):
            # list=['北京','上海','深圳','广州']
            path = './data/dict/cityname.txt'
            d_ = [i.strip() for i in open(path, 'r').readlines()]
            # if slot_value in list:
            if slot_value in d_:
                return {"address":slot_value}
            else:
                dispatcher.utter_message('您输入的不是地名哟')
                return {"address":None}
        # 槽值验证
        def validate_datetime(self,slot_value, dispatcher, tracker, domain):
            d_list = ['今天','明天','后天']
    
            if slot_value in d_list:
            # if slot_value in d_:
                return {"datetime":slot_value}
            else:
                dispatcher.utter_message('暂不支持查询 {} 的天气'.format(slot_value))
                return {"datetime":None}
    
        def submit(self,dispatcher, tracker, domain):
            date = tracker.get_slot('datetime')
            address = tracker.get_slot('address')
            self.judge_time(date)
            text_day, text_night, high, low, wind_direction, humidity, wind_speed, wind_scale,date_ = self.get_weather(address)
            s='{}{}({})的天气情况是:白天{},晚上{}.当天最高温度是{}摄氏度,最低温度是{}摄氏度.风向{},风速{},风力等级为{},空气湿度为{}%'.format(
               address,date,date_, text_day,text_night,high,low,wind_direction,wind_speed,wind_scale,humidity
            )
            dispatcher.utter_message('小娜为您查询到:')
            dispatcher.utter_message(s)
    
            # return [AllSlotsReset()]
            return [Restarted()]
    
    
        def judge_time(self,date):
            if date == '今天':
                self.num = 0
            elif date == '明天':
                self.num = 1
            elif date == '后天':
                self.num = 2
    
        def get_weather(self,address):
            self.LOCATION = address
            str_ = requests.get(url=self.url,params=self.data,timeout=2).text
            dic = json.loads(str_)
            print(dic)
            # 白天天气
            text_day = dic['results'][0]['daily'][self.num]['text_day']
            # 夜晚天气
            text_night = dic['results'][0]['daily'][self.num]['text_night']
            # 最高温度
            high = dic['results'][0]['daily'][self.num]['high']
            # 最低温度
            low = dic['results'][0]['daily'][self.num]['low']
            # 风向
            wind_direction = dic['results'][0]['daily'][self.num]['wind_direction']
            # 湿度(百分比)
            humidity = dic['results'][0]['daily'][self.num]['humidity']
            # 风速
            wind_speed = dic['results'][0]['daily'][self.num]['wind_speed']
            # 风力等级
            wind_scale = dic['results'][0]['daily'][self.num]['wind_scale']
            # 日期
            date_ = dic['results'][0]['daily'][self.num]['date']
    
            return text_day,text_night,high,low,wind_direction,humidity,wind_speed,wind_scale,date_
    
  • 采用flask外部调用接口

    '''
    @author:小帆芽芽
    @date:2021/04/25
    '''
    import json
    import re
    
    import requests
    from flask import Blueprint, render_template, request
    
    blue = Blueprint('rasa', __name__)
    
    REQUEST_URL = "http://localhost:5005/webhooks/rest/webhook"
    HEADERS = {'Content-Type': 'application/json; charset=utf-8'}
    
    
    def init_route(app):
        app.register_blueprint(blue)
    
    @blue.route('/', methods=['GET', 'POST'])
    def test():
        # return 'this a test page', 200
        return render_template('chat.html')
    
    
    @blue.route('/chat',methods=['GET'])
    def chat():
        data=request.args.to_dict()
        message=data['message']
        if message:
            answer = rasaresponse('xiaofangyaya',message)
            return answer
    
    def rasaresponse(user,msg):
        requestDict={'sender':user,'message':msg}
        rsp=requests.post(REQUEST_URL, data=json.dumps(requestDict),headers=HEADERS)
        # content=rsp.text.encode('utf-8').decode("unicode-escape")
        if rsp.status_code == 200:
            rsp_json=json.loads(rsp.text.encode())
            content_text = ''
            if len(rsp_json):
                # print(rsp_json)
                for i in range(len(rsp_json)):
                    # txt_=rsp_json[i]['text']
                    txt_=rsp_json[i].get('text')
                    print('rasa返回内容是---------->{}'.format(txt_))
                    if txt_:
                        content_text=content_text+txt_
                    else:
                        content_text=content_text + '\n' + rsp_json[i]['image']
    
                return content_text
    
            else:
                return '哎呀,这个小娜也不懂呢~~~'
    
        else:
            return '返回错误,请重新输入问话。'
    
  • 运行rasa,依次执行以下命令

    # 启动服务
    # 1. 启动rasa server
    python -m rasa run --port 5005 -m models/20210420-153935.tar.gz --endpoints configs/endpoints.yml --credentials configs/credentials.yml --debug
    # 2. 启动action server
    python -m rasa run actions --port 5055 --actions actions --debug
    # 3. 启动server.py
    python server.py
    
  • 页面测试

在这里插入图片描述

在这里插入图片描述

  • 我的源码地址:
    https://gitee.com/menfeng/rasa-weather-edition

希望点赞关注支持哦!!!!
后期还有大波福利发送
在这里插入图片描述

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐