📜 ⬆️ ⬇️

Cheeky telegram bot

Recently, in trying to deal with nlp, I got the idea to write a simple telegram bot, which will speak like a cheeky gopnik. I.e:



JavaScript was implemented with ES6 and Flow for implementation. Perhaps Python would be better, since there are more stable and proven libraries for nlp under it. But for JS there is Az.js , which is quite enough.


To work with the Telegram API, node-telegram-bot-api was used .


TLDR: bot , source code


Carefully, there is obscene speech and implementation details under the cut!


The part with the implementation of the Telegram API is not very interesting, and many articles have already been written about this, and I’ll leave it out.


I'll start right away with how the bot is trying to find the right answer. The first method of finding an answer is the trigger word:


user: I want a new car!
bot: Want to be harmless!

First we have a list of pairs [regexp, ] :


 const TRIGGERS = [ [/^[][]?$/i, '  ,   !'], [/^$/i, ' !'], [/^(||||)$/i, ' !'], ]; 

Then we have to break the message from the user into words:


 const getWords = (text: string): string[] => Az.Tokens(text) .tokens .filter(({type}) => type === Az.Tokens.WORD) .map(({st, length}) => text.substr(st, length).toLowerCase()); 

Go through all the triggers and return possible answers:


 const getByWordTrigger = function*(text: string): Iterable<string> { for (const word of getWords(text)) { for (const [regexp, answer] of constants.TRIGGERS) { if (word.match(regexp)) { yield answer; } } } }; 

It came out very simple. Now the time has come for the second method of finding an answer - to answer the question with a bold question:


user: When will we go home?
bot: Are you fucking?

In order to determine whether a message is a question, we need to check it for the presence of a question mark at the end and for the presence of question words like "when", "where", etc .:


 const getAnswerToQuestion = (text: string): string[] => { if (text.trim().endsWith('?')) { return [constants.ANSWER_TO_QUESTION]; } const questionWords = getWords(text) .map((word) => Az.Morph(word)) .filter((morphs) => morphs.length && morphs[0].tag.Ques); if (questionWords.length) { return [constants.ANSWER_TO_QUESTION]; } else { return []; } }; 

So, in case of a question, the bot will return a hard-core constants.ANSWER_TO_QUESTION .


The third method of finding the answer - the answer obscene rhyme. This method is the most difficult:


user: I want to go to Austria!
bot: hyavstria
user: he has a tractor
bot: huyaktor

In short: we simply replace the first syllable of a noun or adjective with "xy" and a transformed vowel from a syllable, like "o" → "", "a" → "i", etc.


To begin, we must be able to get the first syllable of the word. It is not difficult:


 const getFirstSyllable = (word: string): string => { const result = []; let readVowel = false; for (const letter of word) { const isVowel = constants.VOWELS.indexOf(letter) !== -1; if (readVowel && !isVowel) { break; } if (isVowel) { readVowel = true; } result.push(letter); } return result.join(''); }; 

Then you need to replace the first syllable with "xy" + vowel, if possible:


 const getRhyme = (word: string): ?string => { const morphs = Az.Morph(word); if (!morphs.length) { return; } const {tag} = morphs[0]; if (!tag.NOUN && !tag.ADJF) { return; } const syllable = getFirstSyllable(word); if (!syllable || syllable === word) { return; } const prefix = constants.VOWEL_TO_RHYME[last(syllable)]; const postfix = word.substr(syllable.length); return `${prefix}${postfix}`; }; 

And finally, return all possible rhymes for words from the message:


 const getRhymes = (text: string): string[] => getWords(text) .map(getRhyme) .filter(Boolean) .reverse(); 

The final method of finding an answer is to respond in confusion with a rude phrase:


user: wtf
bot: what?

This method is more than simple, so it will be implemented in the function aggregating all methods:


 export default (text: string): string[] => { const answers = uniq([ ...getByWordTrigger(text), ...getAnswerToQuestion(text), ...getRhymes(text), ]); if (answers.length) { return answers; } else { return constants.NO_ANSWERS; } }; 

And it's all. Bot , source code .


')

Source: https://habr.com/ru/post/327586/


All Articles