diff --git a/package-lock.json b/package-lock.json index 0f6cee8..b5de5bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3,11 +3,24 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@types/doublearray": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/doublearray/-/doublearray-0.0.29.tgz", + "integrity": "sha1-PL5rthavUkZI1EC733hOnB40AJ0=" + }, "@types/events": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" }, + "@types/kuromoji": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@types/kuromoji/-/kuromoji-0.1.0.tgz", + "integrity": "sha512-gEAkIk4qxsK5ry64fCYFGjb3a+NQVOiNOT6fz0OyXizob+yewF4GFVX23GG4YNwKM2hB0J6fnMPMffFK+cYHnw==", + "requires": { + "@types/doublearray": "*" + } + }, "@types/lokijs": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/lokijs/-/lokijs-1.5.2.tgz", @@ -82,6 +95,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -180,6 +201,11 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "doublearray": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/doublearray/-/doublearray-0.0.2.tgz", + "integrity": "sha1-Yxhv6NNEEydtNiH2qg7F954ifvk=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -314,6 +340,16 @@ "verror": "1.10.0" } }, + "kuromoji": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/kuromoji/-/kuromoji-0.1.2.tgz", + "integrity": "sha512-V0dUf+C2LpcPEXhoHLMAop/bOht16Dyr+mDiIE39yX3vqau7p80De/koFqpiTcL1zzdZlc3xuHZ8u5gjYRfFaQ==", + "requires": { + "async": "^2.0.1", + "doublearray": "0.0.2", + "zlibjs": "^0.3.1" + } + }, "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", @@ -599,6 +635,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=" + }, + "zlibjs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz", + "integrity": "sha1-UBl+2yihxCymWcyLTmqd3W1ERVQ=" } } } diff --git a/package.json b/package.json index 7ca8d9a..5f8f099 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,13 @@ "build": "tsc" }, "dependencies": { + "@types/kuromoji": "0.1.0", "@types/lokijs": "1.5.2", "@types/node": "10.0.5", "@types/promise-retry": "1.1.2", "@types/seedrandom": "2.4.27", "@types/ws": "5.1.2", + "kuromoji": "0.1.2", "lokijs": "1.5.5", "misskey-reversi": "0.0.5", "promise-retry": "1.1.1", diff --git a/src/ai.ts b/src/ai.ts index b1d4839..39b3889 100644 --- a/src/ai.ts +++ b/src/ai.ts @@ -129,7 +129,7 @@ export default class 藍 { }, param)); } - public api = (endpoint: string, param) => { + public api = (endpoint: string, param?: any) => { return request.post(`${config.apiUrl}/${endpoint}`, { json: Object.assign({ i: config.i diff --git a/src/config.ts b/src/config.ts index 43edba5..29b19a5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,7 +3,9 @@ type Config = { i: string; wsUrl: string; apiUrl: string; + keywordEnabled: boolean; reversiEnabled: boolean; + mecabDic?: string; }; const config = require('../config.json'); diff --git a/src/index.ts b/src/index.ts index 58083ae..0ea4fbd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import PingModule from './modules/ping'; import EmojiModule from './modules/emoji'; import FortuneModule from './modules/fortune'; import GuessingGameModule from './modules/guessing-game'; +import KeywordModule from './modules/keyword'; import * as request from 'request-promise-native'; const promiseRetry = require('promise-retry'); @@ -24,4 +25,5 @@ promiseRetry(retry => { ai.install(new GuessingGameModule()); ai.install(new ServerModule()); ai.install(new ReversiModule()); + if (config.keywordEnabled) ai.install(new KeywordModule()); }); diff --git a/src/modules/keyword/index.ts b/src/modules/keyword/index.ts new file mode 100644 index 0000000..67edf4c --- /dev/null +++ b/src/modules/keyword/index.ts @@ -0,0 +1,60 @@ +import 藍 from '../../ai'; +import IModule from '../../module'; +import config from '../../config'; +import * as kuromoji from 'kuromoji'; +import MessageLike from '../../message-like'; +import serifs from '../../serifs'; + +export default class KeywordModule implements IModule { + public name = 'keyword'; + + private ai: 藍; + private tokenizer: kuromoji.Tokenizer; + + public install = (ai: 藍) => { + this.ai = ai; + + kuromoji.builder({ + dicPath: config.mecabDic + }).build((err, tokenizer) => { + if (err) { + console.error(err); + } else { + this.tokenizer = tokenizer; + + setTimeout(this.say, 1000 * 60 * 60); + } + }); + } + + private say = async () => { + const tl = await this.ai.api('notes/local-timeline'); + + const interestedNotes = tl.filter(note => note.userId !== this.ai.account.id && note.text != null); + + let keywords: kuromoji.IpadicFeatures[] = []; + + interestedNotes.forEach(note => { + const tokens = this.tokenizer.tokenize(note.text); + const keywordsInThisNote = tokens.filter(token => token.pos_detail_1 == '固有名詞'); + keywords = keywords.concat(keywordsInThisNote); + }); + + console.log(keywords); + + const keyword = keywords[Math.floor(Math.random() * keywords.length)]; + + this.ai.post(serifs.KEYWORD + .replace('{word}', keyword.surface_form) + .replace('{reading}', keyword.reading)); + } + + public onMention = (msg: MessageLike) => { + if (msg.user.isAdmin && msg.text && msg.text.includes('なんか言って')) { + this.say(); + return true; + } else { + return false; + } + } +} diff --git a/src/serifs.ts b/src/serifs.ts index f115d94..ca5639c 100644 --- a/src/serifs.ts +++ b/src/serifs.ts @@ -86,4 +86,9 @@ export default { * 数当てゲームで正解したとき */ GUESSINGGAME_CONGRATS: '正解です🎉 ({tries}回目で当てました)', + + /** + * キーワード + */ + KEYWORD: '({word}... {reading}...)', };