import discord from discord import app_commands from discord.ext import commands from discord.ext.commands import Context import aiohttp def dictionary_command(): async def send_embed( context, embed: discord.Embed, *, ephemeral: bool = False ) -> None: interaction = getattr(context, "interaction", None) if interaction is not None: if interaction.response.is_done(): await interaction.followup.send(embed=embed, ephemeral=ephemeral) else: await interaction.response.send_message( embed=embed, ephemeral=ephemeral ) else: await context.send(embed=embed) async def fetch_definition(word: str) -> dict: try: url = f"https://api.dictionaryapi.dev/api/v2/entries/en/{word.lower()}" async with aiohttp.ClientSession() as session: async with session.get(url) as response: if response.status == 200: data = await response.json() return {"success": True, "data": data} elif response.status == 404: return {"success": False, "error": "Word not found"} else: return { "success": False, "error": f"API returned status code {response.status}", } except aiohttp.ClientError: return {"success": False, "error": "Network error occurred"} except Exception as e: return {"success": False, "error": "An unexpected error occurred"} @commands.hybrid_command( name="dictionary", description="Get the definition of a word", ) @app_commands.describe(word="The word to look up") async def dictionary(self, context, word: str = None): if not word or not word.strip(): if ( context.message and context.message.reference and context.message.reference.resolved ): replied_message = context.message.reference.resolved if hasattr(replied_message, "content") and replied_message.content: word = replied_message.content.strip().split()[0] else: embed = discord.Embed( title="Error", description="The replied message has no text content to look up.", color=0xE02B2B, ).set_author( name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp", ) await send_embed(context, embed, ephemeral=True) return else: embed = discord.Embed( title="Error", description="Please provide a word to look up or reply to a message with a word.", color=0xE02B2B, ).set_author( name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp" ) await send_embed(context, embed, ephemeral=True) return word = word.strip().split()[0] interaction = getattr(context, "interaction", None) if interaction is not None and not interaction.response.is_done(): await interaction.response.defer() result = await fetch_definition(word) if not result["success"]: error_message = result.get("error", "Unknown error") if error_message == "Word not found": description = f"Could not find a definition for **{word}**.\nPlease check the spelling and try again." else: description = f"Failed to fetch definition: {error_message}" embed = discord.Embed( title="Error", description=description, color=0xE02B2B, ).set_author( name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp" ) await send_embed(context, embed, ephemeral=True) return data = result["data"] if not data or len(data) == 0: embed = discord.Embed( title="Error", description=f"No definition found for **{word}**.", color=0xE02B2B, ).set_author( name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp" ) await send_embed(context, embed, ephemeral=True) return entry = data[0] word_title = entry.get("word", word) phonetic = entry.get("phonetic", "") origin = entry.get("origin", "") meanings = entry.get("meanings", []) embed = discord.Embed( title=f"Dictionary", description=f"**```{word_title}```**", color=0x7289DA, ) embed.set_author( name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp" ) if phonetic: embed.add_field(name="Pronunciation", value=f"`{phonetic}`", inline=False) max_meanings = 3 for idx, meaning in enumerate(meanings[:max_meanings]): part_of_speech = meaning.get("partOfSpeech", "").capitalize() definitions = meaning.get("definitions", []) if definitions: def_text = "" examples = [] for def_idx, definition in enumerate(definitions[:2], 1): def_line = definition.get("definition", "") example = definition.get("example", "") if def_line: def_text += f"{def_idx}. {def_line}\n" if example: examples.append(f"{def_idx}. {example}") if def_text: field_name = ( f"{part_of_speech}" if part_of_speech else f"Definition {idx + 1}" ) embed.add_field( name=field_name, value=def_text.strip(), inline=False ) if examples: example_text = "\n".join(examples) embed.add_field( name="Examples", value=example_text, inline=False ) if idx < len(meanings[:max_meanings]) - 1: embed.add_field(name="────────", value="", inline=False) if origin and len(origin) < 1000: embed.add_field(name="Origin", value=origin, inline=False) synonyms = [] antonyms = [] for meaning in meanings: for definition in meaning.get("definitions", []): synonyms.extend(definition.get("synonyms", [])) antonyms.extend(definition.get("antonyms", [])) if synonyms: synonym_text = ", ".join(synonyms[:10]) embed.add_field(name="Synonyms", value=synonym_text, inline=True) if antonyms: antonym_text = ", ".join(antonyms[:10]) embed.add_field(name="Antonyms", value=antonym_text, inline=True) await send_embed(context, embed) return dictionary