Code Monkey home page Code Monkey logo

iris-bot's Introduction

iris-bot — a Discord bot focusing on natural language interaction

iris-bot is a Discord bot written for the Domain of J community. It was ported from a version I made for Slack, which in turn was ported from a version written for IRC.

The goal of iris-bot is not to have a bot that specialises in a certain functionality with commands, but to have a bot that users can interact with using natural language.

Getting up and running

  1. Install Node. The LTS version should be fine.
  2. Create a copy of <root>/conf/config.example.json as <root>/config.json. Update the values inside.
  3. Run npm run gen-db to initialise the bot configuration DB using the example file as a starting point. This enables the bot to save settings and use responses (outlined below).
  4. npm run quickstart fetches dependencies, builds and then runs the bot using the start entry point.

Developing

To get started developing quickly, follow the first three points in the section directly above. This will set up the configuration that the bot needs in order to run. Following this, run npm install to pull down packages.

When developing, there are some NPM scripts that can be used to make development easier:

  • npm run develop spins up a a development version of the bot. It should also live reload when files are changed.
  • npm run test runs the bot’s unit tests in the console.
  • npm run coverage also runs the tests, but generates a code coverage report as well.
  • npm run pr-check will highlight issues that should be addressed before making a PR.

Bot configuration

The bot stores the majority of its configuration in a SQLite database, <root>/bot.sqlite. An example SQL file used to populate the responses table can be found in the <root>/conf/bot.sql file.

To generate a database from the example file, run npm run gen-db. This can then be viewed and modified using a tool like DB Browser for SQLite.

The main tables generated are documented in the SQL example file, however in summary:

  • tally is used by the tally core to store the count for a server
  • hangman is used by the hangman core to store the game information for a server
  • responses is used to control the responses provided by the response generator
  • call_response is used to respond to specific calls

Adding functionality

The bot uses personality plugins, often called cores in a loose reference to Portal. These are placed in src/personality and implement the Personality interface found in src/interfaces/personality.ts.

Personality interface: required methods

The interface defines the following required method signatures:

onMessage(message: Message): Promise<MessageType>

This is called whenever the bot receives a message.

The parameters are:

  • message: Message - the source message object from Discord

Return a Promise resolving to null to ignore the message, or resolving to one of the MessageTypes to handle it.

onAddressed(message: Message, addressedMessage: string): Promise<MessageType>

This is called when the bot detects that it has been addressed by a user, i.e. when someone types @botname message in the chat.

The parameters are:

  • message: Message - the source message object from Discord
  • addressedMessage: string - the message text after the mention, i.e. @bot hi returns hi

Return a Promise resolving to null to ignore the message, or resolving to one of the MessageTypes to handle it.

Personality interface: optional methods

The interface defines the following optional method signatures:

initialise(): void

This is called when the bot starts up but before it is connected to the server. Use this method to initialise long-running setup tasks in preference of doing it all in the constructor.

destroy(): void

This is called as the bot is shutting down but before the core components are unloaded. It can be used as a place to store settings to i.e. the database. Long-running tasks should be avoided here as there is no guarantee they will complete in time.

onHelp(): Promise<MessageType>

This is called when a user requests help for the specific core. If this method is implemented, your core will show up in the help list with a lowercase string version of the class name.

The parameters are:

  • message: Message - the source message object from Discord

Return a Promise resolving to one of the MessageTypes. Resolving to null is not recommended — simply do not implement this instead.

Generating responses from a set

The bot can generate multiple responses by selecting a random response from a phrase set, meaning responses for a particular command can vary. It does this with the help of three things: the responses table in the configuration DB, a simulated “mood” and and the response generator.

The structure of the response database table is as follows:

CREATE TABLE `responses` ( `type` TEXT, `mood` TEXT, `text` TEXT )
  • type is the name of the phrase set this response belongs to, and is the identifier used in-code to fetch a phrase.
  • mood is the general tone of voice of this phrase, and is be used to vary the responses based upon the bot's mood. The values are 'none' (neutral mood), 'happy' (positive mood) and 'sad' (negative mood).
  • text is the actual textual content of the response.

For example, there may be a phrase set used to welcome new people to the server titled 'welcome'. It could contain the following entries:

[
  { "type": "welcome", "mood": "none", "text": "hey!" },
  { "type": "welcome", "mood": "none", "text": "hi" },
  { "type": "welcome", "mood": "none", "text": "welcome" }
]

When the bot uses the 'welcome' phrase set with a neutral mood, the resulting message may be either "hey!", "hi" or "welcome".

To use this feature in your personality constructs, use the responses property of the DependencyContainer. Pass this to your personality construct in the index file.

class myPersonality implements Personality {
  // Dependency container is made available through `this.deps`
  constructor(private deps: DependencyContainer) {}

  /* other code removed for clarity */

  // Example usage in a custom function
  private myResponse(message: discord.Message): Promise<string> {
    if (message.content === '!command') {
      return this.deps.responses.generateResponse('my-phrase-here');
    }

    return Promise.resolve(null);
  }
}

Running the bot as a systemd service

The bot can be run on a *nix server using systemd. An example unit file is provided in the conf directory. Please be sure to update the values to match your environment.

Place your systemd service file in the systemd/system/ directory on the machine and invoke systemctl daemon-reload. You can then enable and start the service as required.

iris-bot's People

Contributors

jbrowneuk avatar dependabot[bot] avatar

Watchers

 avatar Jordan Campbell avatar

iris-bot's Issues

It is possible to invoke an addressed response by using {£me} keyword

If the call/response table has any addressed calls, it is possible to invoke that call without addressing the bot.

Consider the Call/Response pair:

Call Response
{£me} prompt My response

The intent is that you can address the bot by sending the message botname prompt to which it will respond with My response.

However, it is also possible to get the same response by sending the text {£me} prompt. This is not intended behaviour and so should be fixed.

Blog roll feature polls too often and logs

The blog roll feature that polls for journal updates currently has an interval of 5 minutes. This timespan should be configurable to not DDOS the journal API.

It also has verbose logging which should be tweaked to prevent event log spam when running on production environments.

Long-running async tasks can have their responses posted in the wrong place

If a long-running fetch task occurs (i.e. getting an image for a command) and more messages arrive before the API response is received, the cached "last message" is updated and the channel the response is sent to will change.

i.e.:
Channel 1 userA: +get-slow-api-response
*bot begins data request
Channel 2: userB: anything
*API returns results, bot processes
Channel 2: bot: api response

This means the bot can potentially post a response to a request in a different server.

Bot will have "nothing to say" if a phrase does not have a response for a particular mood

Response generator: if a phrase does not have a value for a specific mood, the bot will respond with the error response "Nothing to say..."

example:

  1. Bot mood +100 - happy
  2. Phrase: genericPhrase:
mood response
none Response1
none Response2
none Response3
sad SadResponse

When this phrase is requested, according to the documentation the fallback none responses (Response1, Response2, Response3) should be chosen.

Actual behaviour: the bot will only respond with "Nothing to say..."
Expected behaviour: the bot will respond with Response1, Response2 or Response3

Feature request: jokes

Request from server:

would also be fun if she (skye) could tell jokes. like we could ask for a joke and she would say one

No centralised way to persist settings

Each personality plug-in persists its settings in a different way. The bot’s settings API should be extended to allow for consumers to persist their settings in a consistent manner to a central store.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.