diff --git a/.env-example b/.env-example index 3849404b..81f69c54 100644 --- a/.env-example +++ b/.env-example @@ -18,3 +18,5 @@ EMOJI_TRASHCAN="" ROLE_STEERING_COUNCIL="" ROLE_MODERATORS="" ROLE_DEVOPS="" + +WOLFRAM_TOKEN="" diff --git a/bot/constants.py b/bot/constants.py index b6081ee5..6e22aebb 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -87,6 +87,10 @@ class Roles(NamedTuple): events = int(os.getenv("EVENTS_ID", 890656665328820224)) +class Tokens(NamedTuple): + wolfram_token = os.getenv("WOLFRAM_TOKEN") + + # Bot replies with pathlib.Path("bot/resources/bot_replies.yml").open(encoding="utf8") as file: bot_replies = yaml.safe_load(file) @@ -94,6 +98,7 @@ class Roles(NamedTuple): POSITIVE_REPLIES = bot_replies["POSITIVE_REPLIES"] NEGATIVE_REPLIES = bot_replies["NEGATIVE_REPLIES"] + # Minecraft Server class Minecraft(NamedTuple): server_address = "mc.gurkult.com" diff --git a/bot/exts/fun/wolfram.py b/bot/exts/fun/wolfram.py new file mode 100644 index 00000000..6513a2b8 --- /dev/null +++ b/bot/exts/fun/wolfram.py @@ -0,0 +1,94 @@ +import random +from io import BytesIO +from typing import Literal, Union +from urllib import parse + +import disnake +from disnake import Embed +from disnake.ext import commands + +from bot.constants import ERROR_REPLIES, Colours, Tokens + + +class WolframCommands(commands.Cog): + """ + Wolfram Category cog, containing commands related to the WolframAlpha API. + + Commands + └ image Fetch the response to a query in the form of an image. + """ + + def __init__(self, bot: commands.Bot) -> None: + self.bot = bot + self.image_url = "https://api.wolframalpha.com/v1/simple" + self.params = { + "appid": Tokens.wolfram_token, + "background": "2F3136", + "foreground": "white", + "layout": "labelbar", + "fontsize": "23", + "width": "700", + "location": "the moon", + "latlong": "0.0,0.0", + "ip": "1.1.1.1", + } + + async def web_request(self, url: str, params: dict) -> Union[bytes, str]: + """Web request handler for wolfram group of commands.""" + async with self.bot.http_session.get(url=url, params=params) as resp: + if resp.status == 200: + return await resp.read() + elif resp.status == 501: + return "Sorry, the API could not understand your input" + elif resp.status == 400: + return "Sorry, the API did not find any input to interpret" + + @commands.slash_command() + async def wolfram(self, inter: disnake.ApplicationCommandInteraction) -> None: + """Commands for wolfram.""" + + @wolfram.sub_command() + async def image( + self, + inter: disnake.ApplicationCommandInteraction, + query: str, + theme: Literal["light", "dark"] = "dark", + ) -> None: + """ + Send wolfram image corresponding to the given query. + + Parameters + ---------- + query: The user query. + theme: The theme of the image generated. dark by default. + """ + await inter.response.defer() + + params = self.params + + if theme == "light": + params |= {"background": "white", "foreground": "2F3136"} + + response = await self.web_request( + url=self.image_url, params=params | {"i": query} + ) + + if isinstance(response, str): + embed = Embed(title=random.choice(ERROR_REPLIES), description=response) + else: + original_url = parse.quote_plus(query) + file = disnake.File(BytesIO(response), filename="image.png") + + embed = Embed(title="Wolfram Alpha", colour=Colours.green) + embed.set_image(file=file) + embed.add_field( + name="Cannot see image?", + value=f"[Click here](https://www.wolframalpha.com/input/?i={original_url})", + ) + + await inter.edit_original_message(embed=embed) + + +def setup(bot: commands.Bot) -> None: + """Load the Wolfram cog.""" + bot.add_cog(WolframCommands(bot))