From 6576bab911e726a51e63a6ecd6075a19f04fda78 Mon Sep 17 00:00:00 2001 From: Charlie Laabs Date: Tue, 29 May 2018 14:13:59 -0500 Subject: [PATCH] Update 0.3: Added attachments, TTS, and message deletion support. --- README.md | 8 +++++ index.js | 60 +++++++++++++++++++++++++++++------ package-lock.json | 80 +++++++++++++++++++++-------------------------- package.json | 4 +-- 4 files changed, 96 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index a0b231e..88d7ccc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # MarkBot for Discord This is a super rough prototype. A Markov chain bot using markov-strings. Just uploading here so it can run and generate training data. + +## Changelog +### 0.3.0 +Added TTS support and random message attachments. +Deleted messages no longer persist in the database longer than 24 hours. + +### 0.2.0 +Updated training algorithm and data structure. \ No newline at end of file diff --git a/index.js b/index.js index 00a0265..c7695fc 100644 --- a/index.js +++ b/index.js @@ -26,12 +26,14 @@ let fileObj = { let markovDB = [] let messageCache = [] +let deletionCache = [] const markovOpts = { maxLength: 400, minWords: 3, minScore: 10 } -let markov = new Markov(markovDB, markovOpts); +let markov +// let markov = new Markov(markovDB, markovOpts); function regenMarkov() { console.log("Regenerating Markov corpus...") @@ -41,11 +43,15 @@ function regenMarkov() { catch (err) { console.log(err) } // console.log("MessageCache", messageCache) markovDB = fileObj.messages + markovDB = uniqueBy(markovDB.concat(messageCache), 'id') + deletionCache.forEach(id => { + let removeIndex = markovDB.map(function (item) { return item.id; }).indexOf(id) + // console.log('Remove Index:', removeIndex) + markovDB.splice(removeIndex, 1) + }) + deletionCache = [] if (markovDB.length == 0) markovDB.push({ string: 'hello', id: null }) - //markovDB = uniqueArray(markovDB.concat(messageCache), 'id') - markovDB = uniqueBy(markovDB.concat(messageCache), 'id') - //markovDB = markovDB.concat(messageCache) markov = new Markov(markovDB, markovOpts); markov.buildCorpusSync() fileObj.messages = markovDB @@ -53,7 +59,7 @@ function regenMarkov() { // console.log(fileObj) fs.writeFileSync('markovDB.json', JSON.stringify(fileObj), 'utf-8') fileObj = null; - markovDB = [] + // markovDB = [] messageCache = [] console.log("Done regenerating Markov corpus.") } @@ -97,7 +103,7 @@ client.on('message', message => { .setAuthor(client.user.username, client.user.avatarURL) .setThumbnail(client.user.avatarURL) .setDescription('A Markov chain chatbot that speaks based on previous chat input.') - .addField('!mark', 'Generates a sentence to say based on the chat database') + .addField('!mark', 'Generates a sentence to say based on the chat database. Send your message as TTS to recieve it as TTS.') .addField('!mark train', 'Fetches the maximum amount of previous messages in the current text channel, adds it to the database, and regenerates the corpus. Takes about 2 minutes.') .addField('!mark regen', 'Manually regenerates the corpus to add recent chat info. Run this before shutting down to avoid any data loss. This automatically runs at midnight.') .addField('!mark invite', 'Don\'t invite this bot to other servers. The database is shared between all servers and text channels.') @@ -108,13 +114,27 @@ client.on('message', message => { } if (command === 'train') { console.log("Training...") + fileObj = { + messages: [] + } + fs.writeFileSync('markovDB.json', JSON.stringify(fileObj), 'utf-8') fetchMessageChunk(message, null, []) } if (command === 'respond') { console.log("Responding...") markov.generateSentence().then(result => { - console.log(result) - message.channel.send(result.string) + console.log('Generated Result:', result) + let messageOpts = { + tts: message.tts + } + let randomMessage = markovDB[Math.floor(Math.random() * markovDB.length)] + console.log('Random Message:', randomMessage) + if (randomMessage.hasOwnProperty('attachment')) { + messageOpts.files = [{ + attachment: randomMessage.attachment + }] + } + message.channel.send(result.string, messageOpts) }).catch(err => { console.log(err) if (err.message == 'Cannot build sentence with current corpus and options') @@ -129,7 +149,14 @@ client.on('message', message => { if (command === null) { console.log("Listening...") if (!message.author.bot) { - messageCache.push({ string: message.content, id: message.id }) + let dbObj = { + string: message.content, + id: message.id + } + if (message.attachments.size > 0) { + dbObj.attachment = message.attachments.values().next().value.url + } + messageCache.push(dbObj) } } if (command === inviteCmd) { @@ -146,6 +173,12 @@ client.on('message', message => { } }) +client.on('messageDelete', message => { + // console.log('Adding message ' + message.id + ' to deletion cache.') + deletionCache.push(message.id) + console.log('deletionCache:', deletionCache) +}) + function validateMessage(message) { let messageText = message.content.toLowerCase() let command = null; @@ -170,7 +203,14 @@ function fetchMessageChunk(message, oldestMessageID, historyCache) { message.channel.fetchMessages({ before: oldestMessageID, limit: 100 }) .then(messages => { historyCache = historyCache.concat(messages.filter(elem => !elem.author.bot).map(elem => { - return { string: elem.content, id: elem.id } + let dbObj = { + string: elem.content, + id: elem.id + } + if (elem.attachments.size > 0) { + dbObj.attachment = elem.attachments.values().next().value.url + } + return dbObj })); oldestMessageID = messages.last().id return historyCache.concat(fetchMessageChunk(message, oldestMessageID, historyCache)) diff --git a/package-lock.json b/package-lock.json index f4acb4f..fe928de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "markbot", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -41,27 +41,15 @@ } }, "discord.js": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.3.0.tgz", - "integrity": "sha512-xM3ydvb4urHjCP3N+Mgpw53a7ZGtmPwllwVgwPqdF2SHNPvTDr4So/+55VVx76s5eO9IMrOWpczsEuIr0/MAgQ==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.3.2.tgz", + "integrity": "sha512-Abw9CTMX3Jb47IeRffqx2VNSnXl/OsTdQzhvbw/JnqCyqc2imAocc7pX2HoRmgKd8CgSqsjBFBneusz/E16e6A==", "requires": { - "long": "3.2.0", - "prism-media": "0.0.1", - "snekfetch": "3.6.1", + "long": "4.0.0", + "prism-media": "0.0.2", + "snekfetch": "3.6.4", "tweetnacl": "1.0.0", - "ws": "4.0.0" - }, - "dependencies": { - "ws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", - "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", - "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.1", - "ultron": "1.1.1" - } - } + "ws": "4.1.0" } }, "erlpack": { @@ -85,14 +73,14 @@ } }, "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "long-timeout": { "version": "0.1.1", @@ -100,12 +88,12 @@ "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" }, "markov-strings": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/markov-strings/-/markov-strings-1.3.5.tgz", - "integrity": "sha512-cGe7DSh1RrkgCxu33xeI6RAhC0KCExGvS7enHkMyieNs0MrSGm9Gu5AYmVCFcWPM/+0SN34t38OdT+/YKrjxjQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/markov-strings/-/markov-strings-1.5.0.tgz", + "integrity": "sha512-fHrnpXvR2p3mkxZEGeQaipus+2Z+DnewLmxn1BosNRajwWza0dHX1NO3reYGsPB5BGtzDyR6lh3owFZyICs2mg==", "requires": { "debug": "3.1.0", - "lodash": "4.17.4" + "lodash": "4.17.10" } }, "moment": { @@ -147,19 +135,19 @@ "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" }, "prism-media": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.1.tgz", - "integrity": "sha1-o0JcnKvVDRxsAuVDlBoRiVZnvRA=" + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.2.tgz", + "integrity": "sha512-L6yc8P5NVG35ivzvfI7bcTYzqFV+K8gTfX9YaJbmIFfMXTs71RMnAupvTQPTCteGsiOy9QcNLkQyWjAafY/hCQ==" }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "snekfetch": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.1.tgz", - "integrity": "sha512-aLEvf1YR440pINb0LEo/SL2Q2s/A26+YEqPlx09A0XpGH7qWp8iqIFFolVILHn2yudWXJne9QWyQu+lzDp+ksQ==" + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" }, "sorted-array-functions": { "version": "1.1.0", @@ -171,16 +159,20 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "unique-by": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-by/-/unique-by-1.0.0.tgz", "integrity": "sha1-UiDIa6e8Vy+3E610ZRRwy2RCEr0=" }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.2" + } + }, "zlib-sync": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/zlib-sync/-/zlib-sync-0.1.4.tgz", diff --git a/package.json b/package.json index cfe21b6..b0e0f0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "markbot", - "version": "0.2.0", + "version": "0.3.0", "description": "A conversational Markov chain bot for Discord", "main": "index.js", "scripts": { @@ -16,7 +16,7 @@ "author": "Charlie Laabs ", "license": "MIT", "dependencies": { - "discord.js": "^11.3.0", + "discord.js": "^11.3.2", "erlpack": "github:discordapp/erlpack", "markov-strings": "^1.3.5", "node-schedule": "^1.3.0",