diff --git a/bots/config.example.json b/bots/config.example.json index 57e8497..bbcf314 100644 --- a/bots/config.example.json +++ b/bots/config.example.json @@ -27,7 +27,10 @@ { "label": "DOWNLOAD", "threshold": 0.85, - "text": "the download?" + "reply": { + "title": "download??", + "desc": "the download?" + } } ] } diff --git a/bots/discord/events/discord/messageCreate.js b/bots/discord/events/discord/messageCreate.js index 3b0f5e0..56bd410 100644 --- a/bots/discord/events/discord/messageCreate.js +++ b/bots/discord/events/discord/messageCreate.js @@ -5,6 +5,9 @@ export default { once: false, execute(helper, _, msg) { if (!msg.content || msg.author.bot) return; - helper.scanText(msg.content.toLowerCase().replace(/<.*?>/g, ''), `${msg.channelId}/${msg.id}`); + helper.scanText( + msg.content.toLowerCase().replace(/<.*?>/g, ''), + `${msg.channelId}/${msg.id}` + ); } }; diff --git a/bots/discord/events/helper/aiResponse.js b/bots/discord/events/helper/aiResponse.js index f6af4cd..b60d6fc 100644 --- a/bots/discord/events/helper/aiResponse.js +++ b/bots/discord/events/helper/aiResponse.js @@ -23,19 +23,26 @@ export default { message = channel.messages.cache.get(ids[1]); } - const intent = aiRes.response.reduce((a, b) => a.confidence > b.confidence ? a : b); - const response = config.responses.find((res) => res.label === intent.name); + const intent = aiRes.response.reduce((a, b) => + a.confidence > b.confidence ? a : b + ); + const response = config.responses.find( + (res) => res.label === intent.name + ); if (response.threshold > intent.confidence) return; - - const embed = new EmbedBuilder() - .setTitle('You have asked a Frequently Asked Question') - .setDescription(response.text) - .setFooter({ text: `Confidence: ${intent.confidence}` }); + if (!response.reply) return; - message.reply({ embeds: [embed]}); + const embed = new EmbedBuilder() + .setTitle(response.reply.title) + .setDescription(response.reply.desc) + .setColor(14908858) + .setFooter({ text: `Confidence: ${intent.confidence}` }); + + message.reply({ embeds: [embed] }); return; - } catch (e) {console.log(e)} - + } catch (e) { + console.log(e); + } } }; diff --git a/bots/discord/index.js b/bots/discord/index.js index d01b845..2375008 100644 --- a/bots/discord/index.js +++ b/bots/discord/index.js @@ -8,75 +8,78 @@ const __dirname = dirname(__filename); import HelperClient from '../../client/index.js'; export default async () => { -const config = JSON.parse(readFileSync('./config.json', 'utf-8')); + const config = JSON.parse(readFileSync('./config.json', 'utf-8')); -const helper = new HelperClient(config); + const helper = new HelperClient(config); -helper.connect(); + helper.connect(); -const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent - ] -}); + const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent + ] + }); -client.commands = new Collection(); + client.commands = new Collection(); -const commandsPath = join(__dirname, 'commands'); -const commandFiles = readdirSync(commandsPath).filter((file) => - file.endsWith('.js') -); + const commandsPath = join(__dirname, 'commands'); + const commandFiles = readdirSync(commandsPath).filter((file) => + file.endsWith('.js') + ); -for (const file of commandFiles) { - const filePath = join(commandsPath, file); - const command = (await import(`file://${filePath}`)).default; - if ('data' in command && 'execute' in command) { - client.commands.set(command.data.name, command); - } else { - console.log( - `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.` - ); + for (const file of commandFiles) { + const filePath = join(commandsPath, file); + const command = (await import(`file://${filePath}`)).default; + if ('data' in command && 'execute' in command) { + client.commands.set(command.data.name, command); + } else { + console.log( + `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.` + ); + } } -} -const discordEventsPath = join(__dirname, 'events/discord'); -const discordEventFiles = readdirSync(discordEventsPath).filter((file) => - file.endsWith('.js') -); + const discordEventsPath = join(__dirname, 'events/discord'); + const discordEventFiles = readdirSync(discordEventsPath).filter((file) => + file.endsWith('.js') + ); -for (const file of discordEventFiles) { - const filePath = join(discordEventsPath, file); - const event = (await import(`file://${filePath}`)).default; - if (event.once) { - client.once(event.name, (...args) => - event.execute(helper, config, ...args) - ); - } else { - client.on(event.name, (...args) => event.execute(helper, config, ...args)); + for (const file of discordEventFiles) { + const filePath = join(discordEventsPath, file); + const event = (await import(`file://${filePath}`)).default; + if (event.once) { + client.once(event.name, (...args) => + event.execute(helper, config, ...args) + ); + } else { + client.on(event.name, (...args) => + event.execute(helper, config, ...args) + ); + } } -} -// The ReVanced Helper events. + // The ReVanced Helper events. -const helperEventsPath = join(__dirname, 'events/helper'); -const helperEventFiles = readdirSync(helperEventsPath).filter((file) => - file.endsWith('.js') -); + const helperEventsPath = join(__dirname, 'events/helper'); + const helperEventFiles = readdirSync(helperEventsPath).filter((file) => + file.endsWith('.js') + ); -for (const file of helperEventFiles) { - const filePath = join(helperEventsPath, file); - const event = (await import(`file://${filePath}`)).default; - if (event.once) { - helper.once(event.name, (...args) => - event.execute(client, config, ...args) - ); - } else { - helper.on(event.name, (...args) => event.execute(client, config, ...args)); + for (const file of helperEventFiles) { + const filePath = join(helperEventsPath, file); + const event = (await import(`file://${filePath}`)).default; + if (event.once) { + helper.once(event.name, (...args) => + event.execute(client, config, ...args) + ); + } else { + helper.on(event.name, (...args) => + event.execute(client, config, ...args) + ); + } } -} -client.login(config.discord.token); - -} \ No newline at end of file + client.login(config.discord.token); +}; diff --git a/bots/index.js b/bots/index.js index e26770a..65b1d94 100644 --- a/bots/index.js +++ b/bots/index.js @@ -1,13 +1,13 @@ import { readdirSync } from 'node:fs'; const botFolders = readdirSync('./', { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .map(dirent => dirent.name); + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent.name); const runBotOnly = process.argv[2] ? process.argv[2] : null; for (const botFolder of botFolders) { - if (botFolder === 'node_modules') continue; - if (runBotOnly && runBotOnly !== botFolder) continue; - const botIndex = await import(`./${botFolder}/index.js`); - botIndex.default(); -} \ No newline at end of file + if (botFolder === 'node_modules') continue; + if (runBotOnly && runBotOnly !== botFolder) continue; + const botIndex = await import(`./${botFolder}/index.js`); + botIndex.default(); +} diff --git a/bots/reddit/events/helper/aiResponse.js b/bots/reddit/events/helper/aiResponse.js index 419277d..3075e87 100644 --- a/bots/reddit/events/helper/aiResponse.js +++ b/bots/reddit/events/helper/aiResponse.js @@ -6,23 +6,33 @@ export default { if (!aiRes.response[0]) return; const ids = aiRes.id.split('/'); - const intent = aiRes.response.reduce((a, b) => a.confidence > b.confidence ? a : b); + const intent = aiRes.response.reduce((a, b) => + a.confidence > b.confidence ? a : b + ); const response = config.responses.find((res) => res.label === intent.name); if (response.threshold > intent.confidence) return; + if (!response.reply) return; switch (ids[0]) { - case 'comment': { - client.getComment(ids[1]).reply(`${response.text}\n\n*Confidence: ${intent.confidence}*`); - break; - } + case 'comment': { + client + .getComment(ids[1]) + .reply( + `## ${response.reply.title}\n\n${response.reply.desc}\n\n*Confidence: ${intent.confidence}*\n\nThis bot is currently being tested in production. Ignore it, if it's wrong.` + ); + break; + } - case 'post': { - client.getSubmission(ids[1]).reply(`${response.text}\n\n*Confidence: ${intent.confidence}*`); - break; - } + case 'post': { + client + .getSubmission(ids[1]) + .reply( + `## ${response.reply.title}\n\n${response.reply.desc}\n\n*Confidence: ${intent.confidence}*\n\nThis bot is currently being tested in production. Ignore it, if it's wrong.` + ); + break; + } } return; - } }; diff --git a/bots/reddit/index.js b/bots/reddit/index.js index d41968e..de58c6e 100644 --- a/bots/reddit/index.js +++ b/bots/reddit/index.js @@ -97,7 +97,9 @@ export default async () => { event.execute(client, config, ...args) ); } else { - helper.on(event.name, (...args) => event.execute(client, config, ...args)); + helper.on(event.name, (...args) => + event.execute(client, config, ...args) + ); } } -} \ No newline at end of file +}; diff --git a/bots/telegram/commands/train.js b/bots/telegram/commands/train.js index 851fdc8..ddde333 100644 --- a/bots/telegram/commands/train.js +++ b/bots/telegram/commands/train.js @@ -9,7 +9,7 @@ export default { message_thread_id: msg.message_thread_id, reply_to_message_id: msg.message_id }); - + if (msg.reply_to_message.message_id === msg.message_thread_id) return bot.sendMessage(msg.chat.id, 'Please reply to a message!', { message_thread_id: msg.message_thread_id, diff --git a/bots/telegram/events/helper/aiResponse.js b/bots/telegram/events/helper/aiResponse.js index 3a217b6..0c5f003 100644 --- a/bots/telegram/events/helper/aiResponse.js +++ b/bots/telegram/events/helper/aiResponse.js @@ -5,15 +5,22 @@ export default { if (!aiRes.response) return; if (!aiRes.response[0]) return; const ids = aiRes.id.split('/'); - const intent = aiRes.response.reduce((a, b) => a.confidence > b.confidence ? a : b); + const intent = aiRes.response.reduce((a, b) => + a.confidence > b.confidence ? a : b + ); const response = config.responses.find((res) => res.label === intent.name); if (response.threshold > intent.confidence) return; + if (!response.reply) return; - bot.sendMessage(ids[0], `${response.text}\n\n*Confidence: ${intent.confidence}*`, { - message_thread_id: ids[1], - reply_to_message_id: ids[2], - parse_mode: 'HTML' - }); + bot.sendMessage( + ids[0], + `## ${response.reply.title}\n\n${response.reply.desc}\n\n_Confidence: ${intent.confidence}_\n\nThis bot is currently being tested in production. Ignore it, if it's wrong.`, + { + message_thread_id: ids[1], + reply_to_message_id: ids[2], + parse_mode: 'Markdown' + } + ); return; } diff --git a/bots/telegram/index.js b/bots/telegram/index.js index 08064c9..1654475 100644 --- a/bots/telegram/index.js +++ b/bots/telegram/index.js @@ -66,4 +66,4 @@ export default async () => { helper.on(event.name, (...args) => event.execute(bot, config, ...args)); } } -} \ No newline at end of file +}; diff --git a/package.json b/package.json index deee07b..cf13cf2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ }, "homepage": "https://github.com/reisxd/revanced-helper#readme", "scripts": { - "lint": "prettier --write . && eslint --fix ." + "lint": "prettier --write . && eslint --fix .", + "installPackages": "cd bots && npm i && cd ../client && npm i && cd ../server && npm i", + "start": "cd bots && node . & cd ../server && node ." }, "devDependencies": { "eslint": "^8.27.0", diff --git a/server/PROTOCOL.md b/server/PROTOCOL.md index 18a5d60..ce39387 100644 --- a/server/PROTOCOL.md +++ b/server/PROTOCOL.md @@ -2,7 +2,7 @@ The server uses TCP for connection and BSON for messages, so you need to serialize and deserialize the messages. -# AI +## AI Sending the server this JSON (BSON) will send you back the AI predictions. @@ -20,11 +20,28 @@ And the server would return something like this: { "op": 2, "id": "String", - "response": "I think the term afn is just a generic slang term for the app that allows you to modify the behavior of Dalvik based android application..." + "response": [ + { + "confidence": 0.99, + "id": "String", + "name": "revanced_download" + } + ] +``` + +### Training the AI + +To train the AI, send the server a JSON (BSON) like this: + +```json +{ + "op": 3, + "label": "revanced_download", + "text": "how to download revanced" } ``` -# OCR +## OCR Sending the server this JSON (BSON) will send you back the read text. diff --git a/server/events/ai.js b/server/events/ai.js index 1344272..224e826 100644 --- a/server/events/ai.js +++ b/server/events/ai.js @@ -1,11 +1,14 @@ import { serialize } from 'bson'; export default async function runAI(client, data, config) { - const witAIReq = await fetch(`https://api.wit.ai/message?v20230319&q=${encodeURI(data.text)}`, { - headers: { - authorization: `Bearer ${config.authToken}` + const witAIReq = await fetch( + `https://api.wit.ai/message?v20230319&q=${encodeURI(data.text)}`, + { + headers: { + authorization: `Bearer ${config.authToken}` + } } - }); + ); const response = await witAIReq.json(); diff --git a/server/events/index.js b/server/events/index.js index ef2d24e..8488178 100644 --- a/server/events/index.js +++ b/server/events/index.js @@ -1,4 +1,5 @@ import runAI from './ai.js'; import runOCR from './ocr.js'; +import trainAI from './train.js'; -export { runAI, runOCR }; +export { runAI, runOCR, trainAI }; diff --git a/server/events/train.js b/server/events/train.js new file mode 100644 index 0000000..4bed2f4 --- /dev/null +++ b/server/events/train.js @@ -0,0 +1,18 @@ +export default async function runAI(data, config) { + fetch('https://api.wit.ai/utterances', { + headers: { + authorization: `Bearer ${config.authToken}` + }, + body: JSON.stringify([ + { + text: data.text, + intent: data.label, + entities: [], + traits: [] + } + ]), + method: 'POST' + }); + + return; +} diff --git a/server/index.js b/server/index.js index de72460..07520c3 100644 --- a/server/index.js +++ b/server/index.js @@ -3,7 +3,7 @@ const config = JSON.parse(readFileSync('./config.json', 'utf-8')); import { createServer } from 'node:net'; import { deserialize } from 'bson'; -import { runAI, runOCR } from './events/index.js'; +import { runAI, runOCR, trainAI } from './events/index.js'; const server = createServer(async (client) => { client.on('data', async (data) => { @@ -17,6 +17,11 @@ const server = createServer(async (client) => { break; } + case 3: { + trainAI(eventData, config.witAI); + break; + } + case 5: { runOCR(client, eventData); break;