diff --git a/.gitignore b/.gitignore index 64fb574..4596390 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea -bot-store/ -config.yaml +*-store/ +*.yaml +!config.sample.yaml # ---> Python # Byte-compiled / optimized / DLL files diff --git a/config.sample.yaml b/config.sample.yaml index 36bfe9c..c818432 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -34,3 +34,7 @@ autojoin_rooms: command_prefix: '!c' reply_in_thread: true + +# The system message helps set the behavior of the assistant. +# For example, you can instruct the assistant with "You are a helpful assistant." +system_prompt: \ No newline at end of file diff --git a/main.py b/main.py index 1b2e2d6..fd4ad3c 100755 --- a/main.py +++ b/main.py @@ -89,7 +89,7 @@ async def main(): storage = Storage(Path(config_data['data_storage'], 'matrixgpt.db')) # Set up event callbacks - callbacks = Callbacks(client, storage, config_data['command_prefix'], openai_config, config_data.get('reply_in_thread', False), config_data['allowed_to_invite'], config_data['allowed_to_chat']) + callbacks = Callbacks(client, storage, config_data['command_prefix'], openai_config, config_data.get('reply_in_thread', False), config_data['allowed_to_invite'], config_data['allowed_to_chat'], config_data.get('system_prompt')) client.add_event_callback(callbacks.message, RoomMessageText) client.add_event_callback(callbacks.invite_event_filtered_callback, InviteMemberEvent) client.add_event_callback(callbacks.decryption_failure, MegolmEvent) @@ -137,13 +137,13 @@ async def main(): except (ClientConnectionError, ServerDisconnectedError): logger.warning("Unable to connect to homeserver, retrying in 15s...") time.sleep(15) + except KeyboardInterrupt: + await client.close() + sys.exit() except Exception: logger.critical(traceback.format_exc()) logger.critical('Sleeping 5s...') time.sleep(5) - except KeyboardInterrupt: - await client.close() - sys.exit() if __name__ == "__main__": diff --git a/matrix_gpt/bot/bot_commands.py b/matrix_gpt/bot/bot_commands.py index ee9d46e..0c1d24a 100644 --- a/matrix_gpt/bot/bot_commands.py +++ b/matrix_gpt/bot/bot_commands.py @@ -2,7 +2,7 @@ import logging from nio import AsyncClient, MatrixRoom, RoomMessageText -from .chat_functions import get_thread_content, process_chat, send_text_to_room +from .chat_functions import process_chat, send_text_to_room # from .config import Config from .storage import Storage @@ -19,7 +19,8 @@ class Command: room: MatrixRoom, event: RoomMessageText, openai, - reply_in_thread + reply_in_thread, + system_prompt: str = None, ): """A command made by a user. @@ -45,6 +46,7 @@ class Command: self.args = self.command.split()[1:] self.openai = openai self.reply_in_thread = reply_in_thread + self.system_prompt = system_prompt async def process(self): """Process the command""" @@ -60,7 +62,7 @@ class Command: await self._process_chat() async def _process_chat(self): - await process_chat(self.client, self.room, self.event, self.command, self.store, self.openai) + await process_chat(self.client, self.room, self.event, self.command, self.store, self.openai, system_prompt=self.system_prompt) async def _show_help(self): """Show the help text""" diff --git a/matrix_gpt/bot/callbacks.py b/matrix_gpt/bot/callbacks.py index 605e0b1..1042151 100644 --- a/matrix_gpt/bot/callbacks.py +++ b/matrix_gpt/bot/callbacks.py @@ -13,7 +13,7 @@ logger = logging.getLogger('MatrixGPT') class Callbacks: - def __init__(self, client: AsyncClient, store: Storage, command_prefix: str, openai, reply_in_thread, allowed_to_invite, allowed_to_chat='all'): + def __init__(self, client: AsyncClient, store: Storage, command_prefix: str, openai, reply_in_thread, allowed_to_invite, allowed_to_chat='all', system_prompt: str = None, ): """ Args: client: nio client used to interact with matrix. @@ -31,6 +31,7 @@ class Callbacks: self.reply_in_thread = reply_in_thread self.allowed_to_invite = allowed_to_invite if allowed_to_invite else [] self.allowed_to_chat = allowed_to_chat + self.system_prompt = system_prompt async def message(self, room: MatrixRoom, event: RoomMessageText) -> None: """Callback for when a message event is received @@ -69,7 +70,7 @@ class Callbacks: # room.member_count > 2 ... we assume a public room # room.member_count <= 2 ... we assume a DM # General message listener - if not msg.startswith(self.command_prefix) and is_thread(event) and not self.store.check_seen_event(event.event_id): + if not msg.startswith(f'{self.command_prefix} ') and is_thread(event) and not self.store.check_seen_event(event.event_id): await self.client.room_typing(room.room_id, typing_state=True, timeout=3000) thread_content = await get_thread_content(self.client, room, event) api_data = [] @@ -80,9 +81,9 @@ class Callbacks: # message = Message(self.client, self.store, msg, room, event, self.reply_in_thread) # await message.process() api_data.append({'role': 'user', 'content': event.body}) - await process_chat(self.client, room, event, api_data, self.store, self.openai, thread_root_id=thread_content[0].event_id) + await process_chat(self.client, room, event, api_data, self.store, self.openai, thread_root_id=thread_content[0].event_id, system_prompt=self.system_prompt) return - elif msg.startswith(self.command_prefix) or room.member_count == 2: + elif msg.startswith(f'{self.command_prefix} ') or room.member_count == 2: # Otherwise if this is in a 1-1 with the bot or features a command prefix, # treat it as a command msg = event.body if not event.body.startswith(self.command_prefix) else event.body[len(self.command_prefix):].strip() # Remove the command prefix @@ -181,13 +182,13 @@ class Callbacks: event: The encrypted event that we were unable to decrypt. """ - logger.error(f"Failed to decrypt event '{event.event_id}' in room '{room.room_id}'!" - f"\n\n" - f"Tip: try using a different device ID in your config file and restart." - f"\n\n" - f"If all else fails, delete your store directory and let the bot recreate " - f"it (your reminders will NOT be deleted, but the bot may respond to existing " - f"commands a second time).") + # logger.error(f"Failed to decrypt event '{event.event_id}' in room '{room.room_id}'!" + # f"\n\n" + # f"Tip: try using a different device ID in your config file and restart." + # f"\n\n" + # f"If all else fails, delete your store directory and let the bot recreate " + # f"it (your reminders will NOT be deleted, but the bot may respond to existing " + # f"commands a second time).") red_x_and_lock_emoji = "❌ 🔐" diff --git a/matrix_gpt/bot/chat_functions.py b/matrix_gpt/bot/chat_functions.py index dac65a0..cbf0de3 100644 --- a/matrix_gpt/bot/chat_functions.py +++ b/matrix_gpt/bot/chat_functions.py @@ -184,7 +184,7 @@ async def get_thread_content(client: AsyncClient, room: MatrixRoom, base_event: return messages -async def process_chat(client, room, event, command, store, openai, thread_root_id: str = None): +async def process_chat(client, room, event, command, store, openai, thread_root_id: str = None, system_prompt: str = None): if not store.check_seen_event(event.event_id): await client.room_typing(room.room_id, typing_state=True, timeout=3000) # if self.reply_in_thread: @@ -196,6 +196,9 @@ async def process_chat(client, room, event, command, store, openai, thread_root_ messages = [ {'role': 'user', 'content': command}, ] + if system_prompt: + messages.insert(0, {"role": "system", "content": system_prompt}, ) + print(messages) response = openai['openai'].ChatCompletion.create( model=openai['model'],