Implement quiet mode (not responding to everything)
More README content "Fixing" auto-joining
This commit is contained in:
parent
1ed989c9b9
commit
85a04c4188
4 changed files with 102 additions and 27 deletions
52
README.md
52
README.md
|
@ -9,20 +9,20 @@ probably add more in the future, so the name is a bit misleading.
|
|||
|
||||
## Features
|
||||
|
||||
- AI-generated responses to all messages in a Matrix room (chatbot)
|
||||
- AI-generated responses to messages in a Matrix room (chatbot)
|
||||
- Currently supports OpenAI (tested with `gpt-3.5-turbo` and `gpt-4`)
|
||||
- AI-generated pictures via the `!gptbot imagine` command
|
||||
- Currently supports OpenAI (DALL-E)
|
||||
- Mathematical calculations via the `!gptbot calculate` command
|
||||
- Currently supports WolframAlpha
|
||||
- Automatic classification of messages (for `imagine`, `calculate`, etc.)
|
||||
- Beta feature, see Usage section for details
|
||||
- Really useful commands like `!gptbot help` and `!gptbot coin`
|
||||
- DuckDB database to store room context
|
||||
|
||||
## Planned features
|
||||
|
||||
- End-to-end encryption support (partly implemented, but not yet working)
|
||||
- Automatic classification of messages (for `imagine`, `calculate`, etc.)
|
||||
- Beta feature, enable for a room using `!gptbot roomsettings classification true`
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -57,12 +57,48 @@ to messages. If you want to create a new room, you can use the `!gptbot newroom`
|
|||
command at any time, which will cause the bot to create a new room and invite
|
||||
you to it. You may also specify a room name, e.g. `!gptbot newroom My new room`.
|
||||
|
||||
Note that the bot will currently respond to _all_ messages in the room. So you
|
||||
shouldn't invite it to a room with other people in it.
|
||||
### Reply generation
|
||||
|
||||
It also supports the `!gptbot help` command, which will print a list of available
|
||||
commands. Messages starting with `!` are considered commands and will not be
|
||||
considered for response generation.
|
||||
Note that the bot will respond to _all_ messages in the room by default. If you
|
||||
don't want this, for example because you want to use the bot in a room with
|
||||
other people, you can use the `!gptbot roomsettings` command to change the
|
||||
settings for the current room. For example, you can disable response generation
|
||||
with `!gptbot roomsettings always_reply false`.
|
||||
|
||||
With this setting, the bot will only be triggered if a message begins with
|
||||
`!gptbot chat`. For example, `!gptbot chat Hello, how are you?` will cause the
|
||||
bot to generate a response to the message `Hello, how are you?`. The bot will
|
||||
still get previous messages in the room as context for generating the response.
|
||||
|
||||
### Commands
|
||||
|
||||
There are a few commands that you can use to interact with the bot. For example,
|
||||
if you want to generate an image from a text prompt, you can use the
|
||||
`!gptbot imagine` command. For example, `!gptbot imagine a cat` will cause the
|
||||
bot to generate an image of a cat.
|
||||
|
||||
To learn more about the available commands, `!gptbot help` will print a list of
|
||||
available commands.
|
||||
|
||||
### Automatic classification
|
||||
|
||||
As a beta feature, the bot can automatically classify messages and use the
|
||||
appropriate API to generate a response. For example, if you send a message
|
||||
like "Draw me a picture of a cat", the bot will automatically use the
|
||||
`imagine` command to generate an image of a cat.
|
||||
|
||||
This feature is disabled by default. To enable it, use the `!gptbot roomsettings`
|
||||
command to change the settings for the current room. `!gptbot roomsettings classification true`
|
||||
will enable automatic classification, and `!gptbot roomsettings classification false`
|
||||
will disable it again.
|
||||
|
||||
Note that this feature is still in beta and may not work as expected. You can
|
||||
always use the commands manually if the automatic classification doesn't work
|
||||
for you (including `!gptbot chat` for a regular chat message).
|
||||
|
||||
Also note that this feature conflicts with the `always_reply false` setting -
|
||||
or rather, it doesn't make sense then because you already have to explicitly
|
||||
specify the command to use.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ from nio import (
|
|||
RoomMessageText,
|
||||
RoomSendResponse,
|
||||
SyncResponse,
|
||||
RoomMessageNotice
|
||||
RoomMessageNotice,
|
||||
JoinError,
|
||||
RoomLeaveError,
|
||||
)
|
||||
from nio.crypto import Olm
|
||||
|
||||
|
@ -58,6 +60,7 @@ class GPTBot:
|
|||
image_api: Optional[OpenAI] = None
|
||||
classification_api: Optional[OpenAI] = None
|
||||
operator: Optional[str] = None
|
||||
room_ignore_list: List[str] = [] # List of rooms to ignore invites from
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config: ConfigParser):
|
||||
|
@ -276,8 +279,25 @@ class GPTBot:
|
|||
invites = self.matrix_client.invited_rooms
|
||||
|
||||
for invite in invites.keys():
|
||||
if invite in self.room_ignore_list:
|
||||
self.logger.log(
|
||||
f"Ignoring invite to room {invite} (room is in ignore list)")
|
||||
continue
|
||||
|
||||
self.logger.log(f"Accepting invite to room {invite}")
|
||||
await self.matrix_client.join(invite)
|
||||
|
||||
response = await self.matrix_client.join(invite)
|
||||
|
||||
if isinstance(response, JoinError):
|
||||
self.logger.log(
|
||||
f"Error joining room {invite}: {response.message}. Not trying again.", "error")
|
||||
|
||||
leave_response = await self.matrix_client.room_leave(invite)
|
||||
|
||||
if isinstance(leave_response, RoomLeaveError):
|
||||
self.logger.log(
|
||||
f"Error leaving room {invite}: {leave_response.message}", "error")
|
||||
self.room_ignore_list.append(invite)
|
||||
|
||||
async def send_image(self, room: MatrixRoom, image: bytes, message: Optional[str] = None):
|
||||
"""Send an image to a room.
|
||||
|
@ -487,13 +507,13 @@ class GPTBot:
|
|||
await self.matrix_client.sync(timeout=30000)
|
||||
|
||||
def respond_to_room_messages(self, room: MatrixRoom | str) -> bool:
|
||||
"""Check whether the bot should respond to messages sent in a room.
|
||||
"""Check whether the bot should respond to all messages sent in a room.
|
||||
|
||||
Args:
|
||||
room (MatrixRoom | str): The room to check.
|
||||
|
||||
Returns:
|
||||
bool: Whether the bot should respond to messages sent in the room.
|
||||
bool: Whether the bot should respond to all messages sent in the room.
|
||||
"""
|
||||
|
||||
if isinstance(room, MatrixRoom):
|
||||
|
@ -501,7 +521,7 @@ class GPTBot:
|
|||
|
||||
with self.database.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"SELECT value FROM room_settings WHERE room_id = ? AND setting = ?", (room, "respond_to_messages"))
|
||||
"SELECT value FROM room_settings WHERE room_id = ? AND setting = ?", (room, "always_reply"))
|
||||
result = cursor.fetchone()
|
||||
|
||||
return True if not result else bool(int(result[0]))
|
||||
|
|
|
@ -28,4 +28,4 @@ async def command_newroom(room: MatrixRoom, event: RoomMessageText, bot):
|
|||
|
||||
await bot.matrix_client.joined_rooms()
|
||||
await bot.send_message(room, f"Alright, I've created a new room called '{room_name}' and invited you to it. You can find it at {new_room.room_id}", True)
|
||||
await bot.send_message(new_room.room_id, f"Welcome to the new room! What can I do for you?")
|
||||
await bot.send_message(new_room, f"Welcome to the new room! What can I do for you?")
|
|
@ -3,10 +3,15 @@ from nio.rooms import MatrixRoom
|
|||
|
||||
|
||||
async def command_roomsettings(room: MatrixRoom, event: RoomMessageText, bot):
|
||||
setting = event.body.split()[2]
|
||||
setting = event.body.split()[2] if len(event.body.split()) > 2 else None
|
||||
value = " ".join(event.body.split()[3:]) if len(
|
||||
event.body.split()) > 3 else None
|
||||
|
||||
if setting == "classification":
|
||||
setting = "use_classification"
|
||||
if setting == "systemmessage":
|
||||
setting = "system_message"
|
||||
|
||||
if setting == "system_message":
|
||||
if value:
|
||||
bot.logger.log("Adding system message...")
|
||||
|
@ -28,38 +33,52 @@ async def command_roomsettings(room: MatrixRoom, event: RoomMessageText, bot):
|
|||
await bot.send_message(room, f"The current system message is: '{system_message}'.", True)
|
||||
return
|
||||
|
||||
if setting == "classification":
|
||||
if setting in ("use_classification", "always_reply"):
|
||||
if value:
|
||||
if value.lower() in ["true", "false"]:
|
||||
value = value.lower() == "true"
|
||||
|
||||
bot.logger.log("Setting classification status...")
|
||||
bot.logger.log(f"Setting {setting} status for {room.room_id} to {value}...")
|
||||
|
||||
with bot.database.cursor() as cur:
|
||||
cur.execute(
|
||||
"""INSERT INTO room_settings (room_id, setting, value) VALUES (?, ?, ?)
|
||||
ON CONFLICT (room_id, setting) DO UPDATE SET value = ?;""",
|
||||
(room.room_id, "use_classification", "1" if value else "0", "1" if value else "0")
|
||||
(room.room_id, setting, "1" if value else "0", "1" if value else "0")
|
||||
)
|
||||
|
||||
await bot.send_message(room, f"Alright, I've set use_classification to: '{value}'.", True)
|
||||
await bot.send_message(room, f"Alright, I've set {setting} to: '{value}'.", True)
|
||||
return
|
||||
|
||||
await bot.send_message(room, "You need to provide a boolean value (true/false).", True)
|
||||
return
|
||||
|
||||
bot.logger.log("Retrieving classification status...")
|
||||
bot.logger.log(f"Retrieving {setting} status for {room.room_id}...")
|
||||
|
||||
use_classification = bot.room_uses_classification(room)
|
||||
with bot.database.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT value FROM room_settings WHERE room_id = ? AND setting = ?;""",
|
||||
(room.room_id, setting)
|
||||
)
|
||||
|
||||
await bot.send_message(room, f"The current classification status is: '{use_classification}'.", True)
|
||||
value = cur.fetchone()[0]
|
||||
|
||||
if not value:
|
||||
if setting == "use_classification":
|
||||
value = False
|
||||
elif setting == "always_reply":
|
||||
value = True
|
||||
else:
|
||||
value = bool(int(value))
|
||||
|
||||
await bot.send_message(room, f"The current {setting} status is: '{value}'.", True)
|
||||
return
|
||||
|
||||
message = f"""
|
||||
The following settings are available:
|
||||
message = f"""The following settings are available:
|
||||
|
||||
- system_message [message]: Get or set the system message to be sent to the chat model
|
||||
- classification [true/false]: Get or set whether the room uses classification
|
||||
- always_reply [true/false]: Get or set whether the bot should reply to all messages (if false, only reply to mentions and commands)
|
||||
"""
|
||||
|
||||
await bot.send_message(room, message, True)
|
||||
|
|
Loading…
Reference in a new issue