js-bot 是一个基于 酷 Q Websocket 服务(CoolQ HTTP API 插件)的浏览器端聊天机器人框架及开发工具,用 Typescript + React 开发,你能够在“聊天模式”下与好友/群聊天,也能够在其 “控制台模式” 下输入 Javascript 代码运行或调用 js-bot 及 coolq-http 提供的 api ,并注册消息等事件的响应函数来实现本身的机器人,还能够在“虚拟聊天模式”下用虚拟帐号向机器人发送消息来测试本身编写的机器人,全部这一切均可以在 pandolia.net/js-bot 这一个网页上进行。html
js-bot 控制台模式效果以下:git
聊天模式效果以下:github
用酷 Q 登陆帐号后,启用 cqhttp 插件,以后退出酷 Q ,找到 “data\app\io.github.richardchien.coolqhttpapi\config” 下相应帐号的配置文件,将 websocket 相关的配置修改以下:web
{
"use_ws": true,
"ws_host": "127.0.0.1",
"ws_port": 6700,
"access_token": "mytoken",
}
复制代码
再次登陆,等酷 Q Websocket 服务启动后,用浏览器打开 pandolia.net/js-bot 网址,就可使用 js-bot 尽情的玩耍了,此时用其余帐号给本帐号发送 "-joke",本帐号会自动回复一则笑话。typescript
若是酷 Q Websocket 服务是在其余机器上部署的,能够在 url 参数中指定其地址及 token ,例如:pandolia.net/js-bot/?ws_… 。npm
对于 IE/Edge ,因为浏览器默认禁止 Javascript 代码链接不一样主机的 WebSocket 服务,解决方案为:Internet选项 -> 安全 -> 本地Internet -> 站点,把全部勾选取消。或者下载本项目代码,build 以后将 html 文件部署在本地再访问。json
若是不开启酷 Q Websocket 服务, js-bot 的 “控制台模式” 和 “虚拟聊天” 模式仍然是可使用的,但与 QQ 相关的功能全都不可用。api
控制台模式下,能够直接在输入框输入 Javascript 代码运行,例如:数组
// 打印文本
>>> print('hello')
hello
// 查找帐号为 3497303033 的好友
>>> buddies.get('3497303033')
[ 好友 feng,3497303033 ]
// ans 中保存上一次命令的运行结果
>>> ans
[ 好友 feng,3497303033 ]
// 向好友发送消息 "hello"
>>> ans.send('hello')
null
// 调用 ai.joke() 生成一个笑话
// 注意: ai.joke() 返回的是一个 Promise 对象,js-bot 解释器会
// 等待其 fullfilled ,将结果保存到 ans 中再返回
>>> ai.joke()
中午去存钱,排队时一美女在后面问我:“存钱是吗?”“恩!”“我正好要取
钱,反正你要存,不如把钱给我,咋俩就不用排队了。”我想一想以为有理,
因而把钱给她了!
// 向好友发送笑话
>>> buddies.get('3497303033').send(ans)
null
复制代码
控制台模式下,可以使用 js-bot 提供的内部变量和方法:浏览器
buddies/groups 中保存的是 Contact 对象,具备 type/qq/name 属性和 send 方法,type 为 BUDDY 表示好友,GROUP 表示群,另外 VIRTUAL_BUDDY 表示虚拟好友。
在控制台模式下运行代码,与在浏览器自带的开发者工具的 Devtool-Console 中运行代码,有两点不同:
对于第二点,要注意的是,即使是在控制台模式下,也不能将 ai.joke() 的结果直接传递给 send 方法,而应该这样调用: ai.joke().then(function (t) { buddies.get('3497303033').send(t) })
能够在控制台模式下对 handler.onMessage 和 handler.onCqEvent 进行从新赋值,从而实现本身的聊天机器人,例如:
>>>
handler.onMessage = function (contact, message) {
if (message.content === '-hello') {
contact.send('你好,' + contact.name)
.then(function() {
popModal('发消息成功');
});
}
}
复制代码
在控制台中运行以上代码后,当 本帐号 收到内容为 "-hello" 的消息时,会自动回复: "你好,xx" 。
为了测试本身开发的机器人程序,须要利用其它帐号向本帐号发送消息,这显然很不方便,所以 js-bot 提供 虚拟聊天模式 来快速测试。
在 js-bot 中的 最近 联系人列表内,点击第二个联系人 [ yourname ] ,就进入了虚拟聊天模式,此时,用户扮演 虚拟好友 向本帐号发送消息。在此模式下输入文本并发送时,机器人会收到一条来自 虚拟好友 的消息, handler.onMessage 一样会被调用,此时,contact 的 type 属性为 cq.VIRTUAL_BUDDY , name 属性为 "虚拟好友" 。
例如,对于上一节的 onMessage 函数,在 虚拟聊天 模式下发送 "-hello" ,则机器人会自动回复 "你好,虚拟好友" 。
若是 js-bot 已链接了酷 Q 的 Websocket 服务,那么 js-bot 的普通聊天模式是可用的,能够在页面上点击好友和群,而后进行聊天。
当进入到普通聊天模式时, js-bot 会将页面上的输入框上方的模式信息文本颜色调得更加明显,提醒用户已进入聊天模式,避免发送无关的信息。
若是没有开启酷 Q 的 Websocket 服务,普通聊天模式没法使用,但控制台模式和虚拟聊天模式仍然是可用的。
本项目采用 Typescript + React 开发,能够下载本项目源码,运行 npm install 和 npm start 启动本项目,并按本身的须要进行开发和扩展。建议采用 Vs Code (须要安装 Eslint 和 Tslint 插件)。
开发和扩展 js-bot 时,修改 src/myhandler-ts.ts 文件就能够了,在此文件中导出两个事件函数:
import Contact from './cq/Contact';
import cq from './cq';
export default {
onMessage: async (contact: Contact, message: IMessage) => {
if (message.content !== '-joke') {
return;
}
const joke = await cq.ai.joke();
await contact.send(joke);
cq.popModal('发送笑话成功.');
},
onCqEvent: async (data: any) => {
return;
},
};
复制代码
若是不会 Typescript ,也能够用 Javascript 开发,修改 src/myhandler-js.js 文件就能够了,须要在 src/index.tsx 文件中改成:import handler from './myhandler.js' 。
本项目中的其余文件,建议不要修改,若是确实须要修改,请在 项目 github 主页 上发 issue 或 pull-request 。
好友消息和群消息以外的其余事件会被传递给 onCqEvent 函数,支持的事件列表及各事件的字段说明详见 cqhttp 事件列表 。
在事件函数中,除了发送消息,也能够用 cq.api 方法调用 cqhttp 提供的 api (例如:发送好友赞等),示例以下:
await cq.api('send_like', { user_id: 158297369 });
复制代码
其余 cqhttp-api 见 cqhttp API 列表 ,调用时需注意下面两个问题:
如下列出 js-bot 内部可以使用的常量、变量和方法,禁止直接修改变量,只能经过调用方法来改变 js-bot 的内部状态。
// 联系人类型: 好友/群/无/控制台/本身/虚拟好友
export const BUDDY = 0;
export const GROUP = 1;
export const NOTYPE = 2;
export const CONSOLE = 3;
export const MYSELF = 4;
export const VIRTUAL_BUDDY = 5;
// 消息方向,LEFT 表明消息画在左边,RIGHT 表明消息画在右边
export const LEFT = 0;
export const RIGHT = 1;
// 日志级别
export const DEBUG = 0;
export const INFO = 1;
export const WARN = 2;
export const ERROR = 3;
// 每一个联系人保存的消息总数最大值
export const MAX_MESSAGES_SIZE = 400;
// 环境(在 .env 文件内定义),项目名称, CQ-WEBSOCKET 参数, github 地址
export const PROJECT_NAME: string;
export const DEFAULT_WS_HOST: string;
export const DEFAULT_TOKEN: string;
export const DEFAULT_RECENTS: string;
export const GITHUB_URL: string;
复制代码
// 消息方向 LEFT/RIGHT
type DirectionType = 0 | 1;
// 消息接口( onMessage 的第二个参数为 IMessage 对象)
interface IMessage {
readonly id: string;
readonly direction: DirectionType;
readonly from: string;
readonly content: string;
}
// 联系人类型 BUDDY ~ VIRTUAL_BUDDY
type ContactType = 0 | 1 | 2 | 3 | 4 | 5;
// 日志级别 DEBUG ~ ERROR
type LogLevel = 0 | 1 | 2 | 3;
// 事件处理接口
interface IHandler {
onMessage: (c: Contact, m: Message) => any,
onCqEvent: (data: any) => any,
}
复制代码
class Contact {
// 类型 BUDDY/GROUP/VIRTUAL_BUDDY ,表明 好友/群/虚拟好友
type: ContactType;
// 帐号
qq: string;
// 名称
name: string;
// 向本联系人发送消息,发送成功返回 null ,发送失败则抛出 Error 错误
send = async (text: string): Promise<null> => { /* */ }
}
复制代码
class ContactTable {
// 类型 BUDDY/GROUP/NOTYPE 表明 好友列表/群列表/最近联系人列表
type: ContactType;
// 名称
get name() { /* */ }
// 分别以数组和字典保存全部联系人,请勿访问这两个属性
_list: Contact[] = [];
_dict: Map<string, Contact> = new Map();
// 联系人个数
get length() { return this._list.length; }
// 遍历、查找联系人
map = this._list.map.bind(this._list);
forEach = this._list.forEach.bind(this._list);
filter = this._list.filter.bind(this._list);
find = this._list.find.bind(this._list);
// 查询联系人
// get('3497303033') 返回 qq 为 '3497303033' 的 Contact 对象
// get(0) 返回第一个 Contact 对象
// 对象不存在时返回 undefined
get(qqOrIndex: string | number): Contact | undefined { /* */ }
}
复制代码
// 好友列表/群列表/最近联系人列表
export const buddies = new ContactTable(BUDDY);
export const groups = new ContactTable(GROUP);
export const recents = new ContactTable(NOTYPE);
// 事件处理对象
export let handler: IHandler;
// 控制台上次命令运行结果
export let ans;
// 打印、清屏
export function print(line = '') { /* */ }
export function clr() { /* */ }
// 日志
export let level: LogLevel;
export function setLogLevel(_level: LogLevel) { /* */ }
export function debug(_level: LogLevel, msg: any) { /* */ }
export function info(_level: LogLevel, msg: any) { /* */ }
export function warn(_level: LogLevel, msg: any) { /* */ }
export function error(_level: LogLevel, msg: any) { /* */ }
// 模态对话框
export async function showModal(msg: any) { /* */ } // 展现
export function closeModal() { /* */ } // 关闭
export function popModal(msg: any, t = 2500) { /* */ } // 展现,t 毫秒后关闭
// cqhttp 服务地址及 token
export const ws_host: string;
export const token: string;
// ai (见 src/ai/index.tsx 目前只有 ai.joke )
export const ai;
// api
export function api(action: string, params: any = null): Promise<any> { /* */ }
// 退出并重启 js-bot
export function abort(msg: string) { /* */ }
// 重置 cqhttp 服务地址
export function reset(w = DEFAULT_WS_HOST, t = DEFAULT_TOKEN, r = DEFAULT_RECENTS) { /* */ }
复制代码
感谢 Richard Chien 开发的强大的 coolq-http-api 。