├── .gitignore ├── README.md ├── app ├── app.js ├── mygpt.js ├── plugins │ └── chatgpt │ │ └── chatgpt.js └── sdk │ ├── LQSdk.js │ ├── db.js │ ├── http.js │ └── utils.js └── image └── README ├── 1680791845855.png ├── 1680791925956.png └── 1682393194800.png /.gitignore: -------------------------------------------------------------------------------- 1 | ### VisualStudioCode template 2 | .vscode/* 3 | !.vscode/settings.json 4 | !.vscode/tasks.json 5 | !.vscode/launch.json 6 | !.vscode/extensions.json 7 | !.vscode/*.code-snippets 8 | 9 | # Local History for Visual Studio Code 10 | .history/ 11 | 12 | # Built Visual Studio Code Extensions 13 | *.vsix 14 | 15 | ### JetBrains template 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 17 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 18 | 19 | # User-specific stuff 20 | .idea/**/workspace.xml 21 | .idea/**/tasks.xml 22 | .idea/**/usage.statistics.xml 23 | .idea/**/dictionaries 24 | .idea/**/shelf 25 | 26 | # AWS User-specific 27 | .idea/**/aws.xml 28 | 29 | # Generated files 30 | .idea/**/contentModel.xml 31 | 32 | # Sensitive or high-churn files 33 | .idea/**/dataSources/ 34 | .idea/**/dataSources.ids 35 | .idea/**/dataSources.local.xml 36 | .idea/**/sqlDataSources.xml 37 | .idea/**/dynamic.xml 38 | .idea/**/uiDesigner.xml 39 | .idea/**/dbnavigator.xml 40 | 41 | # Gradle 42 | .idea/**/gradle.xml 43 | .idea/**/libraries 44 | 45 | # Gradle and Maven with auto-import 46 | # When using Gradle or Maven with auto-import, you should exclude module files, 47 | # since they will be recreated, and may cause churn. Uncomment if using 48 | # auto-import. 49 | # .idea/artifacts 50 | # .idea/compiler.xml 51 | # .idea/jarRepositories.xml 52 | # .idea/modules.xml 53 | # .idea/*.iml 54 | # .idea/modules 55 | # *.iml 56 | # *.ipr 57 | 58 | # CMake 59 | cmake-build-*/ 60 | 61 | # Mongo Explorer plugin 62 | .idea/**/mongoSettings.xml 63 | 64 | # File-based project format 65 | *.iws 66 | 67 | # IntelliJ 68 | out/ 69 | 70 | # mpeltonen/sbt-idea plugin 71 | .idea_modules/ 72 | 73 | # JIRA plugin 74 | atlassian-ide-plugin.xml 75 | 76 | # Cursive Clojure plugin 77 | .idea/replstate.xml 78 | 79 | # SonarLint plugin 80 | .idea/sonarlint/ 81 | 82 | # Crashlytics plugin (for Android Studio and IntelliJ) 83 | com_crashlytics_export_strings.xml 84 | crashlytics.properties 85 | crashlytics-build.properties 86 | fabric.properties 87 | 88 | # Editor-based Rest Client 89 | .idea/httpRequests 90 | 91 | # Android studio 3.1+ serialized cache file 92 | .idea/caches/build_file_checksums.ser 93 | 94 | /.idea/ 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LemonQQ 2 | Protocol Robot Based on NTQQ 3 | 4 | ## 教程 5 | 6 | ![1680791925956](image/README/1680791925956.png) 7 | 8 | ## demo 9 | 10 | ![1680791845855](image/README/1680791845855.png) 11 | 12 | ## 一个简单的GPT插件例子 13 | 14 | ![1682393194800](image/README/1682393194800.png) 15 | 16 | ## 频道 17 | 18 | TG:https://t.me/LemonQQBot 19 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | //// 以下是go语言调用js的函数 请勿更改函数名 入参 不需要的事件可以删除 需保留核心函数 AppInfo 3 | /////////////////////////////////////////////////////////////////////// 4 | //这是一个简单的NTQQ插件开发demo 5 | const LQ = require('./sdk/LQSdk') 6 | const http = require('./sdk/http') 7 | const db = require('./sdk/db') 8 | const { sleep } = require('./sdk/utils'); 9 | 10 | //这是一个 插件信息模板 如果你想写插件 请把文件名改成自定义的 不建议和我们提供的的同名为app.js 11 | 12 | function AppInfo() { 13 | return { 14 | apiVer: 1, //不应修改 15 | appId: 'com.lemon.demo', //应用ID 唯一 建议用域名反写 16 | name: 'DemoApp', //需要改 尽量唯一 17 | ver: '1.0.1', //版本号 18 | authkey: '', //开发者id 预留 19 | author: 'Lemon',//作者 20 | description: 'TG:https://t.me/LemonQQBot', //插件释义 21 | } 22 | } 23 | 24 | //收到新的聊天消息 不需要可删除 25 | function _eventRecvMsg(newMsg) { 26 | console.log('收到新的消息 这是Js打印的数据>>> ', newMsg) 27 | let msgObj = JSON.parse(newMsg) 28 | //不处理自己发的消息 29 | if (msgObj.selfid == msgObj.fromqq) { 30 | return 1 31 | } 32 | //'🐱 🐭 🐹 🐰 🦊 🦝 🐼 ' 特殊表情直接发送 33 | if (msgObj.fromgroup == 123456789) { 34 | sleep(1000) 35 | let ret = LQ.SendGroupMessage(msgObj.selfid, msgObj.fromgroup, msgObj.content, false) 36 | console.log('打印发送返回值>> ', ret) 37 | } 38 | return 0 39 | } 40 | 41 | //收到全量的消息 自行解析 不需要可删除 42 | function _eventTipsMsg(newMsg) { 43 | //var msgObj = JSON.parse(newMsg) 44 | console.log('_eventTipsMsg 这是Js打印的数据>>> ', newMsg) 45 | return 0 46 | } 47 | 48 | ////////////////////////////////////////////////// 49 | //以下是自定义的函数 50 | ///////////////////////////////////////////////// 51 | 52 | 53 | //这个是一个简单的HTTPdemo 调用go的高性能请求池去操作 54 | function demohttp() { 55 | const headers = { 56 | 'User-Agent': 57 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 58 | 'Content-Type': 'application/json', 59 | } 60 | 61 | const cookies = { 62 | cookie1: 'value1', 63 | cookie2: 'value2', 64 | } 65 | const proxyUrl = "http://127.0.0.1:7890" 66 | const body = JSON.stringify({ key: 'value' }) 67 | const timeout = 10 68 | const response = http.get('http://baidu.com/', headers, cookies, body, timeout, proxyUrl) 69 | console.log(response) 70 | } 71 | 72 | //这是一个数据库使用的demo 73 | function demodb() { 74 | console.log(db.get("testkey001")) 75 | console.log(db.has("testkey001")) 76 | console.log(db.put("testkey001", "这是存放的数据")) 77 | console.log(db.put("testkey002", "这是存放的数据2")) 78 | console.log(db.delete("testkey001")) 79 | console.log(db.get("testkey001")) 80 | console.log(db.get("testkey002")) 81 | } -------------------------------------------------------------------------------- /app/mygpt.js: -------------------------------------------------------------------------------- 1 | const ChatGPT = require("./plugins/chatgpt/chatgpt"); 2 | 3 | let chat = new ChatGPT({ 4 | // PROXY_URL: 'http://127.0.0.1:7890', 5 | API_SECRET: '',//GPTKey 6 | QQ_GROUP: []//监听群号 7 | }); 8 | 9 | function AppInfo() { 10 | return { 11 | apiVer: 1, //不应修改 12 | appId: 'com.lemon.gpt', //应用ID 唯一 建议用域名反写 13 | name: 'GPT聊天', 14 | ver: '1.0.1', 15 | authkey: '', 16 | author: '青', 17 | description: 'TG:https://t.me/LemonQQBot', 18 | } 19 | } 20 | 21 | function _eventRecvMsg(newMsg) { 22 | let msgObj = JSON.parse(newMsg) 23 | if (msgObj.selfid === msgObj.fromqq) { 24 | return 1 25 | } 26 | chat.qqGroupChat(msgObj); 27 | return 0 28 | } 29 | 30 | -------------------------------------------------------------------------------- /app/plugins/chatgpt/chatgpt.js: -------------------------------------------------------------------------------- 1 | const LQ = require('../../sdk/LQSdk') 2 | const http = require('../../sdk/http') 3 | 4 | 5 | class ChatGPT { 6 | defaultConfig = { 7 | PROXY_URL: null, 8 | API_SECRET: '', 9 | QQ_GROUP: [], 10 | GPT_TIMEOUT: 60, // 单位:s 11 | } 12 | constructor(config) { 13 | this.config = { ...(this.defaultConfig), ...config }; 14 | console.log('config: ' + JSON.stringify(this.config)); 15 | } 16 | 17 | qqGroupChat = (msgObj) => { 18 | if (this.config.QQ_GROUP.indexOf(Number.parseInt(msgObj.fromgroup)) !== -1) { 19 | let content = msgObj.content; 20 | if (content === undefined) { 21 | return; 22 | } 23 | console.log('content ==> ' + content); 24 | let atString = `[LQ:@${msgObj.selfid}]`; 25 | if (content.startsWith(atString)) { 26 | content = content.substring(atString.length + 1, content.length).trim(); 27 | console.log('prompt ==> ' + content) 28 | try { 29 | if (content.length > 1) { 30 | this.chat(content, (msg) => { 31 | let ret = LQ.SendGroupMessage(msgObj.selfid, msgObj.fromgroup, msg, false); 32 | console.log('QQ Send Result <== ', ret) 33 | }) 34 | } 35 | } catch (e) { 36 | try { 37 | let message = e.message.toString(); 38 | if (message.includes('Timeout')) { 39 | let ret = LQ.SendGroupMessage(msgObj.selfid, msgObj.fromgroup, '访问GPT超时', false); 40 | console.log('QQ Send Result <== ', ret) 41 | } else { 42 | let ret = LQ.SendGroupMessage(msgObj.selfid, msgObj.fromgroup, '访问GPT错误', false); 43 | console.log('QQ Send Result <== ', ret); 44 | } 45 | } catch (e) { 46 | console.error('error', e); 47 | 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | chat = (content, fun) => { 55 | let headers = { 56 | 'Content-Type': 'application/json', 57 | 'Authorization': `Bearer ${this.config.API_SECRET}` 58 | }; 59 | let body = JSON.stringify({ 60 | "model": "gpt-3.5-turbo", 61 | "messages": [ 62 | { 63 | "role": "user", 64 | "content": content 65 | } 66 | ] 67 | }); 68 | console.log('ChatGPT Request ==> ' + content); 69 | const response = http.post('https://api.openai.com/v1/chat/completions', headers, {}, body, this.config.GPT_TIMEOUT, this.config.PROXY_URL) 70 | let data = JSON.parse(response); 71 | if (data.error !== undefined) { 72 | console.error('ChatGPT Response <== ' + response) 73 | fun('GPT响应错误') 74 | } 75 | let message = data.choices[0].message.content; 76 | console.log('ChatGPT Response <== ' + message) 77 | fun(message) 78 | } 79 | } 80 | 81 | module.exports = ChatGPT -------------------------------------------------------------------------------- /app/sdk/LQSdk.js: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | //// 以下是js调用go语言的核心API 这是提供的sdk 不要随意修改 version 1 3 | /////////////////////////////////////////////////////////////////////// 4 | 5 | //待完善 6 | 7 | class LQ { 8 | //发送群消息 9 | SendGroupMessage(quin, group, content, autoEscape) { 10 | let ret = LQSendGroupMessage(quin, group, content, autoEscape) 11 | return ret 12 | } 13 | } 14 | 15 | module.exports = new LQ(); -------------------------------------------------------------------------------- /app/sdk/db.js: -------------------------------------------------------------------------------- 1 | // 本地数据库的增删改查 2 | // 由于转换原因 所有key value 都是string类型 3 | class MyLeveldb { 4 | put(key, value) { 5 | return MyDB_Put(key, value) 6 | } 7 | 8 | get(key) { 9 | return MyDB_Get(key) 10 | } 11 | 12 | delete(key) { 13 | return MyDB_Delete(key) 14 | } 15 | 16 | has(key) { 17 | return MyDB_Has(key) 18 | } 19 | } 20 | 21 | module.exports = new MyLeveldb(); -------------------------------------------------------------------------------- /app/sdk/http.js: -------------------------------------------------------------------------------- 1 | // http 请求操作 2 | class Http { 3 | request(method, url, headers = {}, cookies = {}, body = null, timeout = 10, proxyUrl = null) { 4 | return jsHttp(url, method, headers, cookies, body, timeout, proxyUrl); 5 | } 6 | 7 | get(url, headers = {}, cookies = {}, body = null, timeout = 10, proxyUrl = null) { 8 | return this.request("GET", url, headers, cookies, body, timeout, proxyUrl); 9 | } 10 | 11 | post(url, headers = {}, cookies = {}, body = null, timeout = 10, proxyUrl = null) { 12 | return this.request("POST", url, headers, cookies, body, timeout, proxyUrl); 13 | } 14 | } 15 | 16 | module.exports = new Http(); 17 | -------------------------------------------------------------------------------- /app/sdk/utils.js: -------------------------------------------------------------------------------- 1 | // 懒得没写 等待叭 需要的功能Tg 留言 2 | 3 | function sleep(s) { 4 | jsSleep(s) 5 | } 6 | 7 | 8 | module.exports = { 9 | sleep 10 | } -------------------------------------------------------------------------------- /image/README/1680791845855.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnxiangLemon/LemonQQ/71885981d0bbaa54a28387bb346daa15f5433b59/image/README/1680791845855.png -------------------------------------------------------------------------------- /image/README/1680791925956.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnxiangLemon/LemonQQ/71885981d0bbaa54a28387bb346daa15f5433b59/image/README/1680791925956.png -------------------------------------------------------------------------------- /image/README/1682393194800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnxiangLemon/LemonQQ/71885981d0bbaa54a28387bb346daa15f5433b59/image/README/1682393194800.png --------------------------------------------------------------------------------