開發(fā)之前
在之前的分享中睦番,我們已經(jīng)完成了公眾號的基本框架的搭建,也完成了基于NLP知識的圖文檢索功能,可以說之前的內(nèi)容都是原生開發(fā)丐箩,無論是公眾號基礎(chǔ)能力建設(shè)還是圖文檢索能力,本章分享恤煞,將會在之前的基礎(chǔ)上屎勘,通過云服務(wù)商為我們提供的AI能力,將智能聊天接入其中居扒。
首先假設(shè)一個場景:用戶關(guān)注這個公眾號之后概漱,他給公眾號發(fā)送文本消息,我們首先進(jìn)行圖文檢索喜喂,如果沒找到合適的結(jié)果瓤摧,我們就默認(rèn)進(jìn)入“聊天功能”;如果用戶發(fā)送了語音玉吁,我們同樣先進(jìn)行圖文檢索照弥,如果沒有找得到相似圖文,則通過語音進(jìn)入“聊天功能”进副,這樣看來是不是整個功能變得非常有趣产喉?
功能預(yù)覽
開始開發(fā)
聊天功能增加
聊天功能我們可以借助云廠商提供的聊天機(jī)器人服務(wù):
開通和使用這個服務(wù),可以為我們創(chuàng)建一個簡單的機(jī)器人:
創(chuàng)建完成機(jī)器人,我們可以通過云API對其進(jìn)行代碼的編寫曾沈,云API代碼比較難寫也不怕这嚣,有API Explorer:
系統(tǒng)會為我們自動編寫好基本的代碼,我們只需要稍加修改塞俱,就可以復(fù)制到項目中:
在最外層進(jìn)行相關(guān)初始化:
tbpClient = tbp_client.TbpClient(credential.Credential(secret_id, secret_key), region)
初始化完成姐帚,增加聊天機(jī)器人函數(shù):
def chatBot(user, content):
'''
開發(fā)文檔:https://cloud.tencent.com/document/product/1060/37438
:param user: 用戶id
:param content: 聊天內(nèi)容
:return: 返回機(jī)器人說的話,如果出現(xiàn)故障返回None
'''
try:
req = tbp_models.TextProcessRequest()
params = '{"BotId":"%s","BotEnv":"release","TerminalId":"%s","InputText":"%s"}' % (
bot_id, user, content
)
req.from_json_string(params)
resp = tbpClient.TextProcess(req)
return json.loads(resp.to_json_string())['ResponseMessage']['GroupList'][0]['Content']
except Exception as e:
print(e)
return None
文本轉(zhuǎn)音頻功能增加
同樣的方法障涯,這不過是使用的另一個產(chǎn)品:
同樣通過Explorer編寫代碼罐旗,然后初始化:
ttsClient = tts_client.TtsClient(credential.Credential(secret_id, secret_key), region)
增加相關(guān)的方法實現(xiàn)文本到函數(shù)的轉(zhuǎn)換:
def text2Voice(text):
'''
文檔地址:https://cloud.tencent.com/document/product/1073/37995
:param text: 帶轉(zhuǎn)換的文本
:return: 返回轉(zhuǎn)換后的文件地址
'''
try:
req = tts_models.TextToVoiceRequest()
params = '{"Text":"%s","SessionId":"%s","ModelType":1,"VoiceType":1002}' % (
text, "".join(random.sample('zyxwvutsrqponmlkjihgfedcba', 7)))
req.from_json_string(params)
resp = ttsClient.TextToVoice(req)
file = '/tmp/' + "".join(random.sample('zyxwvutsrqponmlkjihgfedcba', 7)) + ".wav"
with open(file, 'wb') as f:
f.write(base64.b64decode(json.loads(resp.to_json_string())["Audio"]))
return file
except Exception as e:
print(e)
return None
增加微信的素材相關(guān)邏輯
由于我的賬號是未認(rèn)證的訂閱號,所以可以使用的功能有限唯蝶。在這里我需要先將生成的語音素材上傳到公眾號后臺作為永久素材九秀。因為語音類素材最大量為1000個,所以我還要順便刪除多余的素材粘我。
此處我的做法很簡單鼓蜒,先上傳素材,然后獲得素材總數(shù)征字,接下來根據(jù)素材中的時間戳:
{'
media_id': 'HQOG98Gpaa4KcvU1L0MPEW4Zvngs4kBqOyTRzNWBNME',
'name': 'ljpmybc.wav',
'update_time': 1582896372,
'tags': []
}
就是update_time
這個參數(shù)都弹,和現(xiàn)在的時間進(jìn)行判斷,超過60S則認(rèn)為這個素材已經(jīng)過期匙姜,就可以刪除畅厢,這樣保證我們的素材數(shù)量不會溢出:
增加永久素材:
def addingOtherPermanentAssets(file, fileType):
'''
文檔地址:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html
返回結(jié)果:{
"media_id":"HQOG98Gpaa4KcvU1L0MPEcyy31LSuHhRi8gD3pvebhI",
"url":"http:\/\/mmbiz.qpic.cn\/sz_mmbiz_png\/icxY5TTGTBibSyZPfLAEZmeaicUczsoGUpqLgBlRbNxeic4R8r94j60BiaxDLEZTAK7I7qubG3Ik808P8jYLdFJTcOA\/0?wx_fmt=png",
"item":[]
}
:param file:
:return:
'''
typeDict = {
"voice": "wav"
}
url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s&type=%s" % (
getAccessToken(), fileType)
boundary = '----WebKitFormBoundary7MA4YWxk%s' % "".join(random.sample('zyxwvutsrqponmlkjihgfedcba', 7))
with open(file, 'rb') as f:
fileData = f.read()
data = {'media': (os.path.split(file)[1], fileData, typeDict[fileType])}
headers = {
"Content-Type": "multipart/form-data; boundary=%s" % boundary,
"User-Agent": "okhttp/3.10.0"
}
reqAttr = urllib.request.Request(url=url,
data=encode_multipart_formdata(data, boundary=boundary)[0],
headers=headers)
responseData = json.loads(urllib.request.urlopen(reqAttr).read().decode("utf-8"))
try:
for eveVoice in getMaterialsList("voice", getTheTotalOfAllMaterials()['voice_count']):
try:
if int(time.time()) - int(eveVoice["update_time"]) > 60:
deletingPermanentAssets(eveVoice['media_id'])
except:
pass
except:
pass
return responseData['media_id'] if "media_id" in responseData else None
刪除素材:
def deletingPermanentAssets(media_id):
'''
文檔地址:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Deleting_Permanent_Assets.html
:return:
'''
url = 'https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=%s' % (getAccessToken())
data = {
"media_id": media_id
}
postData = json.dumps(data).encode("utf-8")
reqAttr = urllib.request.Request(url=url, data=postData)
print(urllib.request.urlopen(reqAttr).read())
至此,基礎(chǔ)代碼已經(jīng)完成氮昧,剩下的邏輯就是在main_handler中進(jìn)行組合:
文本消息部分的組合邏輯:
media_id = searchNews(event["Content"])
result = getNewsResult(media_id, event)
if not result:
chatBotResponse = chatBot(event["FromUserName"], event["Content"])
result = textXML({"msg": chatBotResponse if chatBotResponse else "目前還沒有類似的文章被發(fā)布在這個公眾號上"}, event)
return response(body=result)
語音消息部分組合邏輯:
media_id = searchNews(event["Recognition"])
result = getNewsResult(media_id, event)
if not result:
chatBotResponse = chatBot(event["FromUserName"], event["Recognition"])
if chatBotResponse:
voiceFile = text2Voice(chatBotResponse)
if voiceFile:
uploadResult = addingOtherPermanentAssets(voiceFile, 'voice')
if uploadResult:
result = voiceXML({"media_id": uploadResult}, event)
if not result:
result = textXML({"msg": "目前還沒有類似的文章被發(fā)布在這個公眾號上"}, event)
return response(body=result)
老規(guī)矩框杜,今日份的代碼同樣更新到Github上,歡迎大家三連擊: