diff --git a/cogs/dictionary_cog.py b/cogs/dictionary_cog.py new file mode 100644 index 0000000..106ec28 --- /dev/null +++ b/cogs/dictionary_cog.py @@ -0,0 +1,149 @@ +import discord +from discord.ext import commands +from discord import app_commands +import aiohttp +import logging +from typing import Optional, List, Dict, Any + +log = logging.getLogger(__name__) + +class DictionaryCog(commands.Cog, name="Dictionary"): + """Cog for word definition and dictionary lookup commands""" + + def __init__(self, bot): + self.bot = bot + self.api_base_url = "https://api.dictionaryapi.dev/api/v2/entries/en" + + async def _fetch_definition(self, word: str) -> Optional[Dict[str, Any]]: + """Fetch word definition from the Free Dictionary API.""" + try: + async with aiohttp.ClientSession() as session: + url = f"{self.api_base_url}/{word.lower()}" + async with session.get(url) as response: + if response.status == 200: + data = await response.json() + return data[0] if data else None + elif response.status == 404: + return None + else: + log.error(f"Dictionary API returned status {response.status} for word '{word}'") + return None + except Exception as e: + log.error(f"Error fetching definition for '{word}': {e}") + return None + + def _format_definition_embed(self, word: str, data: Dict[str, Any]) -> discord.Embed: + """Format the dictionary data into a Discord embed.""" + embed = discord.Embed( + title=f"📖 Definition: {data.get('word', word).title()}", + color=discord.Color.blue() + ) + + # Add phonetic pronunciation if available + phonetics = data.get('phonetics', []) + if phonetics: + for phonetic in phonetics: + if phonetic.get('text'): + embed.add_field( + name="🔊 Pronunciation", + value=phonetic['text'], + inline=True + ) + break + + # Add meanings + meanings = data.get('meanings', []) + definition_count = 0 + + for meaning in meanings[:3]: # Limit to first 3 parts of speech + part_of_speech = meaning.get('partOfSpeech', 'Unknown') + definitions = meaning.get('definitions', []) + + if definitions: + definition_text = definitions[0].get('definition', 'No definition available') + example = definitions[0].get('example') + + field_value = f"**{definition_text}**" + if example: + field_value += f"\n*Example: {example}*" + + embed.add_field( + name=f"📝 {part_of_speech.title()}", + value=field_value, + inline=False + ) + definition_count += 1 + + # Add etymology if available + etymology = data.get('etymology') + if etymology: + embed.add_field( + name="📚 Etymology", + value=etymology[:200] + "..." if len(etymology) > 200 else etymology, + inline=False + ) + + # Add source attribution + embed.set_footer(text="Powered by Free Dictionary API") + + return embed + + async def _define_logic(self, word: str) -> Dict[str, Any]: + """Core logic for the define command.""" + if not word or len(word.strip()) == 0: + return { + "error": "Please provide a word to define.", + "embed": None + } + + # Clean the word input + clean_word = word.strip().lower() + + # Fetch definition + definition_data = await self._fetch_definition(clean_word) + + if definition_data is None: + return { + "error": f"❌ Sorry, I couldn't find a definition for '{word}'. Please check the spelling and try again.", + "embed": None + } + + # Create embed + embed = self._format_definition_embed(word, definition_data) + + return { + "error": None, + "embed": embed + } + + # --- Prefix Command --- + @commands.command(name="define", aliases=["def", "definition"]) + async def define(self, ctx: commands.Context, *, word: str = None): + """Look up the definition of a word.""" + if word is None: + await ctx.reply("Please provide a word to define. Usage: `!define `") + return + + result = await self._define_logic(word) + + if result["error"]: + await ctx.reply(result["error"]) + else: + await ctx.reply(embed=result["embed"]) + + # --- Slash Command --- + @app_commands.command(name="define", description="Look up the definition of a word") + @app_commands.describe(word="The word you want to define") + async def define_slash(self, interaction: discord.Interaction, word: str): + """Slash command for word definition lookup.""" + await interaction.response.defer() + + result = await self._define_logic(word) + + if result["error"]: + await interaction.followup.send(result["error"]) + else: + await interaction.followup.send(embed=result["embed"]) + +async def setup(bot: commands.Bot): + await bot.add_cog(DictionaryCog(bot)) diff --git a/cogs/help_cog.py b/cogs/help_cog.py index 34f6b2d..9dff55f 100644 --- a/cogs/help_cog.py +++ b/cogs/help_cog.py @@ -7,6 +7,7 @@ import asyncio COG_DISPLAY_NAMES = { "AICog": "🤖 AI Chat", "AudioCog": "🎵 Audio Player", + "DictionaryCog": "📖 Dictionary", "GamesCog": "🎮 Games", "HelpCog": "❓ Help", "MultiConversationCog": "🤖 Multi-Conversation AI Chat", diff --git a/neru_bot.py b/neru_bot.py index 047112d..dd68f87 100644 --- a/neru_bot.py +++ b/neru_bot.py @@ -105,6 +105,7 @@ class NeruBot(commands.Bot): "cogs.shell_command_cog", "cogs.marriage_cog", "cogs.upload_cog", + "cogs.dictionary_cog", ] # Load each cog individually