Skip to content

Commit 690e68b

Browse files
committed
创建项目,版本1.0.0.2020.02.15
0 parents  commit 690e68b

File tree

15 files changed

+819
-0
lines changed

15 files changed

+819
-0
lines changed

ReadMe.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# RASA中文聊天机器人项目
2+
3+
4+
5+
**RASA 开发中文指南系列博文:**
6+
7+
- [Rasa中文聊天机器人开发指南(1):入门篇](https://jiangdg.blog.csdn.net/article/details/104328946)
8+
- Rasa中文聊天机器人开发指南(2):NLU篇
9+
- Rasa中文聊天机器人开发指南(3):Core篇
10+
- Rasa中文聊天机器人开发指南(4):RasaX篇
11+
12+
13+
14+
# 1. 安装rasa
15+
16+
## 1.1 环境要求
17+
18+
- python 3.6 +
19+
- mitie
20+
- jieba
21+
22+
## 1.2 安装步骤
23+
24+
**1. 安装rasa**
25+
26+
```shell
27+
# 当前版本为1.7.0
28+
# 该命令运行时间较长,会安装完所有的依赖
29+
pip --default-timeout=500 install -U rasa
30+
```
31+
32+
**2. 安装mitie**
33+
34+
```shell
35+
# 在线安装Mitie
36+
pip install git+https://github.com/mit-nlp/MITIE.git
37+
pip install rasa[mitie] # 注:由于第一步始终没成功过,没尝试过这个命令的意义
38+
```
39+
 由于自己在线安装尝试了很多次都拉不下来,因此只能走离线安装的方式,有三个步骤:
40+
41+
- 首先,下载[MITIE源码](https://github.com/mit-nlp/MITIE)和中文词向量模型[total_word_feature_extractor_zh.dat(密码:p4vx)](https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg),这里需要将该模型拷贝到创建的python项目data目录下(可任意位置),后面训练NLU模型时用到;
42+
43+
- 其次,安装[Visual Studio 2017](https://blog.csdn.net/qq_42276781/article/details/88594870) ,需要勾选“`用于 CMake 的 Visual C++ 工具`”,因为编译MITIE源码需要Cmake和Visual C++环境。安装完毕后,将`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin`添加到环境变量中,再重启电脑使之生效;
44+
45+
- 从Pycharm的命令终端进行Mitie源码根目录,执行下面的命令:
46+
47+
> python setup.py build
48+
> python setup.py install
49+
50+
51+
**3. 安装jieba**
52+
53+
```shell
54+
# 安装Jieba中文分词
55+
pip install jieba
56+
```
57+
58+
# 2. 训练模型
59+
60+
 当所有样本和配置文件准备好后,接下来就是训练模型了,打开命令终端执行下面的命令,该命令会同时训练NLU和Core模型,具体如下:
61+
```shell
62+
python -m rasa train --config configs/config.yml --domain configs/domain.yml --data data/
63+
```
64+
65+
# 3. 运行服务
66+
67+
**(1)启动Rasa服务**
68+
69+
 在命令终端,输入下面命令:
70+
71+
```shell
72+
# 启动rasa服务
73+
# 该服务实现自然语言理解(NLU)和对话管理(Core)功能
74+
# 注:该服务的--port默认为5005,如果使用默认则可以省略
75+
python -m rasa run --port 5005 --endpoints configs/endpoints.yml --credentials configs/credentials.yml --debug
76+
```
77+
78+
**(2)启动Action服务**
79+
80+
在命令终端,输入下面命令:
81+
82+
```shell
83+
# 启动action服务
84+
# 注:该服务的--port默认为5055,如果使用默认则可以省略
85+
Python -m rasa run actions --port 5055 --actions actions --debug
86+
```
87+
88+
**(3)启动server.py服务**
89+
90+
```shell
91+
python server.py
92+
```
93+
94+
**Rasa Server****Action Server****Server.py**运行后,在浏览器输入:
95+
96+
` http://127.0.0.1:8088/ai?content="查询广州明天的天气"`
97+
98+
返回的结果为:
99+
100+
![入门7](https://img-blog.csdnimg.cn/20200215154508497.png)
101+
102+
# 4. 更新日志
103+
104+
105+
106+
**(1)V1.0.0.2020.02.15**
107+
108+
- 创建项目,模型训练成功;
109+
- 前端访问Rasa服务器正常响应;
110+
- 对接图灵闲聊机器人、心知天气API,便于测试;
111+
112+
113+
114+
# 5. License
115+
116+
117+
118+
> ```
119+
> Copyright 2020 Jiangdongguo
120+
>
121+
> Licensed under the Apache License, Version 2.0 (the "License");
122+
> you may not use this file except in compliance with the License.
123+
> You may obtain a copy of the License at
124+
>
125+
> http://www.apache.org/licenses/LICENSE-2.0
126+
>
127+
> Unless required by applicable law or agreed to in writing, software
128+
> distributed under the License is distributed on an "AS IS" BASIS,
129+
> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130+
> See the License for the specific language governing permissions and
131+
> limitations under the License.
132+
> ```
133+

actions/ChatApis.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# 访问图灵机器人openapi
2+
# -*- coding: utf-8 -*-
3+
"""
4+
ChatApis.py
5+
~~~~~~~~~
6+
7+
图灵机器人(公司)闲聊系统API对接
8+
免费版只限每天调用100次,需联外网
9+
10+
:date: 2020-02-10 15:56:00
11+
:author: by jiangdg
12+
"""
13+
import requests
14+
import json
15+
16+
17+
def get_response(msg):
18+
"""
19+
访问图灵机器人openApi
20+
21+
:param msg 用户输入的文本消息
22+
:return string or None
23+
"""
24+
apiurl = "http://openapi.tuling123.com/openapi/api/v2"
25+
# 构造请求参数实体
26+
params = {"reqType": 0,
27+
"perception": {
28+
"inputText": {
29+
"text": msg
30+
}
31+
},
32+
"userInfo": {
33+
"apiKey": "ca7bf19ac0e644c38cfbe9d6fdc08de1",
34+
"userId": "439608"
35+
}}
36+
# 将表单转换为json格式
37+
content = json.dumps(params)
38+
39+
# 发起post请求
40+
r = requests.post(url=apiurl, data=content, verify=False).json()
41+
print("r = " + str(r))
42+
43+
# 解析json响应结果
44+
# {'emotion':{
45+
# 'robotEmotion': {'a': 0, 'd': 0, 'emotionId': 0, 'p': 0},
46+
# 'userEmotion': {'a': 0, 'd': 0, 'emotionId': 10300, 'p': 0}
47+
# },
48+
# 'intent': {
49+
# 'actionName': '',
50+
# 'code': 10004,
51+
# 'intentName': ''
52+
# },
53+
# 'results': [{'groupType': 1, 'resultType': 'text', 'values': {'text': '欢迎来到本机器人的地盘。'}}]}
54+
code = r['intent']['code']
55+
if code == 10004 or code == 10008:
56+
message = r['results'][0]['values']['text']
57+
return message
58+
return None
59+

actions/WeatherApis.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# 访问openapi
2+
# -*- coding: utf-8 -*-
3+
"""
4+
WeatherApis.py
5+
~~~~~~~~~
6+
7+
使用心知天气数据查询天气
8+
9+
:date: 2020-02-10 15:56:00
10+
:author: by jiangdg
11+
"""
12+
13+
import requests
14+
import json
15+
16+
KEY = 'rmhrne8hal69uwyv' # API key(私钥)
17+
UID = "" # 用户ID, TODO: 当前并没有使用这个值,签名验证方式将使用到这个值
18+
19+
LOCATION = 'beijing' # 所查询的位置,可以使用城市拼音、v3 ID、经纬度等
20+
API = 'https://api.seniverse.com/v3/weather/daily.json' # API URL,可替换为其他 URL
21+
UNIT = 'c' # 单位
22+
LANGUAGE = 'zh-Hans' # 查询结果的返回语言
23+
24+
25+
def fetch_weather(location, start=0, days=15):
26+
result = requests.get(API, params={
27+
'key': KEY,
28+
'location': location,
29+
'language': LANGUAGE,
30+
'unit': UNIT,
31+
'start': start,
32+
'days': days
33+
}, timeout=2)
34+
return result.json()
35+
36+
37+
def get_weather_by_day(location, day=1):
38+
result = fetch_weather(location)
39+
normal_result = {
40+
"location": result["results"][0]["location"],
41+
"result": result["results"][0]["daily"][day]
42+
}
43+
44+
return normal_result
45+
46+
47+
if __name__ == '__main__':
48+
default_location = "合肥"
49+
result = fetch_weather(default_location)
50+
print(json.dumps(result, ensure_ascii=False))
51+
52+
default_location = "合肥"
53+
result = get_weather_by_day(default_location)
54+
print(json.dumps(result, ensure_ascii=False))

actions/__init__.py

Whitespace-only changes.

actions/action.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from typing import Dict, Text, Any, List
2+
3+
from rasa_sdk import Tracker, Action
4+
from rasa_sdk.events import UserUtteranceReverted, Restarted
5+
from rasa_sdk.executor import CollectingDispatcher
6+
from rasa_sdk.forms import FormAction
7+
8+
from actions import ChatApis
9+
from actions.WeatherApis import get_weather_by_day
10+
from requests import (
11+
ConnectionError,
12+
HTTPError,
13+
TooManyRedirects,
14+
Timeout
15+
)
16+
17+
18+
class WeatherForm(FormAction):
19+
20+
def name(self) -> Text:
21+
"""Unique identifier of the form"""
22+
23+
return "weather_form"
24+
25+
@staticmethod
26+
def required_slots(tracker: Tracker) -> List[Text]:
27+
"""A list of required slots that the form has to fill"""
28+
29+
return ["date-time", "address"]
30+
31+
def submit(
32+
self,
33+
dispatcher: CollectingDispatcher,
34+
tracker: Tracker,
35+
domain: Dict[Text, Any],
36+
) -> List[Dict]:
37+
"""Define what the form has to do
38+
after all required slots are filled"""
39+
address = tracker.get_slot('address')
40+
date_time = tracker.get_slot('date-time')
41+
42+
date_time_number = text_date_to_number_date(date_time)
43+
44+
if isinstance(date_time_number, str): # parse date_time failed
45+
dispatcher.utter_message("暂不支持查询 {} 的天气".format([address, date_time_number]));
46+
else:
47+
weather_data = get_text_weather_date(address, date_time, date_time_number)
48+
dispatcher.utter_message(weather_data);
49+
return [Restarted()]
50+
51+
52+
def get_text_weather_date(address, date_time, date_time_number):
53+
try:
54+
result = get_weather_by_day(address, date_time_number)
55+
except (ConnectionError, HTTPError, TooManyRedirects, Timeout) as e:
56+
text_message = "{}".format(e)
57+
else:
58+
text_message_tpl = """
59+
{} {} ({}) 的天气情况为:白天:{};夜晚:{};气温:{}-{} °C
60+
"""
61+
text_message = text_message_tpl.format(
62+
result['location']['name'],
63+
date_time,
64+
result['result']['date'],
65+
result['result']['text_day'],
66+
result['result']['text_night'],
67+
result['result']["high"],
68+
result['result']["low"],
69+
)
70+
71+
return text_message
72+
73+
74+
def text_date_to_number_date(text_date):
75+
if text_date == "今天":
76+
return 0
77+
if text_date == "明天":
78+
return 1
79+
if text_date == "后天":
80+
return 2
81+
82+
# Not supported by weather API provider freely
83+
if text_date == "大后天":
84+
# return 3
85+
return text_date
86+
87+
if text_date.startswith("星期"):
88+
# TODO: using calender to compute relative date
89+
return text_date
90+
91+
if text_date.startswith("下星期"):
92+
# TODO: using calender to compute relative date
93+
return text_date
94+
95+
# follow APIs are not supported by weather API provider freely
96+
if text_date == "昨天":
97+
return text_date
98+
if text_date == "前天":
99+
return text_date
100+
if text_date == "大前天":
101+
return text_date
102+
103+
104+
class ActionDefaultFallback(Action):
105+
"""Executes the fallback action and goes back to the previous state
106+
of the dialogue"""
107+
108+
def name(self):
109+
return 'action_default_fallback'
110+
111+
def run(self, dispatcher, tracker, domain):
112+
113+
# 访问图灵机器人API(闲聊)
114+
text = tracker.latest_message.get('text')
115+
message = ChatApis.get_response(text)
116+
if message is not None:
117+
dispatcher.utter_message(message)
118+
else:
119+
dispatcher.utter_template('utter_default', tracker, silent_fail=True)
120+
return [UserUtteranceReverted()]

configs/config.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
language: "zh"
2+
3+
pipeline:
4+
- name: "MitieNLP"
5+
model: "data/total_word_feature_extractor_zh.dat"
6+
- name: "JiebaTokenizer"
7+
- name: "MitieEntityExtractor"
8+
- name: "EntitySynonymMapper"
9+
- name: "RegexFeaturizer"
10+
- name: "MitieFeaturizer"
11+
- name: "SklearnIntentClassifier"
12+
13+
policies:
14+
- name: KerasPolicy
15+
epochs: 500
16+
max_history: 5
17+
- name: FallbackPolicy
18+
fallback_action_name: 'action_default_fallback'
19+
- name: MemoizationPolicy
20+
max_history: 5
21+
- name: FormPolicy

0 commit comments

Comments
 (0)