阿里云+python+flask+ngnix零基础从零开始搭建微信公众号进行后台AI开发全套教程

一、微信公众号开发基础

1.1 与公众号的消息会话

在部署好一个微信公众号时,用户通过微信客户端向公众号发送文本消息并请求返回,这一过程实际上分为四个阶段:

1.用户向微信服务器发出请求
2.微信服务器向云服务器转发请求
3.云服务器接收请求并返回给云服务器响应消息
4.微信服务器再返回给用户回复消息

1.2 搭建开发者环境

开发者环境是指我们开发微信公众号的环境,与云服务器的运行环境相对应。微信官方为开发者提供了开发者文档,里面规定了开发微信公众号所使用的端口号(只能用80(http)和443(https)这两个,实际上微信公众号只支持80端口)。
按照开发者文档,我们首先需要在开发者环境下搭建开发环境:

1.2.1 配置nginx环境

nginx作为高性能的HTTP和反向代理web服务器,负责将每个用户账号从80端口跑到固定的端口,如从8001开始,8002,8003…以此类推。注意运行在哪个端口,微信服务器配置的URL对应的就是wechatXXXX。
首先在云服务器上安装nginx:

sudo apt-get install nginx

接下来在云服务器上打开/etc/nginx/sites-available, 使用vim编辑该目录下的default文件:

sudo vim /etc/nginx/sites-available/default

找到文件中的server部分,将

location / {
	XXXXX
}

这一部分内容改为:

	location /wechat8000 {
	proxy_pass_header Server;
	proxy_set_header Host $http_host;
	proxy_redirect off;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Scheme $scheme;
	proxy_pass http://127.0.0.1:8000;
	}

修改后的default文件(去掉部分注释):

##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or WordPress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;

	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location /wechat8000 {undefined

	proxy_pass_header Server;

	proxy_set_header Host $http_host;

	proxy_redirect off;

	proxy_set_header X-Real-IP $remote_addr;

	proxy_set_header X-Scheme $scheme;

	proxy_pass http://127.0.0.1:8000;

	}

}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}

1.2.2 云服务器与微信服务器建立连接

我们需要在后端服务器上实现一个/wechat80XX的视图,基于这个视图就可以实现微信服务器和后端云服务器的通信:

接下来向服务器上传一个wechat.py文件,用于向微信服务器建立连接。上传方式可以是ftp,也可以是ssh远程传输(效果一样)。
wechat.py(记得修改token、填写APPID和APPSECRET):

 # coding:utf-8

from flask import Flask, request, abort, render_template
import hashlib
import xmltodict
import time
import urllib.request as urllib2
import json

# 微信的token令牌
WECHAT_TOKEN = '你的token'
WECHAT_APPID = '你的APPID'
WECHAT_APPSECRET = '你的APPSECRET'


app = Flask(__name__)


@app.route("/wechat8000", methods=["GET", "POST"])
def wechat():
    """对接微信公众号服务器"""
    # 接收微信服务器发送的参数
    signature = request.args.get("signature")
    timestamp = request.args.get("timestamp")
    nonce = request.args.get("nonce")

    # 校验参数
    if not all([signature, timestamp, nonce]):
        abort(400)

    # 按照微信的流程进行计算签名
    li = [WECHAT_TOKEN, timestamp, nonce]
    # 排序
    li.sort()
    # 拼接字符串
    tmp_str = "".join(li)
    # 进行sha1加密,得到正确的签名值
    sign = hashlib.sha1(tmp_str.encode("utf-8")).hexdigest()

    # 将自己计算的签名值与请求的签名参数进行对比,如果相同,则证明请求来自微信
    if signature != sign:
        # 表示请求不是微信发的
        abort(403)
    else:
        # 表示是微信发送的请求
        if request.method == "GET":
            # 表示是第一次接入微信服务器的验证
            echostr = request.args.get("echostr")
            if not echostr:
                abort(400)
            return echostr
        elif request.method == "POST":
            # 表示是微信服务器转发消息过来
            xml_str = request.data
            if not xml_str:
                abort(400)

            # 对xml字符串进行解析
            xml_dict = xmltodict.parse(xml_str)
            xml_dict = xml_dict["xml"]

            # 提取消息类型
            msg_type = xml_dict.get("MsgType")

            if msg_type == "text":
                # 表示发送的是文本消息
                # 构造返回值,经由微信服务器回复给用户的消息内容
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": xml_dict.get("Content")
                    }
                }
            else:
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": "i love u"
                    }
                }

            # 将字典转换成xml字符串
            resp_xml_str = xmltodict.unparse(resp_dict)
            # 返回消息数据给微信服务器
            return resp_xml_str


