From c0c104a8ec932c144e32d329764b46604e9d8344 Mon Sep 17 00:00:00 2001 From: Hepller Date: Thu, 27 May 2021 21:32:57 +0300 Subject: [PATCH] Release --- config.yml | 36 +++++++++++++ core/core.js | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ core/logger.js | 51 +++++++++++++++++++ data.json | 1 + license | 21 ++++++++ package.json | 30 +++++++++++ readme.md | 9 ++++ 7 files changed, 282 insertions(+) create mode 100644 config.yml create mode 100644 core/core.js create mode 100644 core/logger.js create mode 100644 data.json create mode 100644 license create mode 100644 package.json create mode 100644 readme.md diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..bedbdce --- /dev/null +++ b/config.yml @@ -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 \ No newline at end of file diff --git a/core/core.js b/core/core.js new file mode 100644 index 0000000..ec39262 --- /dev/null +++ b/core/core.js @@ -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 : ''} ${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('Генерация текста ...') + + // Генерация текста + // Если данных будет недостаточно произойдет ошибка <> + 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)) \ No newline at end of file diff --git a/core/logger.js b/core/logger.js new file mode 100644 index 0000000..96f4d41 --- /dev/null +++ b/core/logger.js @@ -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`) + } +} \ No newline at end of file diff --git a/data.json b/data.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/data.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/license b/license new file mode 100644 index 0000000..a1cf3b8 --- /dev/null +++ b/license @@ -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. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..fc933bf --- /dev/null +++ b/package.json @@ -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" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..967b1e8 --- /dev/null +++ b/readme.md @@ -0,0 +1,9 @@ +# Cortex Bot + +Бот ВКонтакте для генерации случайных сообщений на основе цепей Маркова + +--- + +## Лицензия + +Проект распространяется под лицензией **MIT**