【公众号开发】人工智能让我们的公众号活起来

开发之前

在之前的分享中,我们已经完成了公众号的基本框架的搭建,也完成了基于NLP知识的图文检索功能,可以说之前的内容都是原生开发,无论是公众号基础能力建设还是图文检索能力,本章分享,将会在之前的基础上,通过云服务商为我们提供的AI能力,将智能聊天接入其中。

首先假设一个场景:用户关注这个公众号之后,他给公众号发送文本消息,我们首先进行图文检索,如果没找到合适的结果,我们就默认进入“聊天功能”;如果用户发送了语音,我们同样先进行图文检索,如果没有找得到相似图文,则通过语音进入“聊天功能”,这样看来是不是整个功能变得非常有趣?

功能预览

image

开始开发

聊天功能增加

聊天功能我们可以借助云厂商提供的聊天机器人服务:

image

开通和使用这个服务,可以为我们创建一个简单的机器人:

image

创建完成机器人,我们可以通过云API对其进行代码的编写,云API代码比较难写也不怕,有API Explorer:

image

系统会为我们自动编写好基本的代码,我们只需要稍加修改,就可以复制到项目中:

在最外层进行相关初始化:

tbpClient = tbp_client.TbpClient(credential.Credential(secret_id, secret_key), region)

初始化完成,增加聊天机器人函数:

def chatBot(user, content):
    '''
    开发文档:https://cloud.tencent.com/document/product/1060/37438
    :param user: 用户id
    :param content: 聊天内容
    :return: 返回机器人说的话,如果出现故障返回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

文本转音频功能增加

同样的方法,这不过是使用的另一个产品:

image

同样通过Explorer编写代码,然后初始化:

ttsClient = tts_client.TtsClient(credential.Credential(secret_id, secret_key), region)

增加相关的方法实现文本到函数的转换:

def text2Voice(text):
    '''
    文档地址:https://cloud.tencent.com/document/product/1073/37995
    :param text: 带转换的文本
    :return: 返回转换后的文件地址
    '''
    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

增加微信的素材相关逻辑

由于我的账号是未认证的订阅号,所以可以使用的功能有限。在这里我需要先将生成的语音素材上传到公众号后台作为永久素材。因为语音类素材最大量为1000个,所以我还要顺便删除多余的素材。

此处我的做法很简单,先上传素材,然后获得素材总数,接下来根据素材中的时间戳:

{'
    media_id': 'HQOG98Gpaa4KcvU1L0MPEW4Zvngs4kBqOyTRzNWBNME', 
    'name': 'ljpmybc.wav',
    'update_time': 1582896372, 
    'tags': []
}

就是update_time这个参数,和现在的时间进行判断,超过60S则认为这个素材已经过期,就可以删除,这样保证我们的素材数量不会溢出:

增加永久素材:

def addingOtherPermanentAssets(file, fileType):
    '''
    文档地址:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html
    返回结果:{
                "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())

至此,基础代码已经完成,剩下的逻辑就是在main_handler中进行组合:

文本消息部分的组合逻辑:

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 "目前还没有类似的文章被发布在这个公众号上"}, 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": "目前还没有类似的文章被发布在这个公众号上"}, event)
return response(body=result)

老规矩,今日份的代码同样更新到Github上,欢迎大家三连击:


image

image

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • “没想到这么多年过去了,最后还是只有你陪我说话。”严松看着眼前的牌位,眼神黯淡,“要是世铎还在的话,我应该不会常到...
    小子黄阅读 466评论 0 2
  • 男孩抱着目的来加女孩的QQ,想让她帮忙追女孩的好朋友,可惜结果不如人意。也正是这个契机,两人慢慢联系得多了,男孩对...
    爱吃蛋炒饭的小黄同学阅读 840评论 1 4
  • 感恩伟大智慧的格西老师!让我走在智慧的路上!祈愿全世界每个人都能遇到善知识! 感恩健康的身体,让我从睡梦中醒来来!...
    椿芽儿香阅读 155评论 0 3
  • 【禅诗偈语】 直视无前气吐虹,五湖三岛在胸中。 相逢莫怪不相揖,只见山僧不见公。 ——苏轼 【一缕禅思】 公元10...
    南北王阅读 736评论 3 4