背景介绍

itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单。

使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人。

官方文档参考https://itchat.readthedocs.io/zh/latest/

最近要做一个自动应答机器人,获得用户消息GUI+语义分析+机器学习给出答案。

准备工作

需要安装ffmpeg(百度搜索官网,下载windows版解压后把bin目录添加到系统变量的path中)
pip安装 pydub,SpeechRecognition

pip install pydub
pip install SpeechRecognition

绑定消息

GUI这部分使用微信的itchat接口,安装和新手教程可以自己参考官方文档。

绑定语音消息回复的方式为:

@itchat.msg_register(RECORDING)
def tuling_reply(msg):

 其中用的是RECORDING是因为之前代码最开始有from itchat.content import *,否则就要使用itchat.content.RECORDING

关于@修饰符的作用,网上百度就有,说下自己的思考:

    @de
    def func1:
    ----- 等价于 ------
    func1 = de( func1 )

Python解释器读到函数修饰符“@”的时候,后面步骤会是这样了:

1. 去调用de函数,de函数的入口参数就是那个叫“func1”的函数;

2. de函数被执行,入口参数的(也就是func1函数)会被调用(执行);

换言之,修饰符带的那个函数的入口参数,就是下面的那个整个的函数。

参考https://blog.csdn.net/972301/article/details/59537712和 https://blog.csdn.net/fwenzhou/article/details/8733857

所以我们使用@的时候,itchat.msg_register这个函数就被执行了,我们定义的tuling_reply作为参数传了进去,所以才会读取到消息就用这个函数处理消息

 

语音识别

由于微信保存的语音消息都是mp3格式,看了一圈发现只有腾讯语音识别支持mp3,之前尝试过腾讯一句话识别语音API,但是官方没有最新的例程,并且居然不同部分用的是不同版本的文档说明,导致我鉴权一直失败。到后来仔细研读了下,自己写了代码,鉴权应该是通过了,但是返回的消息是x‘\98'这样的一个中文字符,并且解码会失败,这才发现可能是因为腾讯的只支持中文,虽然我在这个随笔的例子是中文语音识别,但我实际项目要做的是英文语音识别。不过在这中间也学到了一些东西,比如加密算法的使用,还有python3的二进制和字符串消息的转换关系。

 1 import binascii
 2 import hashlib
 3 import hmac
 4 import urllib.parse
 5 import urllib.request
 6 import time
 7 import random
 8 import base64
 9 
10 def asr(msg):
11     msg['Text'](msg['FileName'])#保存mp3语音
12     timeData = str(int(time.time())) # 时间戳
13     nonceData = int(random.random()*10000) # Nonce,官网给的信息:随机正整数,与 Timestamp 联合起来, 用于防止重放攻击
14     with open(msg['FileName'], 'rb') as f:
15         voiceData = f.read()#读取mp3语音,获得byte数据,格式是b'\x..'
16     os.remove(msg['FileName'])#删除mp3语音
17     DataLenData = len(voiceData)#读取未base64编码之前的文件长度
18     tmp = int(timeData)#time stamp
19     signDictData = {#需要注意的是字典的key值要按照ascii码升序排序,并不一定是字典序,可以使用sorted(signDictData.keys())来查看ascii码排序结果
20         'Action' : actionData,
21         'Data': base64.b64encode(voiceData).decode('utf8'),#base64编码,编码后是二进制,再用decode解码
22         # 'Data': voiceData,
23         'DataLen': DataLenData,
24         'EngSerViceType': EngSerViceTypeData,
25         'Nonce' : nonceData,
26         'ProjectId':0,
27         'Region': 'ap-shanghai',
28         'SecretId' : secretId,
29         # 'SignatureMethod': 'HmacSHA256',#加密算法可选,不指定这个参数默认是HmacSHA1加密
30         'SourceType': SourceTypeData,
31         'SubServiceType': SubServiceTypeData,
32         'Timestamp' : tmp,
33         'UsrAudioKey': UsrAudioKeyData,
34         'Version': versionData,
35         'VoiceFormat': VoiceFormatData
36     }
37     #   请求方法 + 请求主机 +请求路径 + ? + 请求字符串
38     requestStr = "%s%s%s%s%s"%(requestMethod,uriData,"/","?",dictToStr(signDictData))
39     # signData = urllib.parse.quote(sign(secretKey,requestStr,'HmacSHA1'))
40     #生成签名字符的时候一定是使用的没有经过urlencode编码的requestStr字符串,下面的加了encode的就是把字符串变成byte,sha1是算法,decode是把二进制解码为字符串。digest()是把hmac.new()的结果解析成字符串,然后经过base64编码为byte,再解码为字符串
41     signData = binascii.b2a_base64(hmac.new(secretKey.encode('utf-8'), requestStr.encode('utf-8'), hashlib.sha1).digest())[:-1].decode()
42     # 上述操作是实现签名,下面即进行请求
43     # 先建立请求参数, 此处参数只在签名时多了一个Signature
44     actionArgs = {
45         'Action' : actionData,
46         'Data': base64.b64encode(voiceData).decode('utf8'),
47         # 'Data': voiceData,
48         'DataLen': DataLenData,
49         'EngSerViceType': EngSerViceTypeData,
50         'Nonce' : nonceData,
51         'ProjectId':0,
52         'Region': 'ap-shanghai',
53         'SecretId' : secretId,
54         'SourceType': SourceTypeData,
55         'SubServiceType': SubServiceTypeData,
56         'Timestamp' : tmp,
57         'UsrAudioKey': UsrAudioKeyData,
58         'Version': versionData,
59         'VoiceFormat': VoiceFormatData,
60         "Signature": signData
61     }
62     # 根据uri构建请求的url
63     requestUrl = "https://%s/?"%(uriData)
64     # 将请求的url和参数进行拼接,使用urlencode会修改掉参数中的/和=等符号的表示方式
65     requestUrlWithArgs = requestUrl + urllib.parse.urlencode(actionArgs)
66 
67     # actionArgs = signDictData #这是深复制,两个字典就是一个字典
68     # actionArgs["Signature"] = signData
69 
70     # # 根据uri构建请求的url
71     # requestUrl = "https://%s/?"%(uriData)
72     # # 将请求的url和参数进行拼接
73     # requestUrlWithArgs = requestUrl + dictToStr(actionArgs)
74 
75     # 获得response
76     responseData = urllib.request.urlopen(requestUrlWithArgs).read().decode("utf-8")# 根据uri构建
77     # return json.loads(responseData)["Response"]["Error"]["Message"] #处理错误消息
78     return json.loads(responseData)["Response"]["Result"]#处理正确消息
读取语音文件和腾讯API语音识别

相关文章: