Recently, I borrowed my girlfriend’s official number. I feel that if I only use it to send articles, it is too wasteful to provide these functions of wechat. Think about it, start with the simplest, make a chatbot.
There are several Python solutions for chatbots: AIML, chatterBot, Turing Chatbot and Microsoft Xiaoice.
After considering that may do some customized demand, here I chose a chatterBot (making project address: https://github.com/gunthercox/ChatterBot).
Chatterbot is a Python interface based on a set of rules and machine learning algorithms. With clear structure, good scalability, simple and practical characteristics.
Here’s how chatterBot works:
- An input adapter retrieves data from an input source such as a terminal or API
- Input source will be specified by the logical processing module (logic Adapter) respectively, logical processing module will match the closest to the input data of the training focus known sentence A, then according to the sentence to find the most relevant results B, if there are multiple logical processing module is returned to the different results, will be returned to one of the most relevant results.
- The output adapter returns the matched result to the terminal or API.
It is worth mentioning that chatterBot is a modular project with input Adapter, Logic Adapter, Storage Adapter, Output Adapter, and Trainer modules.
LogicAdapter is a plug-in design. When the main process starts up, it adds all the logic processing plug-ins defined by the user to the Logic context and then passes them to the MultiLogicAdapter for processing. The MultiLogicAdapter calls each LogicAdapter in turn. When the LogicAdapter is called, the can_process method is executed to determine whether the input can match the logic processing plug-in. A question such as “what’s the weather like today?” obviously requires a hit to the weather plugin, in which case the can_process of the time plugin returns False. After hitting the target, the logic Adapter calculates the Statement object and confidence, and the MultiLogicAdapter takes the response with the highest confidence and proceeds to the next step.
Now let’s see how chatterBot works
ChatterBot installation & Use
The installation
ChatterBot is written in Python and can be installed using PIP:
pip install chatterbotCopy the code
The Chinese version of chatterBot requires Python3 or later. It is recommended to develop in python3. x environment
test
Open iPython and test the input
In [1]: from chatterbot import ChatBot # import ChatBot
In [2]: momo = ChatBot('Momo', trainer='chatterbot.trainers.ChatterBotCorpusTrainer')/Users/gs /. Virtualenvs/py3 / lib/python3.6 / site - packages/chatterbot/storage/jsonfile py: 26: UnsuitableForProductionWarning: The JsonFileStorageAdapter is not recommendedfor production environments.
self.UnsuitableForProductionWarning If you want to deploy the storage Adapter on the server side, you should avoid using this format, because it is too slow
In [3]: momo.train("chatterbot.corpus.chinese") # specify training set, here we use Chinese
# Below is the result of the conversation
In [4]: momo.get_response('hello'Out[4]: <Statement text: Hello > In [5]: momo.get_response('What's up?'Out[5]: <Statement text: nothing.> In [6]: momo.get_response('Do you know all about it? ') Out[6]: <Statement text: beautiful than ugly.> In [7]: momo.get_response('Are you a programmer? 'Out[7]: <Statement text: I am a programmer > In [8]: momo.get_response('What language do you use? ') Out[8]: <Statement text: I often use Python, Java and C++.>Copy the code
At this point, you can talk to the robot, but now with so little training data, the robot can only return simple conversations.
This is the default Chinese conversation training data Chinese training data address: https://github.com/gunthercox/chatterbot-corpus/tree/master/chatterbot_corpus/data/chinese.
So how do we add training data?
Training robot
ChatterBot has built-in training class, which includes two methods. One is to type a list to train, such as “hello “,” I’m not good “, which is the former’s answer, and the other is to train by importing Corpus format files. Custom training modules are also supported, but ultimately both types are converted.
The chatterBot trains by calling the train() function, but before doing so it needs to be set up with set_trainer(). Such as:
In [12]: from chatterbot.trainers import ListTrainer # Import the ListTrainer class of the training module
In [13]: momo.get_response('What's your name? ') # Now is not the question, because we did not train before thisOut[13]: <Statement text: I am baking a cake.> In [14]: momo.set_trainer(ListTrainer)# specify the training mode
In [15]: momo.train(['What's your name? '.'My name is Mojo! ']) # training
In [16]: momo.get_response('What's your name? ') # Now the robot can answerOut[16]: <Statement text: >Copy the code
The trained data exists by default in./database.db, where jsonDB is used.
With the introduction of the chatterBot here first, specific usage can be reference documentation: chatterBot Tutorial: http://chatterbot.readthedocs.io/en/stable/tutorial.html
Next, I’ll show you how to use chatterBot in your project.
Create projects using Sanic
Sanic is a Python3.5+ based web framework with the same class as Flask, and it writes code very fast.
In addition to things like Flask, Sanic also supports processing requests as asynchronous requests. This means you can write non-blocking fast code using the new async/await syntax.
If you are not familiar with Sanic, please refer to my previous article: Python Web Framework Sanci Quick Start. You can type [Sanic] in the public number to get the address of the article.
Sanic is used here because it looks a lot like Flask, I’ve been using Flask for a long time, and it was written specifically for Python3.5, using coroutines.
First, I will build a project. I have already built the project here. The project structure is as follows:
.├ ── LICENSE ├─ readme.md ├─ manage.py# Run the file to start the project using the python manage.py command├── Momo │ ├─ __init__. Py │ ├─ app.py# Create app module│ ├─ Exercises ─ Helper.py │ ├─ Settings# Application configuration│ ├─ ├─ ├─ ├─ ├.py │ ├─ ├.py# Test module│ └ ─ ─ mweixin. Py# wechat message processing module├ ─ ─ requirements. TXT └ ─ ─ supervisord. ConfCopy the code
Source code I have uploaded to Github, interested can have a look, can also directly pull down the test. Project code address
Let’s focus on the hello.py file and helper.py.
# hello.py
# -*- coding: utf-8 -*-
from sanic import Sanic, Blueprint
from sanic.views import HTTPMethodView
from sanic.response import text
from momo.helper import get_momo_answer # import get robot answer get function
blueprint = Blueprint('index', url_prefix='/')
class ChatBot(HTTPMethodView):
# Chatbot HTTP request processing logic
async def get(self, request):
ask = request.args.get('ask')
If there is no value, return 'What did you say?'
if ask:
answer = get_momo_answer(ask)
return text(answer)
return text('What did you say? ')
blueprint.add_route(ChatBot.as_view(), '/momo')Copy the code
# helper.py
from chatterbot import ChatBot
momo_chat = ChatBot(
'Momo'.Use mongodb to store data
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'.Here we specify three adpaters
logic_adapters=[
"chatterbot.logic.BestMatch"."chatterbot.logic.MathematicalEvaluation".# Math module
"chatterbot.logic.TimeLogicAdapter".# Time module
],
input_adapter='chatterbot.input.VariableInputTypeAdapter',
output_adapter='chatterbot.output.OutputAdapter',
database='chatterbot',
read_only=True
)
def get_momo_answer(content):
# get the robot return result function
response = momo_chat.get_response(content)
if isinstance(response, str):
return response
return response.textCopy the code
Run the command python manage.py to start the project.
Access the URL in your browser: http://0.0.0.0:8000/momo? Are you a programmer
So far, we have started a Web project, and we can talk to the robot by visiting the URL. It’s time to join the wechat official number!
Access the wechat official account
The premise
- Have a wechat public account that can be used (subscription service account is ok, if not, you can use the test account provided by wechat)
- Have a server accessible from the outside world (VPS or public cloud can be used by new AWS users for free for one year, you can try it)
- The server is configured with python3 (virtualenvWrapper is recommended).
WeChat set
Log in to wechat official account: mp.weixin.qq.com
Open: Development > Basic Configuration
View public number development information:
Enable server configuration:
Set the request URL, here is the URL you configured (requires external access, only port 80 or 443)
For details, see the official document: Access Guide
If your server address has been configured, clicking Submit should now be successful. If not, let’s look at how to configure the server address.
Code sample
Let’s take a look at the view code of wechat request:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from six import StringIO
import re
import xmltodict
from chatterbot.trainers import ListTrainer
from sanic import Blueprint
from sanic.views import HTTPMethodView
from sanic.response import text
from sanic.exceptions import ServerError
from weixin import WeixinMpAPI
from weixin.lib.WXBizMsgCrypt import WXBizMsgCrypt
from momo.settings import Config
blueprint = Blueprint('weixin', url_prefix='/weixin')
class WXRequestView(HTTPMethodView):
def _get_args(self, request):
# Obtain wechat request parameters, add token concatenation into the complete request parameters
params = request.raw_args
if not params:
raise ServerError("invalid params", status_code=400)
args = {
'mp_token': Config.WEIXINMP_TOKEN,
'signature': params.get('signature'),
'timestamp': params.get('timestamp'),
'echostr': params.get('echostr'),
'nonce': params.get('nonce'),}return args
def get(self, request):
This step is a get request. The parameters can be obtained using request.raw_args
args = self._get_args(request)
weixin = WeixinMpAPI(**args) Python-weixin can instantiate a WeixinMpAPI object directly
if weixin.validate_signature(): Verify that the parameter is valid
# If the parameter is won, we will return the echostr parameter sent from wechat to wechat, otherwise return FAIL
return text(args.get('echostr') or 'fail')
return text('fail')
blueprint.add_route(WXRequestView.as_view(), '/request')Copy the code
Here I use the wechat SDK python-Weixin I wrote in Python to handle wechat requests, which can be installed using PIP:
pip install python-weixinCopy the code
The latest version of this package has some problems with Python3 encryption and decryption and can be installed directly from Github:
pip install git+https://github.com/zongxiao/python-weixin.git@py3Copy the code
Then update the app.py file:
# -*- coding: utf-8 -*-
from sanic import Sanic
from momo.settings import Config
def create_app(register_bp=True, test=False):
# to create the app
app = Sanic(__name__)
if test:
app.config['TESTING'] = True
Import configuration from object
app.config.from_object(Config)
register_blueprints(app)
return app
def register_blueprints(app):
from momo.views.hello import blueprint as hello_bp
from momo.views.mweixin import blueprint as wx_bp
app.register_blueprint(hello_bp)
# registered wx_bp
app.register_blueprint(wx_bp)Copy the code
Github: wechat chat robot momo for detailed code
Connecting to a chatbot
Now that our official accounts have access to our own services, it’s time to join the wechat chatbot.
The working flow of wechat chatbot is as follows:
Look at our message logic handling code:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from six import StringIO
import re
import xmltodict
from chatterbot.trainers import ListTrainer
from sanic import Blueprint
from sanic.views import HTTPMethodView
from sanic.response import text
from sanic.exceptions import ServerError
from weixin import WeixinMpAPI
from weixin.reply import TextReply
from weixin.response import WXResponse as _WXResponse
from weixin.lib.WXBizMsgCrypt import WXBizMsgCrypt
from momo.settings import Config
from momo.helper import validate_xml, smart_str, get_momo_answer
from momo.media import media_fetch
blueprint = Blueprint('weixin', url_prefix='/weixin')
appid = smart_str(Config.WEIXINMP_APPID)
token = smart_str(Config.WEIXINMP_TOKEN)
encoding_aeskey = smart_str(Config.WEIXINMP_ENCODINGAESKEY)
# copy returned automatically after following
AUTO_REPLY_CONTENT = """ Hi, friend! This is my mother April number, I am the devil, I can accompany you to chat yo! I can also "charge", and if YOU type "charge", you'll be surprised! < a href = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzAwNjI5MjAzNw==&scene=124#wechat_redirect" > history < / a > "" "
class ReplyContent(object):
_source = 'value'
def __init__(self, event, keyword, content=None, momo=True):
self.momo = momo
self.event = event
self.content = content
self.keyword = keyword
if self.event == 'scan':
pass
@property
def value(self):
if self.momo:
answer = get_momo_answer(self.content)
return answer
return ' '
class WXResponse(_WXResponse):
auto_reply_content = AUTO_REPLY_CONTENT
def _subscribe_event_handler(self):
# pay attention to the processing logic after the public number
self.reply_params['content'] = self.auto_reply_content
self.reply = TextReply(**self.reply_params).render()
def _unsubscribe_event_handler(self):
# Processing logic after removing the close, I will probably cry when removing the close
pass
def _text_msg_handler(self):
# Text message processing logic The main logic of a chatbot
event_key = 'text'
content = self.data.get('Content')
reply_content = ReplyContent('text', event_key, content)
self.reply_params['content'] = reply_content.value
self.reply = TextReply(**self.reply_params).render()
class WXRequestView(HTTPMethodView):
def _get_args(self, request):
params = request.raw_args
if not params:
raise ServerError("invalid params", status_code=400)
args = {
'mp_token': Config.WEIXINMP_TOKEN,
'signature': params.get('signature'),
'timestamp': params.get('timestamp'),
'echostr': params.get('echostr'),
'nonce': params.get('nonce'),}return args
def get(self, request):
args = self._get_args(request)
weixin = WeixinMpAPI(**args)
if weixin.validate_signature():
return text(args.get('echostr') or 'fail')
return text('fail')
def _get_xml(self, data):
post_str = smart_str(data)
Verify that the XML format is correct
validate_xml(StringIO(post_str))
return post_str
def _decrypt_xml(self, params, crypt, xml_str):
# decrypt messages
nonce = params.get('nonce')
msg_sign = params.get('msg_signature')
timestamp = params.get('timestamp')
ret, decryp_xml = crypt.DecryptMsg(xml_str, msg_sign,
timestamp, nonce)
return decryp_xml, nonce
def _encryp_xml(self, crypt, to_xml, nonce):
# Encrypt message
to_xml = smart_str(to_xml)
ret, encrypt_xml = crypt.EncryptMsg(to_xml, nonce)
return encrypt_xml
def post(self, request):
Get the request parameters sent by wechat server
args = self._get_args(request)
weixin = WeixinMpAPI(**args)
if not weixin.validate_signature(): Verify that the parameter is valid
raise AttributeError("Invalid weixin signature")
xml_str = self._get_xml(request.body) Get form data
crypt = WXBizMsgCrypt(token, encoding_aeskey, appid)
decryp_xml, nonce = self._decrypt_xml(request.raw_args, crypt, xml_str) # decryption
xml_dict = xmltodict.parse(decryp_xml)
xml = WXResponse(xml_dict)() or 'success' Get the robot return value based on the message using WXResponse
encryp_xml = self._encryp_xml(crypt, xml, nonce) # Encrypt message
return text(encryp_xml or xml) # Respond to wechat requests
blueprint.add_route(WXRequestView.as_view(), '/request')Copy the code
It can be seen that it is relatively simple for me to process the return result of wechat request, which is also the interface encapsulated by python-Weixin package. The main processing logic is WXResponse.
Note here that if the server does not respond within 5 seconds the wechat server will retry. To speed up response times, do not set the chatterBot’s storage Adapter to use JSONDB on the server.
These are the main processing logic of wechat chatbot. We run the service as follows:
As you can see here, the chatbot can also do simple math and tell the time, because I added the math module and time module when I specified the processing logic above:
momo_chat = ChatBot(
'Momo'.Use mongodb to store data
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'.Here we specify three adpaters
logic_adapters=[
"chatterbot.logic.BestMatch"."chatterbot.logic.MathematicalEvaluation".# Math module
"chatterbot.logic.TimeLogicAdapter".# Time module
],
input_adapter='chatterbot.input.VariableInputTypeAdapter',
output_adapter='chatterbot.output.OutputAdapter',
database='chatterbot',
read_only=True
)Copy the code
Here, WeChat robot structures, is completed, the detailed code has long ball to making: https://github.com/gusibi/momo/tree/chatterbot, interested can refer to it.
Refer to the link
- ChatterBot project address: https://github.com/gunthercox/ChatterBot
- ChatterBot Tutorial: http://chatterbot.readthedocs.io/en/stable/tutorial.html
- Quickly implement a bot in Python: http://www.jianshu.com/p/d1333fde266f
- Based on the Python – ChatterBot structures, different adapter bot: https://ask.hellobi.com/blog/guodongwei1991/7626
- Has automatic learning Python robot – ChatterBot: https://kantai235.github.io/2017/03/16/ChatterBotTeaching/
- Using bot ChatterBot building: https://www.biaodianfu.com/chatterbot.html
- python-weixin sdk: https://github.com/gusibi/python-weixin
trailer
Here, the chatbot is relatively simple and can only reply to simple conversations. The next post will end with how to train the bot on the bot and a more practical feature, how to turn the bot into a blog writing assistant.
Finally, thank your girlfriend for her support.
Welcome to follow (April_Louisa) | Buy me a Fanta |
---|---|