SCF:搭建智能客服/问答机器人

2019-06-27 13:22:23 浏览数 (2)

在实际生产生活中,我们经常会遇到别人问我们问题,而且这个问题是常见的,那么我们就会感到很烦躁:为啥总有人问相似的问题?再仔细冷静一下:我们可不可以做一个机器人,他可以自动回答一些问题?今天本文,就通过简单的方法,在SCF上部署一个问答机器人/智能客服,来为各位有需求的小伙伴,解决实际问题,当然,这篇文章也算是抛砖引玉。一方面,扩展一下大家使用SCF的思路,另一方面温故一下如何打包的方法,最后也尝试使用新的触发方法:云API触发。

准备阶段

首先,我们要有一个数据库,存储我们的问答系统,我这里在腾讯云购买一个云数据库(MySQL),并建立表和字段等信息:

并且插入几个问题:

然后,通过本地编写代码,进行测试:

读取数据库:

代码语言:javascript复制
def getAllDataFromDB(connection):
    cursor = connection.cursor()
    cursor.execute("""SELECT * FROM robot""")
    results = cursor.fetchall()
    data = [eve['question'] for eve in results]
    return data
    
connection = pymysql.connect(host="",
                                 user="",
                                 password="",
                                 port=int(),
                                 db="MyScfTest",
                                 charset='utf8',
                                 cursorclass=pymysql.cursors.DictCursor)
questions = getAllDataFromDB(connection)
connection.close()

使用gensim库,利用TFIDF算法来进行文本相似度计算,jieba进行分词,整理为指定格式->gensim库将要对比的文档通过doc2bow转化为稀疏向量->再通过models中的tf-idf将语料库进行处理->特征值和稀疏矩阵相似度建立索引->最后的到相似结果。

代码如下:

代码语言:javascript复制
def getAnswerList(sentence,questions,count=4):
    documents = []
    for eve_sentence in questions:
        tempData = " ".join(jieba.cut(eve_sentence))
        documents.append(tempData)
    texts=[[word for word in document.split()] for document in documents]
    frequency=defaultdict(int)
    for text in texts:
        for word in text:
            frequency[word] =1
    dictionary=corpora.Dictionary(texts)
    new_xs=dictionary.doc2bow(jieba.cut(sentence))
    corpus=[dictionary.doc2bow(text)for text in texts]
    tfidf=models.TfidfModel(corpus)
    featurenum=len(dictionary.token2id.keys())
    sim=similarities.SparseMatrixSimilarity(tfidf[corpus],num_features=featurenum)[tfidf[new_xs]]
    tempList = [(sim[i], questions[i]) for i in range(1,len(questions))]

    tempList.sort(key=lambda x:x[0],reverse=True)
    if len(tempList) >= count:
        return tempList[0:count]
    else:
        return tempList

这里面的思路是,进行相似度获取,然后根据相似度,进行排序,相似度最高的在前面,最低的放到最后。然后传入的sentence是提出的问题,传入的questions是问题列表,count是返回相似度最高的问题的个数。假如说,数据库有20个问题,那么我在进行了问题的相似度分析之后,会得到一个相似度大小的列表,我对列表排序之后,选择前count个问题返回给用户。

完整代码:

代码语言:javascript复制
import jieba,pymysql
from gensim import corpora,models,similarities
from collections import defaultdict

def getAllDataFromDB(connection):
    cursor = connection.cursor()
    cursor.execute("""SELECT * FROM robot""")
    results = cursor.fetchall()
    data = [eve['question'] for eve in results]
    return data

def getDataFromDB(connection,question):
    cursor = connection.cursor()
    cursor.execute("""SELECT * FROM robot WHERE question = '%s'"""%question)
    results = cursor.fetchall()
    data = [(eve['question'],eve['answer']) for eve in results]
    return data

def getAnswerList(sentence,questions,count=4):
    documents = []
    for eve_sentence in questions:
        tempData = " ".join(jieba.cut(eve_sentence))
        documents.append(tempData)
    texts=[[word for word in document.split()] for document in documents]
    frequency=defaultdict(int)
    for text in texts:
        for word in text:
            frequency[word] =1
    dictionary=corpora.Dictionary(texts)
    new_xs=dictionary.doc2bow(jieba.cut(sentence))
    corpus=[dictionary.doc2bow(text)for text in texts]
    tfidf=models.TfidfModel(corpus)
    featurenum=len(dictionary.token2id.keys())
    sim=similarities.SparseMatrixSimilarity(tfidf[corpus],num_features=featurenum)[tfidf[new_xs]]
    tempList = [(sim[i], questions[i]) for i in range(1,len(questions))]

    tempList.sort(key=lambda x:x[0],reverse=True)
    if len(tempList) >= count:
        return tempList[0:count]
    else:
        return tempList