@app.route('/wechat8000/index')
def index():
    """让用户通过微信访问的网页页面视图"""
    # 从微信服务器中拿取用户的资料数据
    # 1. 拿取code参数
    code = request.args.get("code")
    if not code:
        return "缺失code参数"

    # 2. 向微信服务器发送http请求,获取access_token
    url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" 
          % (WECHAT_APPID, WECHAT_APPSECRET, code)

    # 使用urllib2的urlopen方法发送请求
    # 如果只传网址url参数,则默认使用http的get请求方式
    response = urllib2.urlopen(url)

    # 获取响应体数据,微信返回的json数据
    json_str = response.read()
    resp_dict = json.loads(json_str)

    # 提取access_token
    if "errcode" in resp_dict:
        return "获取access_token失败"
    access_token = resp_dict.get("access_token")
    open_id = resp_dict.get("openid")

    # 3. 向微信服务器发送http请求,获取用户的资料数据
    url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" 
          % (access_token, open_id)

    response = urllib2.urlopen(url)

    # 读取微信传回的json的响应体数据
    user_json_str = response.read()
    user_dict_data = json.loads(user_json_str)

    if "errcode" in user_dict_data:
        return "获取用户信息失败"
    else:
        # 将用户的资料数据填充到页面
        return render_template("index.html", user=user_dict_data)


if __name__ == '__main__':
    app.run(port=8000, debug=True)

通过xftp软件向服务器上传修改后的wechat.py文件:
在这里插入图片描述

云服务器上需要同步基于python的flask,这是一个轻量级web框架,先在服务器上安装flask:

pip install flask

查看端口号8000的开放情况(使用阿里云的朋友记得在阿里云的安全组配置上面开放80端口和8000端口的使用):

netstat -apn | grep 8000

进入虚拟环境:

conda activate paddle_env

前面编写写的GET和POST方法向微信服务器请求access_token,运行wechat.py文件,与微信服务器建立连接,获取accexx_token:

在这里插入图片描述

在URL输入框里的IP后面不用添加端口号,因为一方面微信公众号http协议只支持80端口,另一方面我们先让微信服务器把消息转发到云服务器的nginix上,然后再交给服务器,注意URL一定要填http而不是https,否则不成功:
在这里插入图片描述
提交后显示成功,然后点击启用:
在这里插入图片描述

二、微信公众号部署AI对话机器人

服务器运行AI部署代码:

import paddlenlp
import utils
from utils import select_sum
from utils import post_process_sum

from flask import Flask, request, abort, render_template
import hashlib
import xmltodict
import time
import urllib.request as urllib2
import json

# 微信的token令牌
WECHAT_TOKEN = '你的token'
WECHAT_APPID = '你的APPID'
WECHAT_APPSECRET = '你的SECRET'
model = paddlenlp.transformers.UNIMOLMHeadModel.from_pretrained('data126898')
tokenizer = paddlenlp.transformers.UNIMOTokenizer.from_pretrained('unimo-text-1.0')
model.eval()
num_return_sequences = 8

app = Flask(__name__)


