Python对接腾讯“智能闲聊”实现一个聊天机器人

最近在使用腾讯语音合成时发现了一个有趣的东西:智能闲聊html

好奇之下点了进去,发现是一个智能聊天的功能。而后就顺势根据这个api写了一个简单的聊天机器人。python

好了,废话很少说,下面来一步一步实现聊天机器人git

1:在腾讯ai开放平台建立一个应用。

2:得到该应用的app_id和app_key

3:分析开发文档

开发文档地址:https://ai.qq.com/doc/nlpchat.shtmlgithub

能够看到,要实现这个功能,须要访问以下的地址来请求数据:算法

https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat

而要访问这个地址得到数据还须要携带一些参数,才能得到想要的结果。以下:json

app_id:应用的标识,刚才已经复制过。必须是 int 类型的api

time_stamp:时间戳,这个参数须要实时获取。后边代码里能够实现。(int类型)session

nonce_str:随机的字符串,用来保证签名(sign)不被预测。代码里会实现。app

sign:每次请求的签名。须要根据官方提供的算法进行计算得到。dom

session:会话标识。(具体从哪得到这个不太清楚,可是我随便写的10000能够用)。

question:你的问题。(最长不能超过100个汉字,(utf8编码格式下一个汉字占3个字节))。

 

关于签名(sign)的计算方法,能够看到官方文档提供的算法以下:

官方文档写的比较模糊,关于这个算法具体的分析能够看个人另外一篇博客:

         https://blog.csdn.net/hungpangzi/article/details/84334325

这里再也不赘述。

关于这个得到数据的http请求还有一些限制:

4:根据开发文档写代码

<1>:首先定义一个基础类(由于腾讯ai开放平台的不少api的调用方式都差很少,只是参数略有不一样。所以该类的做用就是将这些共同的代码写出来,预留出的接口能够供不一样的功能使用。)

class BaseClass:
    def __init__(self, url):
        """
        :param url:api的访问地址
        """
        self.URL = url;
        self.APP_ID = 000000000000; # 你本身的app_id
        self.APP_KEY = "xxxxxxxxx"; # 你本身的app_key

        # params属性须要用户后来修改,添加对应api所需的参数
        # 这里列举出的参数都是共有的,特有的参数须要用户本身传入
        self.params = {
            'app_id' : self.APP_ID,
            'time_stamp' : None,
            'nonce_str' : None,
        };

        # 调用接口返回的结果
        self.result = None;


    def __get_sign(self):
        """
        计算得到sign的方法
        :return:None
        """
        # 得到时间戳(秒级),防止请求重放
        time_stamp = int(time.time());

        # 得到随机字符串,保证签名不被预测
        nonce_str = ''.join(random.sample(string.ascii_letters + string.digits, 10))

        # 组合参数(缺乏sign,其值要根据如下得到)
        self.params['time_stamp'] = time_stamp;
        self.params['nonce_str'] = nonce_str;

        # 计算得到sign的值
        before_sign = '';
        # 对key排序拼接
        for key in sorted(self.params):
            before_sign += f'{key}={quote(str(self.params[key]).encode("utf-8"))}&';

        # 将应用秘钥以app_key为键名,拼接到before_sign的末尾
        before_sign += f"app_key={self.APP_KEY}";

        # 对得到的before_sign进行MD5加密(结果大写),获得借口请求签名
        sign = hashlib.md5(before_sign.encode("utf-8")).hexdigest().upper();

        # 将请求签名添加进参数字典
        self.params["sign"] = sign;


    def get_result(self):
        """
        该方法用于调用api,得到返回的结果
        :return: None
        """
        # 完善params参数,将sign添加进参数字典
        self.__get_sign();

        params = urllib.parse.urlencode(self.params).encode("utf-8");
        req = request.Request(url=self.URL, data=params);

        # 设置超时10秒,重试3次
        count = 0;
        while True:
            try:
                count += 1;
                self.result = request.urlopen(req, timeout=10);
                break;
            except Exception as e:
                print(e)
                print(f"链接超时,正在进行第{str(count)}次重连")
                if count <= 3:
                    continue;
                else:
                    break;

    def do_result(self):
        """
        处理结果的方法
        :return: None
        """
        pass;

    
    def run(self):
        """
        主运行方法
        :return: None
        """
        pass;

<2>:实现智能闲聊功能。(定义TencentChat类继承上边的基类)

class TencetChat(BaseClass):
    def __init__(self, question):
        """
        :param question: 聊天的问题
        """
        super(TencetChat, self).__init__("https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat");
        self.params["session"] = "10000" # 这个是我随便写的,可使用。
        self.question = question;


    def deal_question(self):
        """
        对提出的问题进行处理,限制长度和类型
        :return: None
        """
        if not isinstance(self.question, str):
            raise TypeError(f"question参数必须是 ‘str’ 类型的,不能是 ‘{type(self.question)}’ 类型的!!!");
        else:
            if len(self.question.encode("utf-8")) > 300:
                raise ValueError("question参数的长度必须小于300个字节(utf-8格式下)")
            else:
                self.params["question"] = self.question;
                self.do_result();


    def do_result(self):
        """
        处理结果
        :return:None
        """
        self.get_result();
        if self.result:
            res = json.loads(self.result.read().decode("utf-8"));
        # print(res)
            if not res["msg"] == "ok":
                self.answer = "我好像出错了:"+res["msg"];
            else:
                self.answer = res["data"]["answer"];
        else:
            self.answer="我尝试了4次,但仍是失败了,只能说我尽力了。";

    def run(self):
        """
        运行方法
        :return:None
        """
        self.deal_question();


if __name__ == '__main__':
    chat = TencentChat("你好");
    chat.run();
    print("智能闲聊:"+chat.answer);

<3>:为了方便的使用,能够实现一个方法,用来持久化对话,代码以下:

# 整合以后的一个聊天程序
def complete_chat():
    """
    一个完整的聊天的方法
    :return: None
    """
    print("欢迎使用智能闲聊,下面开始聊天吧(输入quit退出聊天):")
    print("*"*50)
    while True:
        question = input("我:");
        if question == "quit":
            break;
        t_chat = TencetChat(question);
        t_chat.run();
        answer = t_chat.answer;
        print("智能闲聊:",answer);


if __name__ == '__main__':
    complete_chat();

一个简单的聊天程序就实现了。

以上代码能够直接复制粘贴使用。

完整代码可到个人GitHub获取:https://github.com/shyorange/InterestingProgram

=================转载请注明出处=============================================