Dennis
0d32c727fa
This commit adds a convenient installation script for Linux and also adds a description on how to install the bot. Furthermore, a very simple example plugin is added. This way, new users can easily discover the possibilities of this plugin. Finally, the default character "Peter"---which is used within Alcuinus---is removed, and a more generic character is added.
194 lines
8.8 KiB
Markdown
194 lines
8.8 KiB
Markdown
The core of this chatbot is based on [github.com/shawnanastasio/python-matrix-bot-api](https://github.com/shawnanastasio/python-matrix-bot-api/) which was published under GPL-3.0. It is heavily modified to create an API to easily add plugins. This bot is intended to operate on the [Matrix network](https://matrix.org).
|
|
|
|
This bot was orginally created to serve two purposes. Firstly, and mainly, it serves as virtual assistent in the Matrix based communication platform of members of the Dutch student association [Alcuinus](https://alcuinus.nl). Secondly, the bot's easy to use API makes the development of a simple plugin an approachable first project for new members of Alcuinus' IT working groups during their training.
|
|
|
|
## Content
|
|
* [Installation & Requirements](#installation-requirements)
|
|
* [Automatic installation (Linux)](#automatic-installation-linux)
|
|
* [Manual installation](#manual-installation)
|
|
* [Plugins](#plugins)
|
|
* [List of available plugins](#list-of-available-plugins)
|
|
* [API](#api)
|
|
* [Mandatory/recommended files](#mandatory-recommended-files)
|
|
* [Help template](#help-template)
|
|
* [Plugin class template](#plugin-class-template)
|
|
* [Additional tips](#additional-tips)
|
|
|
|
## Installation & Requirements:
|
|
First, clone this repository:
|
|
```
|
|
git clone https://git.dennispotter.eu/Dennis/matrix-chatbot
|
|
```
|
|
In order for the bot framework to work, Python 3, [virtualenv](https://virtualenv.pypa.io/en/latest/), and [pip](https://pypi.org/project/pip/) must be installed on your computer or server.
|
|
|
|
### Automatic installation (Linux)
|
|
On Linux, the bash script `install.sh` can be used to install the bot.
|
|
```
|
|
install.sh : Creates a virtualenv, an initial config.json, and installs
|
|
all required packages
|
|
install.sh service: Runs ./install and additionally adds a systemd service.
|
|
This command will ask you for root credentials!
|
|
install.sh help : Prints this message.
|
|
```
|
|
### Manual installation
|
|
Create a virtual environment by entering the directory and running:
|
|
```
|
|
virtualenv .
|
|
```
|
|
Enter the virtual environment
|
|
```
|
|
source bin/activate
|
|
```
|
|
and install all required packages
|
|
```
|
|
pip3 install -r requirements.txt
|
|
```
|
|
Now, you need to create a configuration file `config.json`. The template `config.json.template` can be used for this purpose.
|
|
|
|
Finally, the bot can be started by executing the following command within the virtual environment:
|
|
|
|
```
|
|
./run.py
|
|
```
|
|
|
|
## Plugins
|
|
The bot has different plugins that can be activated by sending `[Keyword in bot's config.json] [Keyword(s) in plugin's config.json]` to a room in which the bot is present. Below, under [List of available plugins](list-of-available-plugins), you can first find a list of already available plugins. Then, under [API](#api), you can find a description on how to develop a new plugin.
|
|
|
|
### List of available plugins:
|
|
* [Hello plugin](src/branch/master/plugins/events): An example plugin that interacts with users that send "Hello bot" to the bot.
|
|
* [Admidio events plugin](src/branch/master/plugins/events): a plugin that interacts with an [Admidio](https://admidio.org) installation.
|
|
|
|
### API
|
|
To interact with rooms, the [Matrix Python SDK](http://matrix-org.github.io/matrix-python-sdk/<Paste>) can be used.
|
|
|
|
#### Mandatory/recommended files
|
|
To create a plugin, a few mandatory or recommended files must be present. The tree below shows the general structure of a plugin. A new plugin must be placed in a directory with the same name. The main class (more on that later) of the plugin must be defined in a Python file with the same name within that directory. The event may not use bot's main configuration file. All configuration must be placed in a separate `config.json`.
|
|
|
|
A subdirectory `messages` is used to store messages. Within this directory, a file `help` may be present. The content of this file must be returned with a method of the plugin class (more on that later). Furthermore, for every language a file `messages.<language>.json` with all messages should exist.
|
|
|
|
The help file is not mandatory. If no help message for a plugin should appear when sending a help request to the bot, this file can be ommitted. The Plugin's `help()` method should return 0 in that case.
|
|
```
|
|
.
|
|
└── plugins
|
|
├── <plugin1>
|
|
│ ├── __init__.py
|
|
│ ├── <plugin1>.py
|
|
│ ├── README.md
|
|
│ ├── config.json
|
|
│ └── messages
|
|
│ ├── messages.<language>.json
|
|
│ └── help
|
|
├── <plugin2>
|
|
╎
|
|
╎
|
|
└── <pluginN>
|
|
```
|
|
#### Help template
|
|
The help function must be created in [HTML](https://www.w3schools.com/html/). The header must be the string that is used to activate the plugin (`<callback>`). Every feature that is listed must start with the string that is used to activate that particular feature.
|
|
|
|
The code belows shows an example of such a help function.
|
|
```html
|
|
<h5><i><callback></i></h5>
|
|
<ul>
|
|
<li><i>feature1</i>: Lorem ipsum dolor sit amet,</li>
|
|
<li><i>feature2</i>: consectetur adipiscing elit.</li>
|
|
<li><i>feature3</i>: Nunc ac volutpat nisi, id hendrerit tellus.</li>
|
|
</ul>
|
|
<br />
|
|
<Additional information>
|
|
|
|
```
|
|
|
|
#### Plugin class template
|
|
The code below shows the template for a simple plugin with a few features. The name of the class of every plugin must be `Plugin`.
|
|
|
|
* It has a method `__init__()` which is executed every time the bot is started. Usually, this should load the configuration file, it should set the sensitivity on which it should execute certain callback functions, it should save the parent object, start additional threads, and execute the setup.
|
|
* It has a method `setup()` which is only executed once (ever). This can be used, for example, to create [SQLite](https://sqlite.org) tables. All data should be saved in subdirectory for that plugin in `data`. See the example below, where `<plugin1>` initiates an SQLite database.
|
|
|
|
```
|
|
.
|
|
├── plugins
|
|
└── data
|
|
├── <plugin1>
|
|
│ └── plugin_data.db
|
|
├── <plugin2>
|
|
╎
|
|
╎
|
|
└── <pluginN>
|
|
```
|
|
|
|
* It has one method `thread_method1()` which is spawned and runs continuously in the background. **Please keep performance in mind when doing this!***. For example, is it actually necessary to continuously run the thread, or is execution only necessary every 5 minutes?
|
|
* For every sensitivity that is defined, a method must be defined that acts on it. The methods get a `room` and `event` object from the parent bot. These can be used to interact with the room. A full documentation on the [Matrix Python SDK](http://matrix-org.github.io/matrix-python-sdk/) can be found [here](http://matrix-org.github.io/matrix-python-sdk/).
|
|
* The Plugin class must contain a method `help()` which only returns the content of `plugin1/messages/help`
|
|
|
|
```python
|
|
CONFIG_LOCATION = os.path.join(os.path.dirname(__file__), 'config.json')
|
|
HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'help')
|
|
MESSAGES_LOCATION = os.path.join(os.path.dirname(__file__),
|
|
'messages/messages.dutch.json')
|
|
|
|
class Plugin:
|
|
""" Description of event plugin """
|
|
|
|
def __init__(self, bot):
|
|
# Load the configuration
|
|
with open(CONFIG_LOCATION) as json_data:
|
|
self.config = json.load(json_data)
|
|
|
|
# Load all messages for this plugin
|
|
with open(MESSAGES_LOCATION) as json_data:
|
|
self.messages = json.load(json_data)
|
|
|
|
# Define sensitivity
|
|
self.handler = []
|
|
|
|
self.handler.append(MRegexHandler("Peter <plugin1> <feature1>",
|
|
self.callback1))
|
|
self.handler.append(MRegexHandler("Peter <plugin1> <feature2>",
|
|
self.callback2))
|
|
|
|
# Save parent bot
|
|
self.bot = bot
|
|
|
|
# Start thread to check events
|
|
self.thread1 = threading.Thread(target=self.thread1_method)
|
|
self.thread1.start()
|
|
|
|
self.setup()
|
|
|
|
def setup(self):
|
|
"""This function only runs once, ever. It installs the plugin"""
|
|
|
|
try:
|
|
# Install some stuff, if not already installed
|
|
except sqlite3.OperationalError:
|
|
# For example, when trying to initialize an SQLite DB
|
|
# which already exists, sqlite3.OperationalError is thrown
|
|
pass
|
|
|
|
def thread1_method(self):
|
|
"""This function continuously loops"""
|
|
|
|
while not self.bot.cancel:
|
|
# Do something. For example, call other methods.
|
|
|
|
# Sleep
|
|
time.sleep(self.config['update_time_span'] * 60)
|
|
|
|
def callback1(self, room, event):
|
|
"""Act on first sensitivity"""
|
|
|
|
room.send_text("You typed 'Peter <plugin1> <feature1>'")
|
|
|
|
def callback2(self, room, event):
|
|
"""Act on second sensitivity"""
|
|
|
|
room.send_text("You typed 'Peter <plugin1> <feature2>'")
|
|
|
|
def help(self):
|
|
return open(HELP_LOCATION, mode="r").read()
|
|
```
|
|
|
|
#### Additional tips
|
|
* Use [f-strings](https://www.python.org/dev/peps/pep-0498/#how-to-denote-f-strings) if possible.
|