最近、nlpに対処するために、大胆なgopnikのように話す簡単な電信ボットを作成するというアイデアを思いつきました。 それは:
- 「欲しい」、「短い」、「いいえ」などのトリガーワードで答えを出す。
- 質問に大胆な質問に答えます。
- わいせつな韻で答えます。
- 適切なものがなく、ボットが混乱している場合は、邪悪なフレーズで応答します。
実装には、ES6とFlowを備えたJavaScriptが選択されました。 おそらくPythonは、その下にnlp用のより安定したテスト済みのライブラリがあるため、よりうまくいくでしょう。 しかし、JSにはAz.jsがあり 、これで十分です。
Telegram APIを使用するために、 node-telegram-bot-apiが使用されました 。
注意、猫の下にはわいせつなスピーチと実装の詳細があります!
Telegram APIを使用した実装の部分はあまり面白くなく、すでに多くの記事がすでに書かれているので、省略します。
ボットが適切な答えを見つけようとするとすぐに始めます。 答えを見つけるための最初の方法は、トリガーワードです。
ユーザー:新しい車が欲しい!
ボット:欲求は無害です!
最初に、ペアのリスト[regexp, ]
ます。
const TRIGGERS = [ [/^[][]?$/i, ' , !'], [/^$/i, ' !'], [/^(||||)$/i, ' !'], ];
次に、ユーザーからのメッセージを単語に分割する必要があります。
const getWords = (text: string): string[] => Az.Tokens(text) .tokens .filter(({type}) => type === Az.Tokens.WORD) .map(({st, length}) => text.substr(st, length).toLowerCase());
すべてのトリガーを通過し、可能な答えを返します。
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; } } } };
とても簡単でした。 答えを見つける2番目の方法 -質問に対する大胆な質問に答える時が来ました:
ユーザー:いつ家に帰りますか?
ボット:一体何だ?
メッセージが質問であるかどうかを判断するには、最後に疑問符がないかどうか、いつ、どこで、などの質問語が存在するかどうかを確認する必要があります。
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 []; } };
そのため、質問の場合、ボットはハードコーディングされたconstants.ANSWER_TO_QUESTION
を返します。
答えを見つける3番目の方法は 、わいせつな韻での答えです。 この方法は最も困難です:
ユーザー:オーストリアに行きたい!
ボット:huyvstriya
ユーザー:彼はトラクターを持っています
ボット:huyaktor
要するに、名詞または形容詞の最初の音節を「hu」で置き換え、その音節から変換された母音を「o」→「e」、「a」→「i」などに置き換えるだけです。
まず、単語の最初の音節を取得できる必要があります。 これは簡単です:
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(''); };
次に、可能であれば、最初の音節を「hu」+母音に置き換える必要があります。
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}`; };
そして最後に、メッセージからの単語のすべての可能な韻を返します:
const getRhymes = (text: string): string[] => getWords(text) .map(getRhyme) .filter(Boolean) .reverse();
答えを見つける最後の方法は 、失礼なフレーズと混同して答えることです。
ユーザー:wtf
ボット:何?
このメソッドは単純ではないため、すべてのメソッドを集約する関数に実装されます。
export default (text: string): string[] => { const answers = uniq([ ...getByWordTrigger(text), ...getAnswerToQuestion(text), ...getRhymes(text), ]); if (answers.length) { return answers; } else { return constants.NO_ANSWERS; } };