From 805b25bb51a2a3bd6082fc32edec89f3de4a2d7f Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 27 Aug 2018 06:59:18 +0900 Subject: [PATCH] Improve AI --- src/ai.ts | 30 ++++++++++- src/index.ts | 6 ++- src/module.ts | 2 +- src/modules/core/index.ts | 100 +++++++++++++++++++++++++++++++++++++ src/modules/timer/index.ts | 3 +- src/serifs.ts | 13 ++++- 6 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/modules/core/index.ts diff --git a/src/ai.ts b/src/ai.ts index f8ac972..b16d247 100644 --- a/src/ai.ts +++ b/src/ai.ts @@ -35,6 +35,12 @@ export default class 藍 { userId?: string; module: string; key: string; + data?: any; + }>; + + public friends: loki.Collection<{ + userId: string; + name?: string; }>; constructor(account: any) { @@ -56,6 +62,13 @@ export default class 藍 { indices: ['key'] }); } + + this.friends = this.db.getCollection('friends'); + if (this.friends === null) { + this.friends = this.db.addCollection('friends', { + indices: ['userId'] + }); + } //#endregion // Install modules @@ -108,6 +121,17 @@ export default class 藍 { this.modules.push(module); } + /** + * 指定したユーザーの「呼んでもらいたい名前」を取得します + */ + public getName = (userId: string) => { + const friend = this.friends.findOne({ + userId: userId + }); + + return friend != null ? friend.name : null; + } + private onMessage = (msg: any) => { switch (msg.type) { // メンションされたとき @@ -172,7 +196,7 @@ export default class 藍 { if (context != null) { const module = this.modules.find(m => m.name == context.module); - module.onReplyThisModule(msg); + module.onReplyThisModule(msg, context.data); } else { this.modules.filter(m => m.hasOwnProperty('onMention')).some(m => { return m.onMention(msg); @@ -199,17 +223,19 @@ export default class 藍 { }); }; - public subscribeReply = (module: IModule, key: string, isMessage: boolean, id: string) => { + public subscribeReply = (module: IModule, key: string, isMessage: boolean, id: string, data?: any) => { this.contexts.insertOne(isMessage ? { isMessage: true, userId: id, module: module.name, key: key, + data: data } : { isMessage: false, noteId: id, module: module.name, key: key, + data: data }); } diff --git a/src/index.ts b/src/index.ts index 73990e5..db770fe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import 藍 from './ai'; import config from './config'; +import CoreModule from './modules/core'; import ReversiModule from './modules/reversi'; import ServerModule from './modules/server'; import PingModule from './modules/ping'; @@ -14,7 +15,7 @@ import TimerModule from './modules/timer'; import * as request from 'request-promise-native'; const promiseRetry = require('promise-retry'); -console.log('starting ai...'); +console.log('--- starting ai... ---'); promiseRetry(retry => { return request.post(`${config.apiUrl}/i`, { @@ -27,6 +28,7 @@ promiseRetry(retry => { const ai = new 藍(account); + ai.install(new CoreModule()); ai.install(new PingModule()); ai.install(new WelcomeModule()); ai.install(new EmojiModule()); @@ -37,5 +39,5 @@ promiseRetry(retry => { if (config.serverMonitoring) ai.install(new ServerModule()); if (config.keywordEnabled) ai.install(new KeywordModule()); - console.log('ai started'); + console.log('--- ai started! ---'); }); diff --git a/src/module.ts b/src/module.ts index 27b6622..672214c 100644 --- a/src/module.ts +++ b/src/module.ts @@ -6,5 +6,5 @@ export default interface IModule { install?: (ai: 藍) => void; onMention?: (msg: MessageLike) => boolean; onLocalNote?: (note: any) => void; - onReplyThisModule?: (msg: MessageLike) => void; + onReplyThisModule?: (msg: MessageLike, data?: any) => void; } diff --git a/src/modules/core/index.ts b/src/modules/core/index.ts new file mode 100644 index 0000000..cb319dc --- /dev/null +++ b/src/modules/core/index.ts @@ -0,0 +1,100 @@ +import * as loki from 'lokijs'; +import 藍 from '../../ai'; +import IModule from '../../module'; +import MessageLike from '../../message-like'; +import serifs from '../../serifs'; + +export default class CoreModule implements IModule { + public name = 'core'; + private ai: 藍; + + public install = (ai: 藍) => { + this.ai = ai; + } + + public onMention = (msg: MessageLike) => { + if (msg.text && msg.text.includes('って呼んで') && !msg.text.startsWith('って呼んで')) { + let friend = this.ai.friends.findOne({ + userId: msg.userId + }); + + if (friend == null) { + friend = this.ai.friends.insertOne({ + userId: msg.userId + }); + } + + const name = msg.text.match(/^(.+?)って呼んで/)[1]; + + const withSan = + name.endsWith('さん') || + name.endsWith('くん') || + name.endsWith('君') || + name.endsWith('ちゃん') || + name.endsWith('様'); + + if (withSan) { + friend.name = name; + this.ai.friends.update(friend); + msg.reply(serifs.core.setNameOk.replace('{name}', name)); + } else { + msg.reply(serifs.core.san).then(reply => { + this.ai.subscribeReply(this, msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id, { + friend: friend, + name: name + }); + }); + } + + return true; + } else if (msg.text && msg.text.includes('おはよう')) { + const friend = this.ai.friends.findOne({ + userId: msg.userId + }); + + if (friend && friend.name) { + msg.reply(serifs.core.goodMorningWithName.replace('{name}', friend.name)); + } else { + msg.reply(serifs.core.goodMorning); + } + + return true; + } else if (msg.text && msg.text.includes('おやすみ')) { + const friend = this.ai.friends.findOne({ + userId: msg.userId + }); + + if (friend && friend.name) { + msg.reply(serifs.core.goodNightWithName.replace('{name}', friend.name)); + } else { + msg.reply(serifs.core.goodNight); + } + + return true; + } else { + return false; + } + } + + public onReplyThisModule = (msg: MessageLike, data: any) => { + if (msg.text == null) return; + + const done = () => { + this.ai.friends.update(data.friend); + msg.reply(serifs.core.setNameOk.replace('{name}', data.friend.name)); + this.ai.unsubscribeReply(this, msg.userId); + }; + + if (msg.text.includes('はい')) { + data.friend.name = data.name + 'さん'; + done(); + } else if (msg.text.includes('いいえ')) { + data.friend.name = data.name; + done(); + } else { + msg.reply(serifs.core.yesOrNo).then(reply => { + this.ai.subscribeReply(this, msg.userId, msg.isMessage, reply.id, data); + }); + } + } +} diff --git a/src/modules/timer/index.ts b/src/modules/timer/index.ts index 71fe1c4..50cd33b 100644 --- a/src/modules/timer/index.ts +++ b/src/modules/timer/index.ts @@ -35,8 +35,9 @@ export default class TimerModule implements IModule { const str = `${hours ? hoursQuery[0] : ''}${minutes ? minutesQuery[0] : ''}${seconds ? secondsQuery[0] : ''}`; setTimeout(() => { + const name = this.ai.getName(msg.userId); this.ai.sendMessage(msg.userId, { - text: serifs.timer.notify.replace('{time}', str) + text: name ? serifs.timer.notifyWithName.replace('{time}', str).replace('{name}', name) : serifs.timer.notify.replace('{time}', str) }); }, time); diff --git a/src/serifs.ts b/src/serifs.ts index 9a9f135..24da184 100644 --- a/src/serifs.ts +++ b/src/serifs.ts @@ -1,4 +1,14 @@ export default { + core: { + setNameOk: 'わかりました。これからは{name}とお呼びしますね!', + san: 'さん付けした方がいいですか?', + yesOrNo: '「はい」か「いいえ」しかわからないんです...', + goodMorning: 'おはようございます!', + goodMorningWithName: 'おはようございます、{name}!', + goodNight: 'おやすみなさい!', + goodNightWithName: 'おやすみなさい、{name}!', + }, + /** * リバーシへの誘いを承諾するとき */ @@ -95,6 +105,7 @@ export default { timer: { set: 'わかりました!', invalid: 'うーん...?', - notify: '{time}経ちましたよ!' + notify: '{time}経ちましたよ!', + notifyWithName: '{name}、{time}経ちましたよ!' } };