Added installation files
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.
This commit is contained in:
parent
3a85bd368f
commit
0d32c727fa
53
README.md
53
README.md
@ -1,33 +1,72 @@
|
||||
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 code has 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.
|
||||
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 files](#mandatory-files)
|
||||
* [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:
|
||||
* [Admidio events plugin](src/branch/master/plugins/events)
|
||||
* [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 files
|
||||
To create a plugin, a few mandatory 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`.
|
||||
#### 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` must 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.
|
||||
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
|
||||
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"bot_credentials": {
|
||||
"username": "",
|
||||
"password": "",
|
||||
"server": ""
|
||||
},
|
||||
|
||||
"character": {
|
||||
"name": "Peter",
|
||||
"avatar": "images/profilepic.jpg",
|
||||
"avatar_mime": "image/jpeg"
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"events"
|
||||
]
|
||||
}
|
17
config.json.template
Normal file
17
config.json.template
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"bot_credentials": {
|
||||
"username": "${uservar}",
|
||||
"password": "${passvar}",
|
||||
"server": "${servervar}"
|
||||
},
|
||||
|
||||
"character": {
|
||||
"name": "Bot",
|
||||
"avatar": "images/default_avatar.png",
|
||||
"avatar_mime": "image/png"
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"hello"
|
||||
]
|
||||
}
|
BIN
images/default_avatar.png
Normal file
BIN
images/default_avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
128
install.sh
Executable file
128
install.sh
Executable file
@ -0,0 +1,128 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Installation script for matrix-chatbot
|
||||
#
|
||||
# @author Dennis Potter <dennis@dennispotter.eu>
|
||||
# @copyright 2019, Dennis Potter
|
||||
# @license GNU General Public License (version 3)
|
||||
#
|
||||
# matrix-chatbot
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
##################################################################################
|
||||
|
||||
# This script does the following:
|
||||
# - create virtualenv
|
||||
# - install requirements of main bot
|
||||
# - create initial config.json
|
||||
# - (optional) create systemd service
|
||||
|
||||
if [[ $1 == help ]]; then
|
||||
echo "Help:"
|
||||
echo "install.sh : Creates a virtualenv, an initial config.json, and installs"
|
||||
echo " all required packages"
|
||||
echo "install.sh service: Runs ./install and additionally adds a systemd service."
|
||||
echo " This command will ask you for root credentials!"
|
||||
echo "install.sh help : Prints this message."
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define directory of chatbot
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# Check if user is superuser
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
echo "ERR: Please do not run this script as super user!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#################################################################
|
||||
# Create function to check availability of software
|
||||
#################################################################
|
||||
function availability {
|
||||
if [[ ! $(command -v $1) ]]; then
|
||||
echo "ERR: '$1' is not available but required. Please install it!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################################################################
|
||||
# Create virtualenv
|
||||
#################################################################
|
||||
# Check whether virtualenv is present
|
||||
availability virtualenv
|
||||
|
||||
# Create virtualenv
|
||||
virtualenv $DIR
|
||||
|
||||
# Enter virtualenv
|
||||
source $DIR/bin/activate
|
||||
|
||||
#################################################################
|
||||
# Install requirements
|
||||
#################################################################
|
||||
# Check whether pip3 is present
|
||||
availability pip3
|
||||
|
||||
# Install requirements
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
#################################################################
|
||||
# Create config.json
|
||||
#################################################################
|
||||
echo ""
|
||||
echo "############################################################################"
|
||||
echo "This step will generate a configuration file. The resulting bot will be very"
|
||||
echo "simple and is only able to respond to the message "Hello bot". However, it"
|
||||
echo "forms the perfect base for further development."
|
||||
echo ""
|
||||
echo "In the following steps, an _existing_ user must be provided. If you did not"
|
||||
echo "yet create a user for your bot, please do so now!"
|
||||
echo "############################################################################"
|
||||
echo ""
|
||||
|
||||
if [[ -f $DIR/config.json ]]; then
|
||||
read -p "$DIR/config.json already exists. Should I overwrite it? [y/n]: " ow
|
||||
|
||||
if [[ $ow != y ]]; then
|
||||
echo "ERR: Cannot write to $DIR/config.json!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
read -p 'Matrix homeserver: ' servervar
|
||||
read -p 'Matrix username: ' uservar
|
||||
read -p 'Matrix password: ' passvar
|
||||
|
||||
sed -e "s/\${servervar}/${servervar}/"\
|
||||
-e "s/\${uservar}/${uservar}/"\
|
||||
-e "s/\${passvar}/${passvar}/"\
|
||||
$DIR/config.json.template > $DIR/config.json
|
||||
|
||||
#################################################################
|
||||
# Configure service
|
||||
#################################################################
|
||||
if [[ $1 != service ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sudo useradd -r mchatbot
|
||||
|
||||
sed -e "s/\${DIR}/${DIR}/"\
|
||||
$DIR/matrix-chatbot.service.template > $DIR/matrix-chatbot.service
|
||||
|
||||
sudo mv $DIR/matrix-chatbot.service /etc/systemd/system/matrix-chatbot.service
|
||||
|
||||
sudo systemctl enable matrix-chatbot.service
|
||||
sudo systemctl start matrix-chatbot.service
|
14
matrix-chatbot.service.template
Normal file
14
matrix-chatbot.service.template
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Matrix chatbot
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
User=mchatbot
|
||||
WorkingDirectory=${DIR}
|
||||
ExecStart=${DIR}/bin/python run.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -15,6 +15,7 @@ HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'help')
|
||||
private_message = "Hey {}! Ik heb je even een privébericht gestuurd 🙂"
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
'''Print error messages to stderr'''
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
class MatrixBotAPI:
|
||||
@ -159,7 +160,11 @@ class MatrixBotAPI:
|
||||
help_text = open(HELP_LOCATION, mode="r").read()
|
||||
|
||||
for plugin in self.plugins:
|
||||
try:
|
||||
help_text += plugin.help()
|
||||
except TypeError:
|
||||
# The plugin probably returned 0, ignore it
|
||||
pass
|
||||
|
||||
self.send_message_private_public(room, event, help_text)
|
||||
|
||||
|
@ -2,7 +2,7 @@ __author__ = "Dennis Potter"
|
||||
__copyright__ = "Copyright 2019, Dennis Potter"
|
||||
__credits__ = ["Dennis Potter"]
|
||||
__license__ = "GPL-3.0"
|
||||
__version__ = "1.0.1"
|
||||
__version__ = "0.5.0"
|
||||
__maintainer__ = "Dennis Potter"
|
||||
__email__ = "dennis@dennispotter.eu"
|
||||
|
||||
@ -16,14 +16,19 @@ import MySQLdb as mysql
|
||||
|
||||
from matrix_bot_api.mregex_handler import MRegexHandler
|
||||
|
||||
EVENTS_DATA_DIR = os.path.join(os.path.dirname(__file__),
|
||||
'../../data/events')
|
||||
DATA_LOCATION = os.path.join(os.path.dirname(__file__),
|
||||
'../../data/events/data.db')
|
||||
CONFIG_LOCATION = os.path.join(os.path.dirname(__file__), 'config.json')
|
||||
HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'messages/help')
|
||||
MESSAGES_LOCATION = os.path.join(os.path.dirname(__file__),
|
||||
'messages/messages.dutch.json')
|
||||
|
||||
class Plugin:
|
||||
""" Description of event plugin """
|
||||
|
||||
""" This plugin grabs events from Admidio (https://admidio.org)
|
||||
and lets users interact with the data
|
||||
"""
|
||||
def __init__(self, bot):
|
||||
# Load the configuration
|
||||
with open(CONFIG_LOCATION) as json_data:
|
||||
@ -61,7 +66,7 @@ class Plugin:
|
||||
|
||||
try:
|
||||
# Try to make a new directory
|
||||
os.mkdir("data/events")
|
||||
os.mkdir(EVENTS_DATA_DIR)
|
||||
|
||||
# Define query to INSERT event table to SQLite DB
|
||||
sql = """CREATE TABLE 'events' (
|
||||
@ -69,7 +74,7 @@ class Plugin:
|
||||
'datetime_posted' datetime);"""
|
||||
|
||||
# Open, execute, commit, and close SQLite database
|
||||
sqlite_db = sqlite3.connect('data/events/data.db')
|
||||
sqlite_db = sqlite3.connect(DATA_LOCATION)
|
||||
sqlite_cursor = sqlite_db.cursor()
|
||||
sqlite_cursor.execute(sql)
|
||||
sqlite_db.commit()
|
||||
@ -120,7 +125,7 @@ class Plugin:
|
||||
results = mysql_cursor.fetchall()
|
||||
|
||||
# Open SQLite database
|
||||
sqlite_db = sqlite3.connect('data/events/data.db')
|
||||
sqlite_db = sqlite3.connect(DATA_LOCATION)
|
||||
|
||||
sqlite_cursor = sqlite_db.cursor()
|
||||
|
1
plugins/hello/README.md
Normal file
1
plugins/hello/README.md
Normal file
@ -0,0 +1 @@
|
||||
This is an example plugin with only a single callback. When a user says "Hello bot" in a room in which te bot is present, the user replies with "Hello \<username\>!".
|
25
plugins/hello/hello.py
Normal file
25
plugins/hello/hello.py
Normal file
@ -0,0 +1,25 @@
|
||||
from matrix_bot_api.mregex_handler import MRegexHandler
|
||||
import os
|
||||
|
||||
HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'messages/help')
|
||||
|
||||
class Plugin:
|
||||
""" This is an example plugin with only a single callback. When
|
||||
a user says "Hello bot" in a room in which te bot is present,
|
||||
the user replies with "Hello <username>!".
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
# Define sensitivity
|
||||
self.handler = []
|
||||
|
||||
self.handler.append(MRegexHandler("Hello bot", self.info_callback))
|
||||
|
||||
# Save parent bot
|
||||
self.bot = bot
|
||||
|
||||
def info_callback(self, room, event):
|
||||
room.send_text(f"Hello {event['sender']}!")
|
||||
|
||||
def help(self):
|
||||
return open(HELP_LOCATION, mode="r").read()
|
5
plugins/hello/messages/help
Normal file
5
plugins/hello/messages/help
Normal file
@ -0,0 +1,5 @@
|
||||
<h5><i>Hello</i></h5>
|
||||
This is an example help message of an example plugin. This message is made up in HTML.
|
||||
<ul>
|
||||
<li><i>bot</i>: greet me with "Hello bot". I will greet you back.</li>
|
||||
</ul>
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
matrix-client>=0.3.2
|
23
run.py
23
run.py
@ -3,14 +3,27 @@
|
||||
This is Peter. Peter is using the Python Matrix Bot API
|
||||
"""
|
||||
|
||||
__author__ = "Dennis Potter"
|
||||
__copyright__ = "Copyright 2019, Dennis Potter"
|
||||
__credits__ = ["Dennis Potter"]
|
||||
__license__ = "GPL-3.0"
|
||||
__version__ = "0.5.0"
|
||||
__maintainer__ = "Dennis Potter"
|
||||
__email__ = "dennis@dennispotter.eu"
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
|
||||
# Bot API import
|
||||
from matrix_bot_api.matrix_bot_api import MatrixBotAPI
|
||||
|
||||
CONFIG_LOCATION = os.path.join(os.path.dirname(__file__), 'config.json')
|
||||
|
||||
def main():
|
||||
# Load the configuration
|
||||
with open('config.json') as json_data:
|
||||
with open(CONFIG_LOCATION) as json_data:
|
||||
config = json.load(json_data)
|
||||
|
||||
# Create an instance of the MatrixBotAPI
|
||||
@ -19,11 +32,11 @@ def main():
|
||||
# Start polling
|
||||
bot.start_polling()
|
||||
|
||||
# Infinitely read stdin to stall main thread while the bot runs in other
|
||||
# threads.
|
||||
# Stall this thread while the bot runs in other threads. On ^C, this will
|
||||
# indicate to all threads that they should cancel
|
||||
try:
|
||||
while True:
|
||||
input()
|
||||
forever = threading.Event();
|
||||
forever.wait()
|
||||
except:
|
||||
bot.cancel = True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user