diff --git a/src/ChatBot.ts b/src/ChatBot.ts index a752f0f..a00c2d1 100644 --- a/src/ChatBot.ts +++ b/src/ChatBot.ts @@ -12,13 +12,13 @@ export default class ChatBot { set trainType(value: TrainType) { this._trainType = value } - private db = new Database(join(__dirname, '..', 'db', 'db.sqlite3')) + public db = new Database(join(__dirname, '..', 'db', 'db.sqlite3')) private _trainType: TrainType = 'All' public constructor() {} public getResponse(msg: Message, sendMsg?: boolean): ChatBot { this.db - .get() + .all() .then(rows => { const a = msg.content.replace('머핀아', '') let r = rows[Math.floor(Math.random() * rows.length)].text diff --git a/src/Client.ts b/src/Client.ts index b163750..29c88d1 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,29 +1,17 @@ -import { ActivityType, Client, GatewayIntentBits, Message } from 'discord.js' +import { ActivityType, Client, Collection, GatewayIntentBits } from 'discord.js' import ChatBot from './ChatBot' import Dokdo from 'dokdo' +import { readdirSync } from 'node:fs' +import { join } from 'node:path' +import Command from './Command' +import noPerm from './noPerm' import 'dotenv/config' -function noPerm(msg: Message) { - msg.reply({ - content: '당신은 내 남자친구가 아니야!', - allowedMentions: { - repliedUser: false, - parse: [], - users: [], - roles: [], - }, - }) -} - -function isNotOwner(msg: Message): boolean { - if (msg.author.id !== '415135882006495242') { - noPerm(msg) - return false - } else return true -} +const prefix = '멒힌아 ' export default class MuffinAI extends Client { - private chatBot = new ChatBot() + public chatBot = new ChatBot() + private modules: Collection = new Collection() public constructor() { super({ intents: [ @@ -36,47 +24,40 @@ export default class MuffinAI extends Client { public override login(): Promise { this.chatBot.train(this) + + readdirSync(join(__dirname, 'Commands')).forEach(file => { + const a = require(join(__dirname, 'Commands', file)) + const b: Command = new a.default() + this.modules.set(b.name, b) + }) + this.once('ready', client => { client.user!.setActivity({ type: ActivityType.Playing, name: 'ㅅ살려주세요..!', }) console.log(`먹힐 준비 완료`) - }).on('messageCreate', msg => { + }).on('messageCreate', async msg => { if (msg.author.bot) return - new Dokdo(this, { - prefix: '멒힌아 ', + await new Dokdo(this, { + prefix, noPerm, aliases: ['테스트'], owners: ['415135882006495242'], }).run(msg) if (msg.content.startsWith('머핀아 ')) this.chatBot.getResponse(msg, true) - else if (msg.content.startsWith('멒힌아 봇꺼')) { - if (!isNotOwner(msg)) return - this.destroy() - } else if (msg.content.startsWith('멒힌아 모드변경')) { - if (!isNotOwner(msg)) return - switch (this.chatBot.trainType) { - case 'muffinOnly': - this.chatBot.trainType = 'All' - msg.channel.send('다음 모드로 변경: 전체 학습') - break - case 'All': - this.chatBot.trainType = 'muffinOnly' - msg.channel.send('다음 모드로 변경: 머핀만 학습') - break - } - } else if (msg.content.startsWith('멒힌아 현재모드')) { - if (!isNotOwner(msg)) return - switch (this.chatBot.trainType) { - case 'muffinOnly': - msg.channel.send('현재 모드: 머핀만 학습') - break - case 'All': - msg.channel.send('현재 모드: 전체 학습') - break - } - } else return + else if (msg.content.startsWith(prefix)) { + const args: string[] = msg.content + .slice(prefix.length) + .trim() + .split('/ +/g') + + const command = this.modules.get(args.join(' ')) + if (!command) return + if (command.noPerm && msg.author.id !== '415135882006495242') + return await noPerm(msg) + command.execute(msg, args) + } }) return super.login() } @@ -86,3 +67,9 @@ export default class MuffinAI extends Client { super.destroy() } } + +declare module 'discord.js' { + interface Client { + chatBot: ChatBot + } +} diff --git a/src/Command.ts b/src/Command.ts new file mode 100644 index 0000000..aac9eb1 --- /dev/null +++ b/src/Command.ts @@ -0,0 +1,6 @@ +import { Message } from 'discord.js' + +export default abstract class Command { + protected constructor(public name: string, public noPerm: boolean = false) {} + public abstract execute(msg: Message, args: string[]): any +} diff --git a/src/Commands/모드변경.ts b/src/Commands/모드변경.ts new file mode 100644 index 0000000..a1801ee --- /dev/null +++ b/src/Commands/모드변경.ts @@ -0,0 +1,20 @@ +import Command from '../Command' +import { type Message } from 'discord.js' + +export default class extends Command { + public constructor() { + super('모드변경', true) + } + public async execute(msg: Message, args: string[]) { + switch (msg.client.chatBot.trainType) { + case 'muffinOnly': + msg.client.chatBot.trainType = 'All' + msg.channel.send('다음 모드로 변경: 전체 학습') + break + case 'All': + msg.client.chatBot.trainType = 'muffinOnly' + msg.channel.send('다음 모드로 변경: 머핀만 학습') + break + } + } +} diff --git a/src/Commands/봇꺼.ts b/src/Commands/봇꺼.ts new file mode 100644 index 0000000..59fdc7d --- /dev/null +++ b/src/Commands/봇꺼.ts @@ -0,0 +1,13 @@ +import Command from '../Command' +import { type Message } from 'discord.js' + +export default class extends Command { + public constructor() { + super('봇꺼', true) + } + public execute(msg: Message, args: string[]) { + msg.channel.send('ㅇㅇ').finally(() => { + msg.client.destroy() + }) + } +} diff --git a/src/Commands/학습데이터량.ts b/src/Commands/학습데이터량.ts new file mode 100644 index 0000000..a3792ad --- /dev/null +++ b/src/Commands/학습데이터량.ts @@ -0,0 +1,21 @@ +import Command from '../Command' +import { type Message } from 'discord.js' + +export default class extends Command { + public constructor() { + super('학습데이터량') + } + public execute(msg: Message, args: string[]) { + msg.client.chatBot.db.all().then(rows => { + const user: any[] = [] + const muffin: any[] = [] + rows.forEach(row => { + if (row.persona === 'muffin') muffin.push(row) + else user.push(row) + }) + msg.channel.send( + `머핀 데이터: ${muffin.length}개\n유저 데이터: ${user.length}개` + ) + }) + } +} diff --git a/src/Commands/현재모드.ts b/src/Commands/현재모드.ts new file mode 100644 index 0000000..7c1a837 --- /dev/null +++ b/src/Commands/현재모드.ts @@ -0,0 +1,18 @@ +import { type Message } from 'discord.js' +import Command from '../Command' + +export default class extends Command { + public constructor() { + super('현재모드') + } + public execute(msg: Message, args: string[]) { + switch (msg.client.chatBot.trainType) { + case 'muffinOnly': + msg.channel.send('현재 모드: 머핀만 학습') + break + case 'All': + msg.channel.send('현재 모드: 전체 학습') + break + } + } +} diff --git a/src/Database.ts b/src/Database.ts index e51e115..b96aa7a 100644 --- a/src/Database.ts +++ b/src/Database.ts @@ -12,15 +12,15 @@ interface ResponseData { } export default class Database { - private db: sqlite3.Database + private sqliteDB: sqlite3.Database public constructor(dbPath: string) { - this.db = new sqlite3.Database(dbPath) + this.sqliteDB = new sqlite3.Database(dbPath) } - public get(): Promise { + public all(): Promise { return new Promise((resolve, reject) => { - this.db.serialize(() => { - this.db.all('SELECT * FROM statement;', (err, rows) => { + this.sqliteDB.serialize(() => { + this.sqliteDB.all('SELECT * FROM statement;', (err, rows) => { if (err) reject(err) resolve([...rows]) }) @@ -33,10 +33,10 @@ export default class Database { params: any[], callBack: (err: Error | null) => void ) { - this.db.run(sql, params, callBack) + this.sqliteDB.run(sql, params, callBack) } public close() { - this.db.close() + this.sqliteDB.close() } } diff --git a/src/noPerm.ts b/src/noPerm.ts new file mode 100644 index 0000000..49ffdb5 --- /dev/null +++ b/src/noPerm.ts @@ -0,0 +1,13 @@ +import { type Message } from 'discord.js' + +export default async function noPerm(msg: Message) { + await msg.reply({ + content: '당신은 내 남자친구가 아니야!', + allowedMentions: { + repliedUser: false, + parse: [], + users: [], + roles: [], + }, + }) +} diff --git a/tests/Database.test.ts b/tests/Database.test.ts index b939422..e810d3e 100644 --- a/tests/Database.test.ts +++ b/tests/Database.test.ts @@ -15,28 +15,32 @@ describe('Test Database', () => { test('Get rows', () => { getData().then(async rows => - expect(await new Database(DBPATH).get()).toEqual(rows) + expect(await new Database(DBPATH).all()).toEqual(rows) ) }) test('Insert row', () => { const db = new Database(DBPATH) - return db.get().then(async data1 => { - db.run('INSERT INTO statement(text) VALUES(?)', ['TEST'], err => { - if (err) throw err - }) - const data2 = await db.get() + return db.all().then(async data1 => { + db.run( + 'INSERT INTO statement(id, text) VALUES(?, ?)', + [++data1[data1.length - 1].id, 'TEST'], + err => { + if (err) throw err + } + ) + const data2 = await db.all() expect(data1[data1.length - 1]).not.toEqual(data2[data2.length - 1]) }) }) test('Delete row', () => { const db = new Database(DBPATH) - return db.get().then(async data1 => { + return db.all().then(async data1 => { db.run('DELETE FROM statement WHERE text=?;', ['TEST'], err => { if (err) throw err }) - const data2 = await db.get() + const data2 = await db.all() expect(data1[data1.length - 1]).not.toEqual(data2[data2.length - 1]) }) })