def putQuestion(question):
    connection = pymysql.connect(host="",
                                     user="",
                                     password="",
                                     port=int(),
                                     db="MyScfTest",
                                     charset='utf8',
                                     cursorclass=pymysql.cursors.DictCursor)
    questions = getAllDataFromDB(connection)
    answers = [getDataFromDB(connection,eve[1]) for eve in getAnswerList(question,questions,count=2)]
    connection.close()
    return answers

sentence = "怎么触发SCF?"
print(putQuestion(sentence))

测试结果:

可以看到,在问题列表:

我们一共有5个问题,这5个问题,和"怎么触发SCF?"相似度最高的问题前两个是:那些事件可以触发SCF函数以及SCF支持那些语言。可以看出,得到的结果是类似的。

这个项目在实际生产中,可以是这样:

你问客服机器人一个问题,机器人给你一个回答,然后下面会说:更多相似问题:巴拉巴拉一堆。

上SCF阶段

函数进行打包,这里要记住,一定要在SCF一样的环境下打包才可以:

CentOS Python3.6

具体打包方法,可以参考文章:https://cloud.tencent.com/developer/article/1443081

打包之后,数据上传:

这里要说明的是,由于函数上传有大小限制,本函数上传了COS,通过COS加载到SCF中,并设置了超时时间为300s:

简单测试,运行结果如下:

代码语言:javascript复制
def main_handler(event, context):
    sentence = "怎么触发SCF?"
    return putQuestion(sentence)

对main_handler进行修改:

首先定义测试模板:

然后修改:

代码语言:javascript复制
def main_handler(event, context):
    sentence = context["question"]
    return putQuestion(sentence)

完整代码(已经删除了我数据库等敏感信息):

代码语言:javascript复制
import jieba,pymysql
from gensim import corpora,models,similarities
from collections import defaultdict

def getAllDataFromDB(connection):
    cursor = connection.cursor()
    cursor.execute("""SELECT * FROM robot""")
    results = cursor.fetchall()
    data = [eve['question'] for eve in results]
    return data

def getDataFromDB(connection,question):
    cursor = connection.cursor()
    cursor.execute("""SELECT * FROM robot WHERE question = '%s'"""%question)
    results = cursor.fetchall()
    data = [(eve['question'],eve['answer']) for eve in results]
    return data

def getAnswerList(sentence,questions,count=4):
    documents = []
    for eve_sentence in questions:
        tempData = " ".join(jieba.cut(eve_sentence))
        documents.append(tempData)
    texts=[[word for word in document.split()] for document in documents]
    frequency=defaultdict(int)
    for text in texts:
        for word in text:
            frequency[word] =1
    dictionary=corpora.Dictionary(texts)
    new_xs=dictionary.doc2bow(jieba.cut(sentence))
    corpus=[dictionary.doc2bow(text)for text in texts]
    tfidf=models.TfidfModel(corpus)
    featurenum=len(dictionary.token2id.keys())
    sim=similarities.SparseMatrixSimilarity(tfidf[corpus],num_features=featurenum)[tfidf[new_xs]]
    tempList = [(sim[i], questions[i]) for i in range(1,len(questions))]

    tempList.sort(key=lambda x:x[0],reverse=True)
    if len(tempList) >= count:
        return tempList[0:count]
    else:
        return tempList


def putQuestion(question):
    connection = pymysql.connect(host="",
                                     user="",
                                     password="",
                                     port=int(),
                                     db="MyScfTest",
                                     charset='utf8',
                                     cursorclass=pymysql.cursors.DictCursor)
    questions = getAllDataFromDB(connection)
    answers = [getDataFromDB(connection,eve[1]) for eve in getAnswerList(question,questions,count=2)]
    connection.close()
    return answers


def main_handler(event, context):
    sentence = context["question"]
    return putQuestion(sentence)

目前,我们的云函数已经部署完成。

云API触发器

有些人对写云API的代码有点一脸懵逼,但是别担心:

https://console.cloud.tencent.com/api/explorer?Product=scf&Version=2018-04-16&Action=Invoke&SignVersion=

云API的Explorer是一个可以自动帮我们写代码的工具,大家可以通过这个工具,进行简答的在线调试:

大家可以看到,选择好了对应的功能,我们填写好对应的参数,通过点击在线调用->发送请求,获得到了结果。

此时我们可以点击代码生成:

我们可以看到系统为我们自动生成了Java、Python等6种语言的代码,这些代码是可以放到项目中直接运行。也就是说,你可以在自己的Node.js,.NET,Java等项目中,调用这个云函数,并且获得结果。

总结

本文是通过一个简单的算法,实现了简单的问答机器人工具。主要涉及到了:

1: 打包函数,可以参考文章中的地址

2:上传代码,可以通过cos上传

3:连接数据库的Demo

4:使用云API触发

当然,SCF的应用场景还有很多,我也会在以后的文章中,更多的和大家分享它的使用场景。

0 人点赞