基于酷Q开发的QQ聊天机器人 接入腾讯AI开放平台需要计算资源较好以及网络条件较好,不然延迟太大,不能支持高频率聊天或者高并发聊天。
安装酷Q 酷Q 机器人是一款比较成熟的QQ机器人,建议开一个QQ小号玩~ 安装完直接打开,登录小号,配置应用,可以先走一遍互动式教程,非常容易上手。 酷Q的图灵机器人需要另外申请,最可恨的是实名制之后每天也就100次的调用次数(即聊天回复累积多于100条时就GG),限制太死。
插件开发: C++ SDK C++ SDK的配置 首先下载/克隆项目,安装Visual Studio 2019 直接用VS 2019打开 awesome-bot 文件夹,VS 将会自动进行 CMake 配置,产生的 build 目录在 out 中,点击菜单栏的「生成」-「全部生成」即可构建,产生的 app.dll 和 app_dev.exe 文件在 out/build/config/ 中。
编译插件 用VS 2019的x86-Release模式生成即可
集成到酷Q 打开酷Q的开发模式 然后将awesome-bot中的app.json和awesome-bot/build中的app.dll一同放进酷Q目录的dev/com.example.demo目录(需手动创建)中 再重启酷Q或重载应用即可在应用管理中看到demo应用,启用即可。
SDK自带了一个demo,私聊是一个复读机:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 on_private_message([](const PrivateMessageEvent &e) { try { auto msgid = send_private_message(e.user_id, e.message); logging::info_success("私聊" , "私聊消息复读完成, 消息 Id: " + to_string(msgid)); send_message(e.target, MessageSegment::face(111 ) + "这是通过 message 模块构造的消息~" ); } catch (ApiError &e) { logging::warning("私聊" , "私聊消息复读失败, 错误码: " + to_string(e.code)); } }); ``` ## 接入腾讯AI开放平台 复读机有点太蠢了,考虑用一下现成的AI 腾讯AI开放平台有一个[智能闲聊](https: 调用智能闲聊的API需要HTTP通信和json解析 ### [jsoncpp](https: 最新版的安装方法如下(需要cmake): ```bash cd json-master cmake.exe CMakeList.txt ``` ---|--- 得到VS工程文件`ALL_BUILD.vcxproj`,打开编译即可。 但这里遇到一个问题,酷Q插件要求必须是x86的PE,但是最新版jsoncpp似乎不支持x86了。 下载jsoncpp 0.5 .0 版,打开解决方案jsoncpp-src-0.5 .0 /makefiles/vs71/jsoncpp.sln(vs71即VS2003,高版本VS默认转换即可) 编译release版时,注意修改生成静态库文件的工程的属性:菜单 - 项目 - 属性 - 配置属性 - C/C++ - 输出文件 - 汇编程序输出 改为 无列表 ### jsoncpp的使用 VS中新建一个win32控制台工程,项目属性配置如下: * C/C++ - 附加包含目录 设为jsoncpp源码的include目录,例如jsoncpp-src-0.5 .0 /include/json,或者直接将这个文件夹复制到cpp文件目录下 * C/C++ - 代码生成 - 运行库和jsoncpp编译时保持一致 * 链接器 - 常规 - 附加库目录 添加jsoncpp工程编译出的静态库所在的目录 * 链接器 - 输入 - 附加依赖项 添加jsoncpp工程编译出的静态库的文件名 编写源代码时,引用方法如下: ```C++ #include <iostream> #include <fstream> #include "json/json.h" using namespace std ; int main() { Json::Value value1; value1["key" ] = "value" ; ``` ### HTTP通信 C++的HTTP通信比较麻烦,可以借助libcurl实现 -> Visual Studio 2017 /2019 的libcurl[编译](https: * 这里碰到一个bug,jsoncpp和libcurl分别编译都能通过,但是放到同一个项目里面的时候不兼容,MT/MD的问题,后来干脆都不用 * 根据腾讯AI开放平台的[通信协议](https: * 计算完sign之后把参数字典做url编码(即实现一下PHP的`http_build_query()`函数),写到文件`CQ_question`用Python处理通信,C++和Python用文件交互即可 ```python def get_content(): url = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat" f = open("CQ_question" ,"r" ,encoding="utf-8" ) question = f.readlines()[0 ] f.close() r = requests.post(url,data=question) return r.json()["data" ]["answer" ] f1 = open("CQ_answer" ,"w" ,encoding="utf-8" ) f1.write(answer) f1.close()
计算sign的过程中用到了md5 和url编码 C++的字典用map实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 map <string , string > paras; paras["app_id" ] = "xxxxxxx" ; paras["time_stamp" ] = to_string(time(0 )); paras["nonce_str" ] = randstr(); paras["session" ] = "10000" ; paras["question" ] = "111" ; map<string, string> getSign(map<string,string> paras, string appkey) { string before_md5 = "" ; Encoder encoder; for (auto iter = paras.begin(); iter != paras.end();iter++) { cout << iter->first << ":" << iter->second << endl ; before_md5 += iter->first + "=" + encoder.UTF8UrlEncode(iter->second) + "&" ; } before_md5 += "app_key=" + appkey; cout << before_md5 << endl ; MD5 sign; sign.update(before_md5); string upper_sign = sign.toString(); transform(upper_sign.begin(), upper_sign.end(), upper_sign.begin(), ::toupper ); paras["sign" ] = upper_sign; cout << upper_sign << endl ; return paras; } string appkey = "xxxxxx" ; paras = getSign(paras,appkey); Encoder encoder; string http_query = "" ; for (auto iter = paras.begin(); iter != paras.end(); iter++) { cout << iter->first << ":" << iter->second << endl ; http_query += iter->first + "=" + encoder.UTF8UrlEncode(iter->second) + "&" ; } http_query.pop_back(); ofile.open("CQ_question" , ios::out); ofile << "question" << endl ; ofile.close(); system("python CQ.py" ); ifstream ifs; string buf="" ; _sleep(1000 ); do { ifs.open("CQ_answer" , ios::in); getline(ifs, buf); if (buf.size() > 1 ) { logging::info_success("腾讯AI" , "收到消息: " + buf); break ; } } while (true ); send_message(e.target, MessageSegment::face(111 ) + buf);