v0.9.0
This commit is contained in:
95
core/core.js
Normal file
95
core/core.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / / \ |__) | |__ \_/
|
||||
* \__ \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021-2022 hepller
|
||||
*/
|
||||
|
||||
// Импорт зависимостей
|
||||
import { VK } from 'vk-io'
|
||||
import YAML from 'yaml'
|
||||
import Markov from 'markov-generator'
|
||||
|
||||
// Импорт системных модулей
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
// Импорт компонентов ядра
|
||||
import Logger from './logger.js'
|
||||
import Utils from './utils.js'
|
||||
import DataManager from './data_manager.js'
|
||||
|
||||
// Парсинг конфигураций проекта
|
||||
const config = YAML.parse(readFileSync('config.yml', 'utf8'))
|
||||
const project = JSON.parse(readFileSync('package.json', 'utf8'))
|
||||
|
||||
// Инициализация vk-io
|
||||
const vk = new VK(
|
||||
|
||||
// Определение места работы бота (группа / страница)
|
||||
config.longpoll.group_id
|
||||
|
||||
// При работе в группе
|
||||
? {token: config.longpoll.token, v: config.longpoll.version, pollingGroupId: config.longpoll.group_id}
|
||||
|
||||
// При работе на странице
|
||||
: {token: config.longpoll.token, v: config.longpoll.version}
|
||||
)
|
||||
|
||||
// Сообщение о запуске
|
||||
Logger.info(`Cortex Bot v${project.version} запущен`)
|
||||
|
||||
// Сообщение о подключении к VK API
|
||||
Logger.info('Подключение к VK Long Poll ...')
|
||||
|
||||
// Старт получения событий ВК
|
||||
vk.updates.startPolling().then(() => Logger.info('VK Long Poll подключен'))
|
||||
|
||||
// Обработчик сообщений ВК
|
||||
vk.updates.on('message_new', async ctx => {
|
||||
|
||||
// Игнорирование лишних сообщений
|
||||
if (!ctx.isChat || ctx.isOutbox) return
|
||||
if (config.messages.active_chats != 'all' && !config.messages.active_chats.includes(ctx.chatId)) return
|
||||
|
||||
// Логирование сообщений
|
||||
Logger.info(`#${ctx.chatId} ${ctx.senderId} '->' ${ctx.text || '<no_text>'} ${ctx?.attachments}`)
|
||||
|
||||
// Получение чата из БД
|
||||
ctx.chat = DataManager.getChat(ctx.chatId)
|
||||
|
||||
// Запись сообщения в БД
|
||||
if (!ctx.isGroup && ctx.text && config.database.data_save && !ctx.chat.data.includes(ctx.text)) DataManager.writeChatData(ctx.chatId, ctx.text)
|
||||
|
||||
// Генерация сообщения с определенным шансом
|
||||
if (Utils.getWithChance(config.messages.chance)) {
|
||||
|
||||
// Сообщение в консоль о генерации текста
|
||||
Logger.info(`#${ctx.chatId} Генерация текста ...`)
|
||||
|
||||
// Генерация текста
|
||||
// * Если данных будет недостаточно произойдет ошибка <<Maximum call stack size exceeded>>
|
||||
const sentence = new Markov({input: ctx.chat.data, minLength: config.generation.min_words}).makeChain()
|
||||
|
||||
// Форматирование текста (если включено)
|
||||
const formatted_sentence = config.messages.format ? Utils.formatString(sentence) : sentence
|
||||
|
||||
// Предупреждение при превышении лимита символов
|
||||
if (formatted_sentence.split('').length > config.messages.symbols_limit) return Logger.warn(`#${ctx.chatId} Превышен лимит символов (${formatted_sentence.split('').length}/${config.messages.symbols_limit})`)
|
||||
|
||||
// Установка статуса набора текста
|
||||
ctx.setActivity()
|
||||
|
||||
// Задержка перед отправкой сообщений для имитации написания (если включено)
|
||||
// * Высчитывается на основе количества символов в сгенерированном тексте
|
||||
if (config.messages.writing_imitation) await Utils.sleep(formatted_sentence.split('').length * 2 + '00')
|
||||
|
||||
// Отправка сообщения
|
||||
ctx.send(formatted_sentence).then(() => Logger.info(`#${ctx.chatId} Сообщение сгенерировано ("${sentence}")`))
|
||||
}
|
||||
})
|
||||
|
||||
// Логирование неперехваченных исключений
|
||||
process.on('uncaughtException', error => Logger.error(error.stack))
|
||||
|
||||
// Логирование необработанных ошибок (promise error)
|
||||
process.on('unhandledRejection', error => Logger.error(error.stack))
|
||||
56
core/data_manager.js
Normal file
56
core/data_manager.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / / \ |__) | |__ \_/
|
||||
* \__ \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021-2022 hepller
|
||||
*/
|
||||
|
||||
// Импорт системных модулей
|
||||
import { readFileSync, writeFileSync } from 'fs'
|
||||
|
||||
// Получение БД
|
||||
const db = JSON.parse(readFileSync('data.json', 'utf8'))
|
||||
|
||||
/** Менеджер БД */
|
||||
export default class DataManager {
|
||||
|
||||
/**
|
||||
* Получает чат из БД
|
||||
* @param {number} chat_id ID чата
|
||||
*/
|
||||
static getChat(chat_id) {
|
||||
|
||||
// Поиск чата в БД
|
||||
let chat = db.chats.find(chat => chat.id == chat_id)
|
||||
|
||||
// Добавление чата в БД при его отсутствии
|
||||
if (!chat) {
|
||||
|
||||
// Добавление
|
||||
db.chats.push({id: chat_id, data: []})
|
||||
|
||||
// Запись
|
||||
writeFileSync('data.json', JSON.stringify(db, null, '\t'))
|
||||
|
||||
// Обновление значения переменной
|
||||
chat = db.chats.find(chat => chat.id == chat_id)
|
||||
}
|
||||
|
||||
// Возвращение объекта чата
|
||||
return chat
|
||||
}
|
||||
|
||||
/**
|
||||
* Записывает новые данные для чата
|
||||
* @param {number} chat_id ID чата
|
||||
* @param {string} data Данные
|
||||
*/
|
||||
static writeChatData(chat_id, data) {
|
||||
|
||||
// Добавление данных в БД
|
||||
DataManager.getChat(chat_id).data.push(data)
|
||||
|
||||
// Запись БД
|
||||
writeFileSync('data.json', JSON.stringify(db, null, '\t'))
|
||||
}
|
||||
}
|
||||
37
core/logger.js
Normal file
37
core/logger.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / / \ |__) | |__ \_/
|
||||
* \__ \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021-2022 hepller
|
||||
*/
|
||||
|
||||
// Импорт компонентов ядра
|
||||
import Utils from './utils.js'
|
||||
|
||||
/** Логер */
|
||||
export default class Logger {
|
||||
|
||||
/**
|
||||
* Выводит в лог информацию
|
||||
* @param {string} text Текст сообщения
|
||||
*/
|
||||
static info(text) {
|
||||
console.log(`[${Utils.getTimeString()} INFO]: ${text}`.replace(/\n/g, '\\n'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Выводит в лог предупреждения
|
||||
* @param {string} text Текст предупреждения
|
||||
*/
|
||||
static warn(text) {
|
||||
console.log(`\u001B[33m[${Utils.getTimeString()} WARN]: ${text}\u001B[0m`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Выводит в лог ошибки
|
||||
* @param {string} text Текст ошибки
|
||||
*/
|
||||
static error(text) {
|
||||
console.log(`\u001B[31m[${Utils.getTimeString()} ERRO]: ${text}\u001B[0m`)
|
||||
}
|
||||
}
|
||||
53
core/utils.js
Normal file
53
core/utils.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / / \ |__) | |__ \_/
|
||||
* \__ \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021-2022 hepller
|
||||
*/
|
||||
|
||||
/** Функции */
|
||||
export default class Utils {
|
||||
|
||||
/** Возвращает строку со временем в формате `hh:mm:ss` */
|
||||
static getTimeString() {
|
||||
|
||||
// Переменные
|
||||
let hours = new Date().getHours()
|
||||
let minutes = new Date().getMinutes()
|
||||
let seconds = new Date().getSeconds()
|
||||
|
||||
// Исправление одинарных символов
|
||||
if (hours < 10) hours = `0${hours}`
|
||||
if (minutes < 10) minutes = `0${minutes}`
|
||||
if (seconds < 10) seconds = `0${seconds}`
|
||||
|
||||
// Возвращение строки
|
||||
return `${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает `true` с определенным шансом
|
||||
* @param {number} likelihood Вероятность (%)
|
||||
*/
|
||||
static getWithChance(likelihood) {
|
||||
|
||||
// Замена некорректных значений
|
||||
if (likelihood < 0) likelihood = 0
|
||||
if (likelihood > 100) likelihood = 100
|
||||
|
||||
// Возвращение значения
|
||||
return Math.random() * 100 < likelihood
|
||||
}
|
||||
|
||||
/**
|
||||
* Останавливает выполнение функции на указанное время
|
||||
* @param {number} ms Время остановки (в миллисекундах)
|
||||
*/
|
||||
static sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
static formatString(text) {
|
||||
return text.toLowerCase().charAt(0).toUpperCase() + text.slice(1) + '.'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user