feat: setter and getter
This commit is contained in:
parent
ba3f5ae0b2
commit
c1fab17950
9 changed files with 1968 additions and 62 deletions
5
jest.config.js
Normal file
5
jest.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
};
|
|
@ -3,7 +3,6 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.7.1",
|
"discord.js": "^14.7.1",
|
||||||
"dokdo": "^0.6.2",
|
"dokdo": "^0.6.2",
|
||||||
|
@ -12,16 +11,20 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@migan/prettier-config": "^1.0.0",
|
"@migan/prettier-config": "^1.0.0",
|
||||||
|
"@types/jest": "^29.4.0",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
|
"jest": "^29.4.0",
|
||||||
"prettier": "^2.8.3",
|
"prettier": "^2.8.3",
|
||||||
|
"ts-jest": "^29.0.5",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tsup": "^6.5.0",
|
"tsup": "^6.5.0",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup",
|
"build": "tsup",
|
||||||
"dev": "ts-node-esm src",
|
"dev": "ts-node src",
|
||||||
"start": "node dist"
|
"start": "node dist",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"prettier": "@migan/prettier-config"
|
"prettier": "@migan/prettier-config"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
import sqlite3 from 'sqlite3'
|
|
||||||
import type { Client, Message } from 'discord.js'
|
import type { Client, Message } from 'discord.js'
|
||||||
import { dirname, join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import Database from './Database'
|
||||||
|
|
||||||
type TrainType = 'muffinOnly' | 'All'
|
type TrainType = 'muffinOnly' | 'All'
|
||||||
|
|
||||||
export default class ChatBot {
|
export default class ChatBot {
|
||||||
private db = new sqlite3.Database(
|
get trainType(): TrainType {
|
||||||
join(dirname(fileURLToPath(import.meta.url)), '..', 'db', 'db.sqlite3')
|
return this._trainType
|
||||||
)
|
}
|
||||||
private trainType: TrainType = 'All'
|
|
||||||
|
set trainType(value: TrainType) {
|
||||||
|
this._trainType = value
|
||||||
|
}
|
||||||
|
private db = new Database(join(__dirname, '..', 'db', 'db.sqlite3'))
|
||||||
|
private _trainType: TrainType = 'All'
|
||||||
public constructor() {}
|
public constructor() {}
|
||||||
|
|
||||||
public getResponse(msg: Message, sendMsg?: boolean): ChatBot {
|
public getResponse(msg: Message, sendMsg?: boolean): ChatBot {
|
||||||
this.db.all(
|
this.db
|
||||||
'SELECT text FROM statement;',
|
.get()
|
||||||
(err, rows: Array<{ text: string }>) => {
|
.then(rows => {
|
||||||
if (err) throw err
|
|
||||||
const a = msg.content.replace('머핀아', '')
|
const a = msg.content.replace('머핀아', '')
|
||||||
let r = rows[Math.floor(Math.random() * rows.length)].text
|
let r = rows[Math.floor(Math.random() * rows.length)].text
|
||||||
if (!r) r = '살ㄹ려주세요'
|
if (!r) r = '살ㄹ려주세요'
|
||||||
|
@ -26,22 +29,20 @@ export default class ChatBot {
|
||||||
msg.channel.sendTyping()
|
msg.channel.sendTyping()
|
||||||
setTimeout(() => msg.channel.send(r), 1000)
|
setTimeout(() => msg.channel.send(r), 1000)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
.catch(console.error)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public train(client: Client): ChatBot {
|
public train(client: Client): ChatBot {
|
||||||
|
const sql = `INSERT INTO statement(text, persona) VALUES(?, ?);`
|
||||||
client.on('messageCreate', msg => {
|
client.on('messageCreate', msg => {
|
||||||
if (msg.author.bot) return
|
if (msg.author.bot) return
|
||||||
if (msg.author.id === '1026185545837191238') {
|
if (msg.author.id === '1026185545837191238') {
|
||||||
this.db.run(
|
this.db.run(sql, [msg.content, 'muffin'], err => {
|
||||||
`INSERT INTO statement(text, persona) VALUES('${msg.content}', 'muffin');`,
|
if (err) throw err
|
||||||
err => {
|
this.getResponse(msg)
|
||||||
if (err) throw err
|
})
|
||||||
this.getResponse(msg)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
if (this.trainType !== 'All') return
|
if (this.trainType !== 'All') return
|
||||||
if (!msg.content.startsWith('머핀아 ')) return
|
if (!msg.content.startsWith('머핀아 ')) return
|
||||||
|
@ -49,9 +50,8 @@ export default class ChatBot {
|
||||||
.replaceAll("'", '')
|
.replaceAll("'", '')
|
||||||
.slice(0, 50)
|
.slice(0, 50)
|
||||||
.toLowerCase()}`
|
.toLowerCase()}`
|
||||||
const text = msg.content.replace('머핀아 ', '').replaceAll("'", '')
|
const text = msg.content.replace('머핀아 ', '')
|
||||||
const sql = `INSERT INTO statement(text, persona) VALUES('${text}', '${user}');`
|
this.db.run(sql, [text, user], err => {
|
||||||
this.db.run(sql, err => {
|
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -59,18 +59,6 @@ export default class ChatBot {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeTrainType(): TrainType {
|
|
||||||
switch (this.trainType) {
|
|
||||||
case 'muffinOnly':
|
|
||||||
this.trainType = 'All'
|
|
||||||
break
|
|
||||||
case 'All':
|
|
||||||
this.trainType = 'muffinOnly'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return this.trainType
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
this.db.close()
|
this.db.close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ActivityType, Client, GatewayIntentBits, Message } from 'discord.js'
|
import { ActivityType, Client, GatewayIntentBits, Message } from 'discord.js'
|
||||||
import ChatBot from './ChatBot.js'
|
import ChatBot from './ChatBot'
|
||||||
import Dokdo from 'dokdo'
|
import Dokdo from 'dokdo'
|
||||||
import 'dotenv/config'
|
import 'dotenv/config'
|
||||||
|
|
||||||
|
@ -56,8 +56,19 @@ export default class MuffinAI extends Client {
|
||||||
this.destroy()
|
this.destroy()
|
||||||
} else if (msg.content.startsWith('멒힌아 모드변경')) {
|
} else if (msg.content.startsWith('멒힌아 모드변경')) {
|
||||||
if (!isNotOwner(msg)) return
|
if (!isNotOwner(msg)) return
|
||||||
const a = this.chatBot.changeTrainType()
|
switch (this.chatBot.trainType) {
|
||||||
switch (a) {
|
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':
|
case 'muffinOnly':
|
||||||
msg.channel.send('현재 모드: 머핀만 학습')
|
msg.channel.send('현재 모드: 머핀만 학습')
|
||||||
break
|
break
|
||||||
|
|
42
src/Database.ts
Normal file
42
src/Database.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import sqlite3 from 'sqlite3'
|
||||||
|
|
||||||
|
interface ResponseData {
|
||||||
|
id: number
|
||||||
|
text: string
|
||||||
|
search_text: string
|
||||||
|
conversation: string
|
||||||
|
created_at: string
|
||||||
|
in_response_to: string | null
|
||||||
|
search_in_response_to: string
|
||||||
|
persona: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Database {
|
||||||
|
private db: sqlite3.Database
|
||||||
|
public constructor(dbPath: string) {
|
||||||
|
this.db = new sqlite3.Database(dbPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(): Promise<ResponseData[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.db.serialize(() => {
|
||||||
|
this.db.all('SELECT * FROM statement;', (err, rows) => {
|
||||||
|
if (err) reject(err)
|
||||||
|
resolve([...rows])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public run(
|
||||||
|
sql: string,
|
||||||
|
params: any[],
|
||||||
|
callBack: (err: Error | null) => void
|
||||||
|
) {
|
||||||
|
this.db.run(sql, params, callBack)
|
||||||
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.db.close()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
import('./Client.js').then(a => new a.default().login())
|
import('./Client').then(a => new a.default().login())
|
||||||
|
|
43
tests/Database.test.ts
Normal file
43
tests/Database.test.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import Database from '../src/Database'
|
||||||
|
import sqlite3 from 'sqlite3'
|
||||||
|
|
||||||
|
describe('Test Database', () => {
|
||||||
|
const DBPATH = `${__dirname}/../db/db.sqlite3`
|
||||||
|
const db = new sqlite3.Database(DBPATH)
|
||||||
|
const getData = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
db.all('SELECT * FROM statement;', async (err, rows) => {
|
||||||
|
if (err) reject(err)
|
||||||
|
resolve(rows)
|
||||||
|
}).close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test('Get rows', () => {
|
||||||
|
getData().then(async rows =>
|
||||||
|
expect(await new Database(DBPATH).get()).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()
|
||||||
|
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 => {
|
||||||
|
db.run('DELETE FROM statement WHERE text=?;', ['TEST'], err => {
|
||||||
|
if (err) throw err
|
||||||
|
})
|
||||||
|
const data2 = await db.get()
|
||||||
|
expect(data1[data1.length - 1]).not.toEqual(data2[data2.length - 1])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -26,10 +26,10 @@
|
||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
"module": "Node16",
|
"module": "commonjs",
|
||||||
/* Specify what module code is generated. */
|
/* Specify what module code is generated. */
|
||||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||||
"moduleResolution": "Node16" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
// "moduleResolution": "Node16" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
||||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
|
|
Loading…
Reference in a new issue