Merge branch 'typescript'

This commit is contained in:
Charlie Laabs
2020-01-11 20:47:52 -06:00
5 changed files with 142 additions and 71 deletions

20
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/index.ts"
]
}
]
}

110
README.md
View File

@@ -1,27 +1,48 @@
# MarkBot for Discord # MarkBot for Discord
A Markov chain bot using markov-strings. A Markov chain bot using markov-strings.
# Setup ## Usage
First, create a [Discord bot application](https://discordapp.com/developers/applications/).
## Windows
### Requirements
* [Node.js 8.0+ (Current)](https://nodejs.org/en/download/current/)
### Setup 1. Train the bot in a lengthy text channel:
1. Install Node.js 8.0 or newer. * User: `!mark train`
* Markbot: `@User, Finished training from past 76394 messages.`
1. Ask the bot to say something:
* User: `!mark`
* Markbot: `This Shopko has a Linux release`
## Setup
First, create a [Discord bot application](https://discordapp.com/developers/applications/).
### Windows
#### Requirements
* [Node.js 12.0+ (Current)](https://nodejs.org/en/download/)
* Installing with build tools is recommended
#### Setup
1. Install Node.js 12.0 or newer.
1. Download this repository using git in a command prompt 1. Download this repository using git in a command prompt
```cmd ```cmd
git clone https://github.com/charlocharlie/markov-discord.git git clone https://github.com/charlocharlie/markov-discord.git
``` ```
or by just downloading and extracting the [project zip](https://github.com/charlocharlie/markov-discord/archive/master.zip) from GitHub. or by just downloading and extracting the [project zip](https://github.com/charlocharlie/markov-discord/archive/master.zip) from GitHub.
1. Open a command prompt in the `markov-discord` folder. 1. Open a command prompt in the `markov-discord` folder.
```sh ```sh
# Install Windows build tools # Install Windows build tools (if you didn't install build tools with Node)
npm install --global --production windows-build-tools npm install --global --production windows-build-tools
# NPM install non-development packages # NPM install non-development packages
npm install --production npm install --production
``` ```
1. Create a file called `config.json` in the project directory with the contents: 1. Create a file called `config.json` in the project directory with the contents:
```json ```json
{ {
"prefix":"!mark", "prefix":"!mark",
@@ -29,28 +50,34 @@ First, create a [Discord bot application](https://discordapp.com/developers/appl
"token":"k5NzE2NDg1MTIwMjc0ODQ0Nj.DSnXwg.ttNotARealToken5p3WfDoUxhiH" "token":"k5NzE2NDg1MTIwMjc0ODQ0Nj.DSnXwg.ttNotARealToken5p3WfDoUxhiH"
} }
``` ```
Feel free to change the command prefix, game display. Add your bot token. Feel free to change the command prefix, game display. Add your bot token.
1. Run the bot: 1. Run the bot:
```sh ```sh
npm start npm start
``` ```
### Debian Linux
## Debian Linux #### Requirements
### Requirements
* Node.js 8.0+ * Node.js 12.0+
* Python 2.7 (for erlpack) * Python 2.7 (for erlpack)
* C++ build tools (for erlpack) * C++ build tools (for erlpack)
### Download #### Download
```sh ```sh
# Clone this repository # Clone this repository
git clone https://github.com/charlocharlie/markov-discord.git git clone https://github.com/charlocharlie/markov-discord.git
cd markov-discord cd markov-discord
``` ```
### Configure #### Configure
Create a file called `config.json` in the project directory with the contents: Create a file called `config.json` in the project directory with the contents:
```json ```json
{ {
"prefix":"!mark", "prefix":"!mark",
@@ -58,9 +85,11 @@ Create a file called `config.json` in the project directory with the contents:
"token":"k5NzE2NDg1MTIwMjc0ODQ0Nj.DSnXwg.ttNotARealToken5p3WfDoUxhiH" "token":"k5NzE2NDg1MTIwMjc0ODQ0Nj.DSnXwg.ttNotARealToken5p3WfDoUxhiH"
} }
``` ```
Feel free to change the command prefix, game display. Add your bot token. Feel free to change the command prefix, game display. Add your bot token.
### Install and Run #### Install and Run
```sh ```sh
# Install Node.js if you haven't already # Install Node.js if you haven't already
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
@@ -77,43 +106,61 @@ sudo apt-get install build-essential -y
npm start npm start
``` ```
## Docker ### Docker
### Setup with source
1. Install Docker for your OS. #### Setup with Docker Hub image
1. Download this repository using git in a command prompt
```sh
git clone https://github.com/charlocharlie/markov-discord.git
```
or by just downloading and extracting the [project zip](https://github.com/charlocharlie/markov-discord/archive/master.zip) from GitHub.
1. Open a command prompt in the markov-discord folder and run this one-liner:
```sh
docker run --rm -e TOKEN=YOUR.BOT.TOKEN -v config:/usr/src/markbot/config -it $(docker build -q .)
# Be patient as the build output is suppressed
```
### Setup with Docker Hub image
1. Install Docker for your OS. 1. Install Docker for your OS.
1. Open a command prompts and run: 1. Open a command prompts and run:
```sh ```sh
docker pull charlocharlie/markov-discord docker pull charlocharlie/markov-discord
docker run --rm -d charlocharlie/markov-discord:latest docker run --rm -d charlocharlie/markov-discord:latest
``` ```
#### Setup with source
1. Install Docker for your OS.
1. Download this repository using git in a command prompt
```sh
git clone https://github.com/charlocharlie/markov-discord.git
```
or by just downloading and extracting the [project zip](https://github.com/charlocharlie/markov-discord/archive/master.zip) from GitHub.
1. Open a command prompt in the markov-discord folder and run this one-liner:
```sh
docker run --rm -e TOKEN=YOUR.BOT.TOKEN -v config:/usr/src/markbot/config -it $(docker build -q .)
# Be patient as the build output is suppressed
```
## Changelog
### 0.7.1
* Readme updates
* Config loading fix
* Fix min score
* Add generator options to config
* Document Node 12 update
# Changelog
### 0.7.0 ### 0.7.0
* Convert project to Typescript * Convert project to Typescript
* Optimize Docker build (smaller image) * Optimize Docker build (smaller image)
* Load corpus from filesystem to reduce memory load * Load corpus from filesystem to reduce memory load
### 0.6.2 ### 0.6.2
* Fix MarkovDB not loading on boot * Fix MarkovDB not loading on boot
### 0.6.1 ### 0.6.1
* Fix bot crashing on scheduled regen * Fix bot crashing on scheduled regen
### 0.6.0 ### 0.6.0
* Added Docker deploy functionality. * Added Docker deploy functionality.
* Moved config and database to `./config` directory. Existing configs will be migrated. * Moved config and database to `./config` directory. Existing configs will be migrated.
* Config-less support via bot token located in an environment variable. * Config-less support via bot token located in an environment variable.
@@ -121,6 +168,7 @@ npm start
* Change corpus regen time to 4 AM. * Change corpus regen time to 4 AM.
### 0.5.0 ### 0.5.0
* Fixed bug where `!mark help` didn't work. * Fixed bug where `!mark help` didn't work.
* Only admins can train. * Only admins can train.
* The bot responds when mentioned. * The bot responds when mentioned.
@@ -131,6 +179,7 @@ npm start
* Simpler config loading. * Simpler config loading.
### 0.4.0 ### 0.4.0
* Huge refactor. * Huge refactor.
* Added `!mark debug` which sends debug info alongside the message. * Added `!mark debug` which sends debug info alongside the message.
* Converted the fetchMessages function to async/await (updating the requirement to Node.js 8). * Converted the fetchMessages function to async/await (updating the requirement to Node.js 8).
@@ -139,11 +188,14 @@ npm start
* Added linting and linted the project. * Added linting and linted the project.
### 0.3.0 ### 0.3.0
* Added TTS support and random message attachments. * Added TTS support and random message attachments.
* Deleted messages no longer persist in the database longer than 24 hours. * Deleted messages no longer persist in the database longer than 24 hours.
### 0.2.0 ### 0.2.0
* Updated training algorithm and data structure. * Updated training algorithm and data structure.
# Thanks # Thanks
Thanks to [BotMaker-for-Discord](https://github.com/CorySanin/BotMaker-for-Discord) which I used as a reference when during development. Thanks to [BotMaker-for-Discord](https://github.com/CorySanin/BotMaker-for-Discord) which I used as a reference when during development.

View File

@@ -4,7 +4,11 @@ import * as Discord from 'discord.js';
// https://discord.js.org/#/docs/main/stable/general/welcome // https://discord.js.org/#/docs/main/stable/general/welcome
import * as fs from 'fs'; import * as fs from 'fs';
import Markov, { MarkovGenerateOptions, MarkovResult } from 'markov-strings'; import Markov, {
MarkovGenerateOptions,
MarkovResult,
MarkovConstructorOptions,
} from 'markov-strings';
import * as schedule from 'node-schedule'; import * as schedule from 'node-schedule';
@@ -23,8 +27,11 @@ interface MessagesDB {
} }
interface MarkbotConfig { interface MarkbotConfig {
prefix: string; stateSize?: number;
game: string; minScore?: number;
maxTries?: number;
prefix?: string;
game?: string;
token?: string; token?: string;
} }
@@ -37,8 +44,11 @@ const client = new Discord.Client();
const PAGE_SIZE = 100; const PAGE_SIZE = 100;
// let guilds = []; // let guilds = [];
// let connected = -1; // let connected = -1;
let GAME = 'GAME'; let GAME = '!mark help';
let PREFIX = '! '; let PREFIX = '!mark';
let STATE_SIZE = 2; // Value of 1 to 3, based on corpus quality
let MAX_TRIES = 1000;
let MIN_SCORE = 10;
const inviteCmd = 'invite'; const inviteCmd = 'invite';
const errors: string[] = []; const errors: string[] = [];
@@ -49,14 +59,8 @@ let fileObj: MessagesDB = {
let markovDB: MessageRecord[] = []; let markovDB: MessageRecord[] = [];
let messageCache: MessageRecord[] = []; let messageCache: MessageRecord[] = [];
let deletionCache: string[] = []; let deletionCache: string[] = [];
const markovOpts = { let markovOpts: MarkovConstructorOptions = {
stateSize: 2, stateSize: STATE_SIZE,
maxLength: 2000,
minWords: 3,
maxWords: 0,
minScore: 10,
minScorePerWord: 0,
maxTries: 10000,
}; };
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -139,15 +143,21 @@ function loadConfig(): void {
PREFIX = cfg.prefix || '!mark'; PREFIX = cfg.prefix || '!mark';
GAME = cfg.game || '!mark help'; GAME = cfg.game || '!mark help';
token = cfg.token || process.env.TOKEN || token; token = cfg.token || process.env.TOKEN || token;
STATE_SIZE = cfg.stateSize || STATE_SIZE;
MIN_SCORE = cfg.minScore || MIN_SCORE;
MAX_TRIES = cfg.maxTries || MAX_TRIES;
} catch (e) { } catch (e) {
console.error('Failed to read config.json.'); console.warn('Failed to read config.json.');
throw e; token = process.env.TOKEN || token;
} }
try { try {
client.login(token); client.login(token);
} catch (e) { } catch (e) {
console.error('Failed to login with token:', token); console.error('Failed to login with token:', token);
} }
markovOpts = {
stateSize: STATE_SIZE,
};
} }
/** /**
@@ -245,27 +255,16 @@ async function fetchMessages(message: Discord.Message): Promise<void> {
* @param {Boolean} debug Sends debug info as a message if true. * @param {Boolean} debug Sends debug info as a message if true.
* @param {Boolean} tts If the message should be sent as TTS. Defaults to the TTS setting of the * @param {Boolean} tts If the message should be sent as TTS. Defaults to the TTS setting of the
* invoking message. * invoking message.
* @param {Array<String>} filterWords Array of words that the message generated will be filtered on.
*/ */
function generateResponse( function generateResponse(message: Discord.Message, debug = false, tts = message.tts): void {
message: Discord.Message,
debug = false,
tts = message.tts,
filterWords?: string[]
): void {
console.log('Responding...'); console.log('Responding...');
const options: MarkovGenerateOptions = {}; const options: MarkovGenerateOptions = {
if (filterWords) { filter: (result): boolean => {
options.filter = (result): boolean => { return result.score >= MIN_SCORE;
for (let i = 0; i < filterWords.length; i += 1) { },
if (result.string.includes(filterWords[i])) { maxTries: MAX_TRIES,
return true; };
}
}
return false;
};
options.maxTries = 5000;
}
const fsMarkov = new Markov([''], markovOpts); const fsMarkov = new Markov([''], markovOpts);
const markovFile = JSON.parse(fs.readFileSync('config/markov.json', 'utf-8')) as Markov; const markovFile = JSON.parse(fs.readFileSync('config/markov.json', 'utf-8')) as Markov;
fsMarkov.corpus = markovFile.corpus; fsMarkov.corpus = markovFile.corpus;

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "markbot", "name": "markbot",
"version": "0.7.0", "version": "0.7.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "markbot", "name": "markbot",
"version": "0.7.0", "version": "0.7.1",
"description": "A conversational Markov chain bot for Discord", "description": "A conversational Markov chain bot for Discord",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@@ -34,7 +34,7 @@
"zlib-sync": "^0.1.6" "zlib-sync": "^0.1.6"
}, },
"engines": { "engines": {
"node": ">=8.0.0" "node": ">=12.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.12.21", "@types/node": "^12.12.21",