respond to !matrixgpt and !bots

This commit is contained in:
Cyberes 2024-04-07 22:44:27 -06:00
parent c482341c82
commit d325a136fa
5 changed files with 52 additions and 25 deletions

View File

@ -1,39 +1,44 @@
# MatrixGPT # MatrixGPT
_ChatGPT bot for Matrix._ _Chatbots for Matrix._
Uses code from [anoadragon453/nio-template](https://github.com/anoadragon453/nio-template).
## Install ## Install
```bash 1. Install requirements:
sudo apt install libolm-dev gcc python3-dev ```bash
pip install -r requirements.txt sudo apt install libolm-dev gcc python3-dev
``` pip install -r requirements.txt
```
2. Copy `config.sample.yaml` to `config.yaml` and fill it out with your bot's Matrix auth and your API key(s).
Copy `config.sample.yaml` to `config.yaml` and fill it out with your bot's auth and your OpenAI API key. [Pantalaimon](https://github.com/matrix-org/pantalaimon) is **required** for the bot to be able to talk in encrypted
rooms.
[Pantalaimon](https://github.com/matrix-org/pantalaimon) is **required** for the bot to be able to talk in encrypted rooms.
Then invite your bot and start a chat by prefixing your message with `!c`. The bot will create a thread (you don't need
to use `!c` in the thread).
I included a sample Systemd service. I included a sample Systemd service.
## Use ## Use
Invite the bot to your room and query it with the command `!c` (this can be changed in the config.) Invite your bot to a room.
Start a chat by prefixing your message with your trigger (for example, `!c`). The bot will create a thread when it
replies to you and you don't need to use the trigger in the thread.
Don't try to use two bots in the same thread. Don't try to use two bots in the same thread.
You can DM a bot for a private chat. Don't use the trigger prefix in a DM.
The bot will move its read marker when a new message is sent in the room. The bot will move its read marker when a new message is sent in the room.
The bot can give helpful reactions: The bot can give helpful reactions:
- 🚫 means that the user is not allowed to chat with the bot. - 🚫 means that the user is not allowed to chat with the bot.
- ❌ means the bot encountered an exception. The bot restarts when it encounters an exception which means it will not be able to respond for a short time after this reaction. - ❌ means the bot encountered an exception. The bot restarts when it encounters an exception which means it will not be
able to respond for a short time after this reaction.
- ❌ 🔐 means there was a decryption failure. - ❌ 🔐 means there was a decryption failure.
Use `!matrixgpt` to view the bot's help. The bot also responds to `!bots`.
## Encryption ## Encryption
This bot supports encryption. I recommend using [Pantalaimon](https://github.com/matrix-org/pantalaimon/) to manage encryption keys as the built-in solution is a little janky and may be unreliable. This bot supports encryption. I recommend using [Pantalaimon](https://github.com/matrix-org/pantalaimon/) to manage
encryption keys as the built-in solution is a little janky and may be unreliable.

View File

@ -7,7 +7,7 @@ from nio import (AsyncClient, InviteMemberEvent, MatrixRoom, MegolmEvent, RoomMe
from .chat_functions import check_authorized, is_thread, check_command_prefix from .chat_functions import check_authorized, is_thread, check_command_prefix
from .config import global_config from .config import global_config
from .handle_actions import do_reply_msg, do_reply_threaded_msg, do_join_channel from .handle_actions import do_reply_msg, do_reply_threaded_msg, do_join_channel, sound_off
from .matrix import MatrixClientHelper from .matrix import MatrixClientHelper
logger = logging.getLogger('MatrixGPT') logger = logging.getLogger('MatrixGPT')
@ -22,7 +22,7 @@ class MatrixBotCallbacks:
async def handle_message(self, room: MatrixRoom, requestor_event: RoomMessageText) -> None: async def handle_message(self, room: MatrixRoom, requestor_event: RoomMessageText) -> None:
""" """
Callback for when a message event is received Callback for when a message event is received.
""" """
# Mark all messages as read. # Mark all messages as read.
mark_read_task = asyncio.create_task(self.client.room_read_markers(room.room_id, requestor_event.event_id, requestor_event.event_id)) mark_read_task = asyncio.create_task(self.client.room_read_markers(room.room_id, requestor_event.event_id, requestor_event.event_id))
@ -35,6 +35,10 @@ class MatrixBotCallbacks:
return return
if requestor_event.sender == self.client.user_id: if requestor_event.sender == self.client.user_id:
return return
if msg == '!bots' or msg == '!matrixgpt':
logger.debug(f'Message from {requestor_event.sender} in {room.room_id} --> "{msg}"')
await sound_off(room, requestor_event, self.client_helper)
return
command_activated, sent_command_prefix, command_info = check_command_prefix(msg) command_activated, sent_command_prefix, command_info = check_command_prefix(msg)
if not command_activated and is_thread(requestor_event): if not command_activated and is_thread(requestor_event):

View File

@ -3,7 +3,7 @@ import logging
import traceback import traceback
from typing import Union from typing import Union
from nio import RoomSendResponse from nio import RoomSendResponse, MatrixRoom, RoomMessageText
from matrix_gpt import MatrixClientHelper from matrix_gpt import MatrixClientHelper
from matrix_gpt.api_client_manager import api_client_helper from matrix_gpt.api_client_manager import api_client_helper
@ -34,8 +34,8 @@ def assemble_messages(messages: list, mode: str):
async def generate_ai_response( async def generate_ai_response(
client_helper: MatrixClientHelper, client_helper: MatrixClientHelper,
room, room: MatrixRoom,
event, event: RoomMessageText,
msg: Union[str, list], msg: Union[str, list],
command_info: CommandInfo, command_info: CommandInfo,
thread_root_id: str = None, thread_root_id: str = None,
@ -104,7 +104,8 @@ async def generate_ai_response(
text_response, text_response,
reply_to_event_id=event.event_id, reply_to_event_id=event.event_id,
thread=True, thread=True,
thread_root_id=thread_root_id if thread_root_id else event.event_id thread_root_id=thread_root_id if thread_root_id else event.event_id,
markdown_convert=True
) )
await client.room_typing(room.room_id, typing_state=False, timeout=1000) await client.room_typing(room.room_id, typing_state=False, timeout=1000)
if not isinstance(resp, RoomSendResponse): if not isinstance(resp, RoomSendResponse):

View File

@ -101,3 +101,22 @@ async def do_join_channel(client_helper: MatrixClientHelper, room: MatrixRoom, e
return return
else: else:
logger.error(f'Unable to join room: {room.room_id}') logger.error(f'Unable to join room: {room.room_id}')
async def sound_off(room: MatrixRoom, event: RoomMessageText, client_helper: MatrixClientHelper):
text_response = """## MatrixGPT
<https://git.evulid.cc/cyberes/MatrixGPT>
### Commands
`!matrixgpt` - show this help message\n\n"""
for command in global_config['command']:
text_response = text_response + f"`{command['trigger']}` - Model: {command['model']}. Temperature: {command['temperature']}. Max tokens: {command['max_tokens']}.\n\n"
return await client_helper.send_text_to_room(
room.room_id,
text_response,
reply_to_event_id=event.event_id,
markdown_convert=True
)

View File

@ -119,7 +119,7 @@ class MatrixClientHelper:
return await self.client.room_send(room_id, "m.reaction", content, ignore_unverified_devices=True) return await self.client.room_send(room_id, "m.reaction", content, ignore_unverified_devices=True)
async def send_text_to_room(self, room_id: str, message: str, notice: bool = False, async def send_text_to_room(self, room_id: str, message: str, notice: bool = False,
markdown_convert: bool = True, reply_to_event_id: Optional[str] = None, markdown_convert: bool = False, reply_to_event_id: Optional[str] = None,
thread: bool = False, thread_root_id: Optional[str] = None, extra_error: Optional[str] = None, thread: bool = False, thread_root_id: Optional[str] = None, extra_error: Optional[str] = None,
extra_msg: Optional[str] = None) -> Union[RoomSendResponse, ErrorResponse]: extra_msg: Optional[str] = None) -> Union[RoomSendResponse, ErrorResponse]:
"""Send text to a matrix room. """Send text to a matrix room.
@ -142,9 +142,7 @@ class MatrixClientHelper:
A RoomSendResponse if the request was successful, else an ErrorResponse. A RoomSendResponse if the request was successful, else an ErrorResponse.
""" """
# Determine whether to ping room members or not
msgtype = "m.notice" if notice else "m.text" msgtype = "m.notice" if notice else "m.text"
content = {"msgtype": msgtype, "format": "org.matrix.custom.html", "body": message} content = {"msgtype": msgtype, "format": "org.matrix.custom.html", "body": message}
if markdown_convert: if markdown_convert: