Release
This commit is contained in:
36
config.yml
Normal file
36
config.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
# __ __ __ ___ ___
|
||||
# / ' / \ |__) | |__ \_/
|
||||
# \__, \__/ | \ | |___ / \
|
||||
|
||||
# VK API
|
||||
vk_api:
|
||||
# Токен
|
||||
token: TOKEN
|
||||
|
||||
# Отправка сообщений
|
||||
messages:
|
||||
# Шанс генерации
|
||||
chance: 20
|
||||
# Максимальное кол-во символов в тексте
|
||||
symbols_limit: 250
|
||||
# ID бесед, в которых бот активен
|
||||
active_chats: all
|
||||
# Форматирование текста
|
||||
format:
|
||||
# Строчные буквы
|
||||
to_lower_case: true
|
||||
# Заглавная буква в начале
|
||||
capitalize_word: true
|
||||
# Точка в конце
|
||||
end_dot: true
|
||||
|
||||
# Генерация текста
|
||||
generation:
|
||||
# Минимальное кол-во слов в генерируемом тексте
|
||||
min_words: 5
|
||||
|
||||
# Настройки БД
|
||||
database:
|
||||
# Сохранение сообщений пользователей
|
||||
# * Одинаковые строки не сохраняются
|
||||
data_save: true
|
||||
134
core/core.js
Normal file
134
core/core.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / ' / \ |__) | |__ \_/
|
||||
* \__, \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021 hepller
|
||||
*/
|
||||
|
||||
// Импорт модулей
|
||||
import {VK} from 'vk-io'
|
||||
import YAML from 'yaml'
|
||||
import Markov from 'markov-generator'
|
||||
import fs from 'fs'
|
||||
import Logger from './logger.js'
|
||||
|
||||
/** Конфиг */
|
||||
let config = YAML.parse(fs.readFileSync('config.yml', 'utf8'))
|
||||
|
||||
// БД и файл проекта
|
||||
const db = JSON.parse(fs.readFileSync('data.json', 'utf8'))
|
||||
const project = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
||||
|
||||
/** VK API */
|
||||
const vk = new VK({token: config.vk_api.token, v: 5.130, apiLimit: 1})
|
||||
|
||||
/**
|
||||
* Сохраняет БД
|
||||
* @param {object} data БД
|
||||
*/
|
||||
db.write = (data) => {
|
||||
fs.writeFileSync('data.json', JSON.stringify(data, null, '\t'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает объект чата из БД
|
||||
* @param {number} id ID чата
|
||||
*/
|
||||
db.getChat = (id) => {
|
||||
|
||||
// Поиск чата по ID
|
||||
let chat = db.chats.find(chat => chat.id == id)
|
||||
|
||||
// Создание нового объекта чата при отсутствии
|
||||
if (!chat) {
|
||||
|
||||
// Добавление в БД
|
||||
db.chats.push({id: id, data: []})
|
||||
|
||||
// Запись БД
|
||||
db.write(db)
|
||||
|
||||
// Получение из БД
|
||||
chat = db.chats.find(chat => chat.id == id)
|
||||
}
|
||||
|
||||
// Возвращение объекта чата
|
||||
return chat
|
||||
}
|
||||
|
||||
// Сообщения при запуске
|
||||
Logger.info(`Cortex Bot v${project.version}`)
|
||||
Logger.info('Подключение к VK API ...')
|
||||
|
||||
// Перезагрузка конфигурации при её изменении
|
||||
watchFile('./config.yml', async () => {
|
||||
|
||||
// Парсинг
|
||||
config = YAML.parse(fs.readFileSync('config.yml', 'utf8'))
|
||||
|
||||
// Запись в лог
|
||||
Logger.info('Конфигурация перезагружена')
|
||||
})
|
||||
|
||||
// Старт получения обновлений ВК
|
||||
vk.updates.startPolling().then(() => Logger.info('VK API подключено'))
|
||||
|
||||
// Обработчик сообщений ВК
|
||||
vk.updates.on('message_new', async ctx => {
|
||||
|
||||
// Игнорирование лишних сообщений
|
||||
if (!ctx.isChat) return
|
||||
if (config.messages.active_chats != 'all' && !config.messages.active_chats.includes(ctx.chatId)) return
|
||||
|
||||
// Логирование сообщений
|
||||
Logger.info(`#${ctx.chatId} ${ctx.senderId} ${ctx.isOutbox ? '<-' : '->'} ${ctx?.text ? ctx.text : '<no_text>'} ${ctx?.attachments}`)
|
||||
|
||||
// Завершение функции, если сообщение исходящее или от сообщества
|
||||
if (ctx.isOutbox || ctx.isGroup) return
|
||||
|
||||
// Объект пользователя
|
||||
ctx.chat = await db.getChat(ctx.chatId)
|
||||
|
||||
// Запись сообщения в БД
|
||||
if (ctx.text && config.database.data_save && !ctx.chat.data.includes(ctx.text)) {
|
||||
|
||||
// Запись в БД
|
||||
db.chats.find(chat => chat.id == ctx.chatId).data.push(ctx.text)
|
||||
|
||||
// Сохранение БД
|
||||
db.write(db)
|
||||
}
|
||||
|
||||
// Генерация сообщения с определенным шансом
|
||||
if (Math.random() * 100 < config.messages.chance) {
|
||||
|
||||
// Сообщение в консоль о генерации текста
|
||||
Logger.info('Генерация текста ...')
|
||||
|
||||
// Генерация текста
|
||||
// Если данных будет недостаточно произойдет ошибка <<Maximum call stack size exceeded>>
|
||||
let sentence = new Markov(getChat().data, config.generation.min_words).makeChain()
|
||||
|
||||
// Форматирование текста
|
||||
if (config.messages.format.to_lower_case) sentence = sentence.toLowerCase()
|
||||
if (config.messages.format.capitalize_word) sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1)
|
||||
if (config.messages.format.end_dot) sentence = sentence + '.'
|
||||
|
||||
// Предупреждение при превышении лимита символов
|
||||
if (sentence.split('').length > config.messages.symbols_limit) return Logger.warn(`#${ctx.chatId} Превышен лимит символов (${sentence.split('').length}/${config.messages.symbols_limit})`)
|
||||
|
||||
// Статус набора текста
|
||||
await ctx.setActivity()
|
||||
|
||||
// Задержка перед отправкой сообщений
|
||||
// Высчитывается на основе количества символов в сгенерированном тексте для имитации написания
|
||||
await new Promise(resolve => setTimeout(resolve, sentence.split('').length * 2 + '00'))
|
||||
|
||||
// Отправка сообщения
|
||||
await ctx.send(sentence)
|
||||
}
|
||||
})
|
||||
|
||||
// Обработчики ошибок
|
||||
process.on('uncaughtException', error => Logger.error(error))
|
||||
process.on('unhandledRejection', error => Logger.error(error))
|
||||
51
core/logger.js
Normal file
51
core/logger.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/** __ __ __ ___ ___
|
||||
* / ' / \ |__) | |__ \_/
|
||||
* \__, \__/ | \ | |___ / \
|
||||
*
|
||||
* @copyright © 2021 hepller
|
||||
*/
|
||||
|
||||
/** Получает текущее время */
|
||||
const 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}`
|
||||
}
|
||||
|
||||
/** Логер */
|
||||
export default class Logger {
|
||||
|
||||
/**
|
||||
* Выводит в лог информацию
|
||||
* @param {string} text - Текст сообщения
|
||||
*/
|
||||
static info(text) {
|
||||
console.log(`${getTimeString()} INFO - ${text}`.replace(/\n/g, '\\n'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Выводит в лог предупреждения
|
||||
* @param {string} text - Текст предупреждения
|
||||
*/
|
||||
static warn(text) {
|
||||
console.log(`\u001B[33m${getTimeString()} WARN - ${text}\u001B[0m`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Выводит в лог ошибки
|
||||
* @param {string} text - Текст ошибки
|
||||
*/
|
||||
static error(text) {
|
||||
console.log(`\u001B[31m${getTimeString()} ERRO - ${text}\u001B[0m`)
|
||||
}
|
||||
}
|
||||
21
license
Normal file
21
license
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright © 2021 hepller
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "cortex-bot",
|
||||
"version": "0.6.3",
|
||||
"description": "vk delirium generator bot",
|
||||
"main": "core/core.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hepller/cortex-bot.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vk",
|
||||
"bot",
|
||||
"markov"
|
||||
],
|
||||
"author": "hepller",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/hepller/cortex-bot/issues"
|
||||
},
|
||||
"homepage": "https://github.com/hepller/cortex-bot#readme",
|
||||
"dependencies": {
|
||||
"markov-generator": "^1.2.3",
|
||||
"vk-io": "^4.3.0",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user