@app.route("/wechat8000", methods=["GET", "POST"])
def wechat():
    """对接微信公众号服务器"""
    # 接收微信服务器发送的参数
    signature = request.args.get("signature")
    timestamp = request.args.get("timestamp")
    nonce = request.args.get("nonce")

    # 校验参数
    if not all([signature, timestamp, nonce]):
        abort(400)

    # 按照微信的流程进行计算签名
    li = [WECHAT_TOKEN, timestamp, nonce]
    # 排序
    li.sort()
    # 拼接字符串
    tmp_str = "".join(li)
    # 进行sha1加密,得到正确的签名值
    sign = hashlib.sha1(tmp_str.encode("utf-8")).hexdigest()

    # 将自己计算的签名值与请求的签名参数进行对比,如果相同,则证明请求来自微信
    if signature != sign:
        # 表示请求不是微信发的
        abort(403)
    else:
        # 表示是微信发送的请求
        if request.method == "GET":
            # 表示是第一次接入微信服务器的验证
            echostr = request.args.get("echostr")
            if not echostr:
                abort(400)
            return echostr
        elif request.method == "POST":
            # 表示是微信服务器转发消息过来
            xml_str = request.data
            if not xml_str:
                abort(400)

            # 对xml字符串进行解析
            xml_dict = xmltodict.parse(xml_str)
            xml_dict = xml_dict["xml"]

            # 提取消息类型
            msg_type = xml_dict.get("MsgType")

            if msg_type == "text":
                # 表示发送的是文本消息
                # 构造返回值,经由微信服务器回复给用户的消息内容
                source_text = xml_dict.get("Content")
                # 由于训练时间较长,这里我们直接读训练好的模型

                inputs = source_text
                inputs_ids = tokenizer.gen_encode(inputs, return_tensors=True, add_start_token_for_decoding=True,
                                                  return_position_ids=True)
                # 调用生成api并指定解码策略为beam_search
                outputs, scores = model.generate(**inputs_ids, decode_strategy='beam_search', num_beams=8,
                                                 num_return_sequences=num_return_sequences)
                # 调用生成api并指定解码策略为Sampling,不同策略的效果不同哦。
                r = ''
                for i in range(num_return_sequences):
                    r = r+'{} 上联: {} 下联:{}'.format(i, inputs, ''.join(post_process_sum(outputs[i].numpy(), tokenizer)[1]))+'n'


                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": r
                    }
                }
            else:
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": "i love u"
                    }
                }

            # 将字典转换成xml字符串
            resp_xml_str = xmltodict.unparse(resp_dict)
            resp_xml_str = resp_xml_str+"我爱你"
            # 返回消息数据给微信服务器
            return resp_xml_str


@app.route('/wechat8000/index')
def index():
    """让用户通过微信访问的网页页面视图"""
    # 从微信服务器中拿取用户的资料数据
    # 1. 拿取code参数
    code = request.args.get("code")
    if not code:
        return "缺失code参数"

    # 2. 向微信服务器发送http请求,获取access_token
    url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" 
          % (WECHAT_APPID, WECHAT_APPSECRET, code)

    # 使用urllib2的urlopen方法发送请求
    # 如果只传网址url参数,则默认使用http的get请求方式
    response = urllib2.urlopen(url)

    # 获取响应体数据,微信返回的json数据
    json_str = response.read()
    resp_dict = json.loads(json_str)

    # 提取access_token
    if "errcode" in resp_dict:
        return "获取access_token失败"
    access_token = resp_dict.get("access_token")
    open_id = resp_dict.get("openid")

    # 3. 向微信服务器发送http请求,获取用户的资料数据
    url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" 
          % (access_token, open_id)

    response = urllib2.urlopen(url)

    # 读取微信传回的json的响应体数据
    user_json_str = response.read()
    user_dict_data = json.loads(user_json_str)

    if "errcode" in user_dict_data:
        return "获取用户信息失败"
    else:
        # 将用户的资料数据填充到页面
        return render_template("index.html", user=user_dict_data)

if __name__ == '__main__':
    app.run(port=8000, debug=True)





服务器运行结果:
在这里插入图片描述
公众号效果:
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>