Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ankanch/266fb2936e7ba6aaab315e944827e959 to your computer and use it in GitHub Desktop.
Save ankanch/266fb2936e7ba6aaab315e944827e959 to your computer and use it in GitHub Desktop.
适用于飞书外部群的ChatGPT 机器人 (基于飞书网页版)
/**
* 适用于飞书外部群的ChatGPT 机器人
* 对于飞书内部群,可以直接通过开发飞书机器人实现内部群的消息监听和回复。
* 但对于飞书外部群,无法添加内部机器人程序, 只能添加非常简单的基于Webhook 的机器人 (参考:https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot)
* 机器人无法直接获得外部群的消息。
*
* 本脚本实现,监听飞书网页版外部群消息(HTML元素变化),并将群消息发送给 ChatGPT 处理。
* 使用方法:
* 1. 打开飞书网页版
* 2. 等待网页版加载完成
* 3. 点开一个外部群聊的聊天窗口
* 4. 按 F12 打开浏览器控制台
* 5. 控制台粘贴本代码,并回车
* 6. 群里的其他人可以通过发送 "+GPT {你的问题}" 以选择ChatGPT回复该消息
*
* 已知问题:某些情况下可能需要用户手动在网页版往下滑下消息,以便脚本检测到新消息。
*
* 仅实现了单次对话,无上下文。
*
* 你需要获取OpenAI 的API key 和 飞书外部群机器人webhook 链接以使用本脚本。
*/
console.log('飞书网页版消息');
// ChatGPT API配置
const apiEndpoint = 'https://api.openai.com/v1/chat/completions';
// ==============================================================================================
// ========================== 请在下面填入你的 OpenAI API Key ==========================
// ==============================================================================================
const apiKey = '{your chat gpt api key}';
// 示例 : https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxx
// 如何获取以上链接,请参考 https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot
const feishuGroupBotEndpoint = "{your feishu group webhook URL}";
// ==============================================================================================
// ===================== 请在上面填入你的 飞书外部群机器人webhook地址 ==========================
// ==============================================================================================
// 发送消息给ChatGPT
async function sendMessage(message) {
try {
const response = await fetch(apiEndpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-3.5-turbo',
messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: message }]
})
});
const data = await response.json();
const reply = data.choices[0].message.content;
return reply;
} catch (error) {
console.error('API请求错误:', error);
return '发生错误,请重试。';
}
}
// 发送消息给飞书群
async function sendMessageToFeishu(message) {
try {
const response = await fetch(feishuGroupBotEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
msg_type: 'text',
content: {
text: message
}
})
});
return "";
} catch (error) {
console.error('sendMessageToFeishu API请求错误:', error);
return 'sendMessageToFeishu 发生错误,请重试。';
}
}
// 设置要监控的CSS选择器
var selector = "#root-messenger-nav-application > div > div > div.lark-chat-right-box.js-lark-chat-right-box > div.lark-chat-right > div > div > div > div > div.chatSidebar_content > div > div.chatMainContent > div.bizChat > div.chatMessages > div.messageContainer._2AC2c > div.messageList > div > div > div > div.list_items";
// 获取目标元素
var targetElement = document.querySelector(selector);
// 定义MutationObserver回调函数
var observerCallback = function (mutationsList, observer) {
for (var mutation of mutationsList) {
if (mutation.type === "childList") {
var addedNodes = mutation.addedNodes;
for (var i = 0; i < addedNodes.length; i++) {
var addedNode = addedNodes[i];
console.log("新增内容:", addedNode.innerHTML);
var messageTextDiv = addedNode.querySelector('.message-text');
var textContent = messageTextDiv.textContent.trim();
if (textContent.endsWith('展开')) {
textContent = textContent.slice(0, -2);
console.log('移除后的字符串:', textContent);
}
if (!textContent.startsWith('+GPT')) {
console.log('忽略输入,请使用 +GTP 开头 : ',textContent);
return;
}
textContent = textContent.replace(/^(\+GPT\s*)+/, '');
console.log('SEND--->:', textContent);
sendMessage(textContent)
.then(reply => {
console.log('<---RECV:', reply);
sendMessageToFeishu(reply);
})
.catch(error => {
console.error('发生错误:', error);
});
}
}
}
};
// 创建MutationObserver实例
var observer = new MutationObserver(observerCallback);
// 配置MutationObserver
var observerConfig = { childList: true, subtree: true };
// 开始监控目标元素的变化
observer.observe(targetElement, observerConfig);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment