From a26e3ebf084774f1cc3b61b42459f00337674083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= Date: Sun, 22 Dec 2024 05:04:20 +0100 Subject: [PATCH] Add slash command --- .vscode/settings.json | 3 ++ main.py | 90 ++++++++++++++++++------------------------- misc.py | 66 +++++++++++++++++++++++++++++++ pyproject.toml | 7 +++- 4 files changed, 112 insertions(+), 54 deletions(-) create mode 100644 misc.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 2ecf3e8..1e96592 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,8 @@ "anewdawn", "asctime", "audioop", + "automerge", + "buildx", "docstrings", "dotenv", "forgefilip", @@ -17,6 +19,7 @@ "plubplub", "pycodestyle", "pydocstyle", + "pyproject", "PYTHONDONTWRITEBYTECODE", "PYTHONUNBUFFERED", "testpaths", diff --git a/main.py b/main.py index c5759f3..c59dfb0 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,6 @@ from __future__ import annotations import logging import os import sys -from typing import TYPE_CHECKING import hikari import lightbulb @@ -11,8 +10,7 @@ import openai from dotenv import load_dotenv from openai import OpenAI -if TYPE_CHECKING: - from openai.types.chat.chat_completion import ChatCompletion +from misc import chat, get_allowed_users, get_trigger_keywords logger: logging.Logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -26,49 +24,47 @@ if not discord_token or not openai_api_key: sys.exit(1) -bot = lightbulb.BotApp(token=discord_token, intents=hikari.Intents.GUILD_MESSAGES | hikari.Intents.GUILD_MESSAGE_TYPING) +bot = hikari.GatewayBot( + token=discord_token, + intents=hikari.Intents.GUILD_MESSAGES | hikari.Intents.GUILD_MESSAGE_TYPING, + logs="INFO", +) +bot_client: lightbulb.GatewayEnabledClient = lightbulb.client_from_app(bot) +bot.subscribe(hikari.StartingEvent, bot_client.start) + openai_client = OpenAI(api_key=openai_api_key) -def chat(user_message: str) -> str | None: - """Chat with the bot using the OpenAI API. +@bot_client.register(guilds=[hikari.Snowflake(98905546077241344), hikari.Snowflake(341001473661992962)]) +class Ask( + lightbulb.SlashCommand, + name="ask", + description="Ask the AI a question.", +): + """A command to ask the AI a question.""" - Args: - user_message: The message to send to OpenAI. + text: str = lightbulb.string("text", "The question or message to ask the AI.") - Returns: - The response from the AI model. - """ - completion: ChatCompletion = openai_client.chat.completions.create( - model="gpt-4o-mini", - messages=[ - { - "role": "developer", - "content": "You are in a Discord group chat with people above the age of 30. Use Discord Markdown to format messages if needed.", # noqa: E501 - }, - {"role": "user", "content": user_message}, - ], - ) - response: str | None = completion.choices[0].message.content - logger.info("AI response: %s", response) + @lightbulb.invoke + async def invoke(self, ctx: lightbulb.Context) -> None: + """Handle the /ask command.""" + user_message: str = self.text - return response + if not user_message: + await ctx.respond("You need to provide a question or message.") + return + try: + response: str | None = chat(user_message, openai_client) + except openai.OpenAIError as e: + logger.exception("An error occurred while chatting with the AI model.") + await ctx.respond(f"An error occurred: {e}") + return -def get_allowed_users() -> list[str]: - """Get the list of allowed users to interact with the bot. - - Returns: - The list of allowed users. - """ - return [ - "thelovinator", - "killyoy", - "forgefilip", - "plubplub", - "nobot", - "kao172", - ] + if response: + await ctx.respond(response) + else: + await ctx.respond("I forgor how to think 💀") @bot.listen(hikari.MessageCreateEvent) @@ -89,13 +85,13 @@ async def on_message(event: hikari.MessageCreateEvent) -> None: return lowercase_message: str = incoming_message.lower() if incoming_message else "" - trigger_keywords: list[str] = get_trigger_keywords() + trigger_keywords: list[str] = get_trigger_keywords(bot) if any(trigger in lowercase_message for trigger in trigger_keywords): logger.info("Received message: %s from: %s", incoming_message, event.author.username) async with bot.rest.trigger_typing(event.channel_id): try: - response: str | None = chat(incoming_message) + response: str | None = chat(incoming_message, openai_client) except openai.OpenAIError as e: logger.exception("An error occurred while chatting with the AI model.") e.add_note(f"Message: {incoming_message}\nEvent: {event}\nWho: {event.author.username}") @@ -112,18 +108,6 @@ async def on_message(event: hikari.MessageCreateEvent) -> None: await bot.rest.create_message(event.channel_id, "I forgor how to think 💀") -def get_trigger_keywords() -> list[str]: - """Get the list of trigger keywords to respond to. - - Returns: - The list of trigger keywords. - """ - bot_user: hikari.OwnUser | None = bot.get_me() - bot_mention_string: str = f"<@{bot_user.id}>" if bot_user else "" - notification_keywords: list[str] = ["lovibot", bot_mention_string] - return notification_keywords - - if __name__ == "__main__": logger.info("Starting the bot.") - bot.run(asyncio_debug=True, check_for_updates=True) + bot.run() diff --git a/misc.py b/misc.py new file mode 100644 index 0000000..0ae5fc9 --- /dev/null +++ b/misc.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import hikari + from openai import OpenAI + from openai.types.chat.chat_completion import ChatCompletion + + +logger: logging.Logger = logging.getLogger(__name__) + + +def get_allowed_users() -> list[str]: + """Get the list of allowed users to interact with the bot. + + Returns: + The list of allowed users. + """ + return [ + "thelovinator", + "killyoy", + "forgefilip", + "plubplub", + "nobot", + "kao172", + ] + + +def get_trigger_keywords(bot: hikari.GatewayBotAware) -> list[str]: + """Get the list of trigger keywords to respond to. + + Returns: + The list of trigger keywords. + """ + bot_user: hikari.OwnUser | None = bot.get_me() + bot_mention_string: str = f"<@{bot_user.id}>" if bot_user else "" + notification_keywords: list[str] = ["lovibot", bot_mention_string] + return notification_keywords + + +def chat(user_message: str, openai_client: OpenAI) -> str | None: + """Chat with the bot using the OpenAI API. + + Args: + user_message: The message to send to OpenAI. + openai_client: The OpenAI client to use. + + Returns: + The response from the AI model. + """ + completion: ChatCompletion = openai_client.chat.completions.create( + model="gpt-4o-mini", + messages=[ + { + "role": "developer", + "content": "You are in a Discord group chat with people above the age of 30. Use Discord Markdown to format messages if needed.", # noqa: E501 + }, + {"role": "user", "content": user_message}, + ], + ) + response: str | None = completion.choices[0].message.content + logger.info("AI response: %s", response) + + return response diff --git a/pyproject.toml b/pyproject.toml index 41535ca..92e2692 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,12 @@ version = "0.1.0" description = "My shit bot" readme = "README.md" requires-python = ">=3.13" -dependencies = ["hikari-lightbulb", "hikari", "openai", "python-dotenv"] +dependencies = [ + "hikari-lightbulb>=3.0.0a15", + "hikari", + "openai", + "python-dotenv", +] [dependency-groups] dev = ["pytest-asyncio", "pytest", "ruff"]