replace lexicala with wordnik

This commit is contained in:
Evert Prants 2021-09-15 21:50:28 +03:00
parent 4f887e3331
commit 2b42fb63f4
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
3 changed files with 137 additions and 67 deletions

View File

@ -2,7 +2,7 @@
"main": "plugin.js", "main": "plugin.js",
"name": "diction", "name": "diction",
"description": "Find definitions for words", "description": "Find definitions for words",
"version": "1.1.0", "version": "1.2.1",
"tags": ["commands", "utility", "dictionary"], "tags": ["commands", "utility", "dictionary"],
"dependencies": ["simplecommands"], "dependencies": ["simplecommands"],
"npmDependencies": [] "npmDependencies": []

View File

@ -8,28 +8,60 @@ import {
} from '@squeebot/core/lib/plugin'; } from '@squeebot/core/lib/plugin';
import { IMessage, MessageResolver } from '@squeebot/core/lib/types'; import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
const poslist = [ interface IDefinition {
'noun', partOfSpeech: string;
'verb', text: string;
'adjective', }
'adverb',
'participle', interface IWordCache {
'article', lastIndex: {
'pronoun', name: string;
'preposition', index: number;
'conjunction', lastTime: number;
'interjection', }[];
'determiner', definitions: IDefinition[];
]; inserted: number;
}
let lastQuery = 0; let lastQuery = 0;
const wordCache: Record<string, IWordCache> = {};
/**
* Find and remove words that haven't been looked up for a day
*/
function flushCache() {
let oldestWords: string[] = [];
Object.keys(wordCache).forEach((word) => {
const cached = wordCache[word];
let notOld = false;
for (const person of cached.lastIndex) {
if (person.lastTime > Date.now() - 24 * 60 * 60 * 1000) {
notOld = true;
break;
}
}
if (!notOld) {
oldestWords.push(word);
}
});
if (!oldestWords.length) {
return;
}
oldestWords.forEach((item) => {
delete wordCache[item];
});
logger.log(`[diction] Dictionary cleared of the previous words ${oldestWords.join(', ')}.`);
}
@Configurable({ @Configurable({
lexicala: { wordnik: '',
username: '',
password: '',
},
cooldown: 5, cooldown: 5,
limit: 5,
}) })
class DictionPlugin extends Plugin { class DictionPlugin extends Plugin {
@EventListener('pluginUnload') @EventListener('pluginUnload')
@ -41,13 +73,12 @@ class DictionPlugin extends Plugin {
@DependencyLoad('simplecommands') @DependencyLoad('simplecommands')
addCommands(cmd: any): void { addCommands(cmd: any): void {
const user = this.config.get('lexicala.username'); const key = this.config.get('wordnik');
const passwd = this.config.get('lexicala.password');
const rate = this.config.get('cooldown', 5); const rate = this.config.get('cooldown', 5);
const rauth = 'Basic ' + Buffer.from(`${user}:${passwd}`).toString('base64'); const limit = this.config.get('limit', 5);
if (!user || !passwd) { if (!key) {
logger.warn('Lexicala define command is disabled due to no credentials.'); logger.warn('Wordnik define command is disabled due to no credentials.');
return; return;
} }
@ -55,66 +86,105 @@ class DictionPlugin extends Plugin {
name: 'define', name: 'define',
plugin: this.name, plugin: this.name,
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => { execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
if (lastQuery > Date.now() - rate * 1000) { const word = simplified.join(' ');
msg.resolve('You\'re doing that too fast!');
return true;
}
let pos: string | null = simplified[0];
if (pos && poslist.indexOf(pos.toLowerCase()) !== -1 && simplified.length > 1) {
pos = '&pos=' + pos;
} else {
pos = '';
}
const word = encodeURIComponent(simplified.slice(pos ? 1 : 0).join(' '));
if (!word) { if (!word) {
msg.resolve('Please specifiy a word or term!'); msg.resolve('Please specifiy a word or term!');
return true; return true;
} }
if (lastQuery > Date.now() - rate * 1000 && !wordCache[word]) {
msg.resolve('You\'re doing that too fast!');
return true;
}
let chosenDefinition: IDefinition;
let definitionCount = 0;
let definitionIndex = 0;
// Check cached definitions
const userTarget = msg.fullSenderID as string;
if (wordCache[word]) {
const cached = wordCache[word];
const alreadyAsked = cached.lastIndex.find((item) => item.name === userTarget);
definitionCount = cached.definitions.length;
if (alreadyAsked) {
let nextI = alreadyAsked.index + 1;
if (nextI >= cached.definitions.length) {
nextI = 0;
}
if (alreadyAsked.lastTime < Date.now() - 5 * 60 * 1000) {
nextI = 0;
}
alreadyAsked.lastTime = Date.now();
alreadyAsked.index = nextI;
definitionIndex = nextI;
chosenDefinition = cached.definitions[nextI];
} else {
chosenDefinition = cached.definitions[0];
cached.lastIndex.push({
name: userTarget,
index: 0,
lastTime: Date.now(),
});
}
} else {
// Request definition
const encodedWord = encodeURIComponent(word);
lastQuery = Date.now(); lastQuery = Date.now();
let response; let response;
try { try {
const s = `https://dictapi.lexicala.com/search?source=global&language=en${pos}&text=${word}`; const s = `https://api.wordnik.com/v4/word.json/${encodedWord}/definitions?limit=${limit}&api_key=${key}`;
response = await httpGET(s, { Authorization: rauth }); response = await httpGET(s);
response = JSON.parse(response); response = JSON.parse(response);
} catch (e) { } catch (e) {
msg.resolve('Server did not respond.'); msg.resolve('Server did not respond.');
return true; return true;
} }
if (!response.n_results || response.n_results === 0 || !response.results) { if (!response || !response.length) {
msg.resolve('Nothing found.'); msg.resolve('No definitions found.');
return true; return true;
} }
const resolve = []; const cached: IWordCache = {
for (const def of response.results) { lastIndex: [
const wd = def.headword.text; {
const wdp = def.headword.pos; name: userTarget,
const results = def.senses.map((rep: any) => rep.definition).slice(0, 4); index: 0,
lastTime: Date.now(),
resolve.push({ }
word: wd, ],
type: wdp, definitions: (response as Record<string, string>[]).map(({ partOfSpeech, text }) => ({
results, partOfSpeech, text: text.replace(/(<([^>]+)>)/ig, '')
}); })),
inserted: Date.now(),
} }
const str = resolve.slice(0, 4).map((rep: any) => { wordCache[word] = cached;
return `${rep.word} (${rep.type}):\n` + rep.results.join('\n'); chosenDefinition = cached.definitions[0];
}).join('\n'); definitionCount = cached.definitions.length;
logger.log(`[diction] Dictionary cached the word "${word}"`);
flushCache();
}
const { partOfSpeech, text } = chosenDefinition;
msg.resolve(`(${definitionIndex + 1}/${definitionCount}) ${word}${
partOfSpeech ? ` - ${partOfSpeech}` : ''
} - ${text}`);
msg.resolve(str);
return true; return true;
}, },
match: /define (\w*)/, match: /define (\w*)/,
aliases: ['df'], aliases: ['df'],
description: 'Find definitions for words', description: 'Find definitions for words. Call again to advance to next definition',
usage: '[<pos>] <word>' usage: '<word>'
}); });
} }
} }

View File

@ -11,7 +11,7 @@
}, },
{ {
"name": "diction", "name": "diction",
"version": "1.1.0" "version": "1.2.1"
}, },
{ {
"name": "fun", "name": "fun",