Skip to content

Commit 2ba299b

Browse files
authored
Merge pull request #18 from Symphonic3/codex/define
Add define command backed by dictionary API meanings
2 parents 81c99fb + 9888638 commit 2ba299b

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

commands/define.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const { getMeanings } = require('../services/dictionary');
2+
3+
const MAX_MEANINGS = 8;
4+
const MAX_DEFINITIONS_PER_MEANING = 3;
5+
const MAX_MESSAGE_LENGTH = 1900;
6+
7+
function summarizeMeaning(meaning) {
8+
const definitions = meaning.definitions.slice(0, MAX_DEFINITIONS_PER_MEANING);
9+
if (!definitions.length)
10+
return null;
11+
12+
const partOfSpeech = meaning.partOfSpeech ? `${meaning.partOfSpeech}: ` : '';
13+
return `${partOfSpeech}${definitions.join(' | ')}`;
14+
}
15+
16+
function buildMeaningsMessage(term, meanings) {
17+
const summaries = meanings
18+
.map(summarizeMeaning)
19+
.filter(Boolean)
20+
.slice(0, MAX_MEANINGS);
21+
22+
const lines = [`Meanings for **${term}**:`];
23+
let added = 0;
24+
25+
for (let i = 0; i < summaries.length; i++) {
26+
const candidateLine = `${i + 1}. ${summaries[i]}`;
27+
const preview = `${lines.join('\n')}\n${candidateLine}`;
28+
29+
if (preview.length > MAX_MESSAGE_LENGTH)
30+
break;
31+
32+
lines.push(candidateLine);
33+
added++;
34+
}
35+
36+
const hiddenCount = Math.max(0, summaries.length - added) + Math.max(0, meanings.length - MAX_MEANINGS);
37+
if (hiddenCount > 0)
38+
lines.push(`...and ${hiddenCount} more meaning(s).`);
39+
40+
return lines.join('\n');
41+
}
42+
43+
async function defineCommand(message, args) {
44+
const term = args.join(' ').trim();
45+
46+
if (!term) {
47+
await message.channel.send(`Please provide a term. Example: \`${message.client.prefix}define bitcoin\``);
48+
return;
49+
}
50+
51+
let meanings;
52+
try {
53+
meanings = await getMeanings(term);
54+
} catch {
55+
await message.channel.send('Unable to fetch definitions right now. Please try again later.');
56+
return;
57+
}
58+
59+
if (meanings.length === 0) {
60+
await message.channel.send(`No meanings found for **${term}**.`);
61+
return;
62+
}
63+
64+
await message.channel.send(buildMeaningsMessage(term, meanings));
65+
}
66+
67+
module.exports = {
68+
define: {
69+
execute: defineCommand
70+
},
71+
def: {
72+
execute: defineCommand
73+
}
74+
};

services/dictionary.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const axios = require('axios');
2+
3+
const DICTIONARY_API_URL = 'https://api.dictionaryapi.dev/api/v2/entries/en/';
4+
5+
function normalizeMeaning(meaning) {
6+
const partOfSpeech = String(meaning?.partOfSpeech || '').trim();
7+
const definitions = Array.isArray(meaning?.definitions)
8+
? meaning.definitions
9+
.map(definition => String(definition?.definition || '').trim())
10+
.filter(Boolean)
11+
: [];
12+
13+
return {
14+
partOfSpeech,
15+
definitions
16+
};
17+
}
18+
19+
async function getMeanings(term) {
20+
const normalizedTerm = String(term || '').trim();
21+
if (!normalizedTerm)
22+
return [];
23+
24+
try {
25+
const response = await axios.get(`${DICTIONARY_API_URL}${encodeURIComponent(normalizedTerm)}`);
26+
const entries = Array.isArray(response.data) ? response.data : [];
27+
28+
return entries
29+
.flatMap(entry => Array.isArray(entry?.meanings) ? entry.meanings : [])
30+
.map(normalizeMeaning)
31+
.filter(meaning => meaning.definitions.length > 0);
32+
} catch (error) {
33+
if (error.response?.status === 404)
34+
return [];
35+
36+
throw new Error('Failed to fetch meanings.');
37+
}
38+
}
39+
40+
module.exports = {
41+
getMeanings
42+
};

0 commit comments

Comments
 (0)