148 lines
5.2 KiB
Python
148 lines
5.2 KiB
Python
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 <word>`")
|
|
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))
|