Compare commits
2 Commits
1fb3805794
...
e6a9743de3
| Author | SHA1 | Date | |
|---|---|---|---|
| e6a9743de3 | |||
| 31b7e14f75 |
64
bot.js
64
bot.js
@ -3,6 +3,7 @@ const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { OpenRouterClient } = require('openrouter-kit');
|
||||
const { getPrompt } = require('./prompts.js');
|
||||
const logger = require('./logger.js');
|
||||
require('dotenv').config();
|
||||
const char = {name:'marina'}
|
||||
class TelegramHistoryBot {
|
||||
@ -13,7 +14,7 @@ class TelegramHistoryBot {
|
||||
|
||||
// Инициализация OpenRouter с проверкой ключа
|
||||
if (!process.env.OPENROUTER_API_KEY) {
|
||||
console.warn('⚠️ OPENROUTER_API_KEY не найден, ИИ-суммаризация будет недоступна');
|
||||
logger.warn('⚠️ OPENROUTER_API_KEY не найден, ИИ-суммаризация будет недоступна');
|
||||
this.openRouter = null;
|
||||
} else {
|
||||
this.openRouter = new OpenRouterClient({
|
||||
@ -37,9 +38,9 @@ class TelegramHistoryBot {
|
||||
try {
|
||||
await this.loadHistory();
|
||||
this.setupHandlers();
|
||||
console.log('✅ Bot запущен и готов к работе');
|
||||
logger.info('✅ Bot запущен и готов к работе');
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка инициализации бота:', error);
|
||||
logger.error('❌ Ошибка инициализации бота:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@ -48,9 +49,9 @@ class TelegramHistoryBot {
|
||||
try {
|
||||
const data = await fs.readFile(this.historyFile, 'utf8');
|
||||
this.history = JSON.parse(data);
|
||||
console.log(`📚 Загружено ${this.history.length} сообщений из истории`);
|
||||
logger.info(`📚 Загружено ${this.history.length} сообщений из истории`);
|
||||
} catch (error) {
|
||||
console.log('📝 История не найдена, создаем новую');
|
||||
logger.warn('📝 История не найдена, создаем новую');
|
||||
this.history = [];
|
||||
await this.saveHistory();
|
||||
}
|
||||
@ -60,7 +61,7 @@ class TelegramHistoryBot {
|
||||
try {
|
||||
await fs.writeFile(this.historyFile, JSON.stringify(this.history, null, 2));
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка сохранения истории:', error);
|
||||
logger.error('❌ Ошибка сохранения истории:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +73,7 @@ class TelegramHistoryBot {
|
||||
// await ctx.deleteMessage
|
||||
// return
|
||||
// }
|
||||
console.log('📊 Получена команда summary_day');
|
||||
logger.info('📊 Получена команда summary_day');
|
||||
const args = ctx.message.text.split(' ');
|
||||
if (args.length > 1) {
|
||||
char.name=args[1]
|
||||
@ -82,7 +83,7 @@ class TelegramHistoryBot {
|
||||
});
|
||||
|
||||
this.bot.command('summary_hours', async (ctx) => {
|
||||
console.log('📊 Получена команда summary_hours');
|
||||
logger.info('📊 Получена команда summary_hours');
|
||||
const args = ctx.message.text.split(' ');
|
||||
if (args.length < 2 || isNaN(parseInt(args[1]))) {
|
||||
await ctx.reply('❗ Укажите количество часов: /summary_hours 6');
|
||||
@ -94,7 +95,7 @@ class TelegramHistoryBot {
|
||||
});
|
||||
|
||||
this.bot.command('summary_last', async (ctx) => {
|
||||
console.log('📊 Получена команда summary_last');
|
||||
logger.info('📊 Получена команда summary_last');
|
||||
const args = ctx.message.text.split(' ');
|
||||
if (args.length < 2 || isNaN(parseInt(args[1]))) {
|
||||
await ctx.reply('❗ Укажите количество сообщений: /summary_last 50');
|
||||
@ -120,25 +121,25 @@ class TelegramHistoryBot {
|
||||
|
||||
// Обработка ошибок
|
||||
this.bot.catch(async (err, ctx) => {
|
||||
console.error('❌ Ошибка бота:', err);
|
||||
logger.error('❌ Ошибка бота:', err);
|
||||
try {
|
||||
await ctx.reply('❌ Произошла ошибка при обработке команды');
|
||||
} catch (replyError) {
|
||||
console.error('❌ Не удалось отправить сообщение об ошибке:', replyError);
|
||||
logger.error('❌ Не удалось отправить сообщение об ошибке:', replyError);
|
||||
}
|
||||
});
|
||||
|
||||
// Запуск бота
|
||||
this.bot.launch();
|
||||
console.log('🚀 Бот запущен');
|
||||
logger.info('🚀 Бот запущен');
|
||||
|
||||
// Graceful stop
|
||||
process.once('SIGINT', () => {
|
||||
console.log('🛑 Получен сигнал SIGINT, останавливаем бота...');
|
||||
logger.warn('🛑 Получен сигнал SIGINT, останавливаем бота...');
|
||||
this.bot.stop('SIGINT');
|
||||
});
|
||||
process.once('SIGTERM', () => {
|
||||
console.log('🛑 Получен сигнал SIGTERM, останавливаем бота...');
|
||||
logger.warn('🛑 Получен сигнал SIGTERM, останавливаем бота...');
|
||||
this.bot.stop('SIGTERM');
|
||||
});
|
||||
}
|
||||
@ -169,9 +170,9 @@ class TelegramHistoryBot {
|
||||
|
||||
const userName = messageData.first_name || messageData.username || 'Unknown';
|
||||
const content = messageData.text || `[${messageData.message_type}]`;
|
||||
console.log(`💾 Сохранено сообщение от ${userName}: ${content.substring(0, 50)}${content.length > 50 ? '...' : ''}`);
|
||||
logger.info(`💾 Сохранено сообщение от ${userName} в ${msg.chat.id} : ${content.substring(0, 50)}${content.length > 50 ? '...' : ''}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при обработке сообщения:', error);
|
||||
logger.error('❌ Ошибка при обработке сообщения:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +221,7 @@ class TelegramHistoryBot {
|
||||
}
|
||||
|
||||
async handleSummaryCommand(ctx, type, value) {
|
||||
console.log(`📊 Обработка команды суммаризации: ${type}${value ? ` (${value})` : ''}`);
|
||||
logger.info(`📊 Обработка команды суммаризации: ${type}${value ? ` (${value})` : ''}`);
|
||||
|
||||
const chatId = ctx.chat.id;
|
||||
let messages = [];
|
||||
@ -250,7 +251,7 @@ class TelegramHistoryBot {
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`📈 Найдено ${messages.length} сообщений для суммаризации`);
|
||||
logger.info(`📈 Найдено ${messages.length} сообщений для суммаризации`);
|
||||
|
||||
if (messages.length === 0) {
|
||||
await ctx.reply('❗ Сообщения для суммаризации не найдены');
|
||||
@ -267,10 +268,10 @@ class TelegramHistoryBot {
|
||||
|
||||
// Отправляем результат
|
||||
await ctx.reply(summary, { parse_mode: 'HTML' });
|
||||
console.log('✅ Суммаризация отправлена');
|
||||
logger.info('✅ Суммаризация отправлена');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при создании суммаризации:', error);
|
||||
logger.error('❌ Ошибка при создании суммаризации:', error);
|
||||
await ctx.reply('❌ Произошла ошибка при создании суммаризации. Попробуйте позже.');
|
||||
}
|
||||
}
|
||||
@ -388,7 +389,7 @@ class TelegramHistoryBot {
|
||||
|
||||
createSummaryPrompt(type, value) {
|
||||
const timeDescription = this.getTimeDescription(type, value);
|
||||
console.log('Выбранный персонаж: ', char)
|
||||
logger.info('Выбранный персонаж: ', char)
|
||||
return `Ты получишь данные чата Telegram ${timeDescription}. ` +
|
||||
getPrompt(char.name)
|
||||
|
||||
@ -443,13 +444,13 @@ ${conversationFlow}`;
|
||||
async callAISummarization(prompt, data) {
|
||||
// Если API ключ недоступен, используем fallback
|
||||
if (!process.env.OPENROUTER_API_KEY) {
|
||||
console.log('⚠️ OpenRouter API ключ недоступен, используем базовую суммаризацию');
|
||||
logger.warn('⚠️ OpenRouter API ключ недоступен, используем базовую суммаризацию');
|
||||
return this.generateFallbackSummary(data);
|
||||
}
|
||||
|
||||
try {
|
||||
const formattedMessages = this.formatMessagesForAI(data);
|
||||
console.log('🤖 Отправляем запрос к OpenRouter...');
|
||||
logger.info('🤖 Отправляем запрос к OpenRouter...');
|
||||
|
||||
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
@ -460,7 +461,8 @@ ${conversationFlow}`;
|
||||
'X-Title': 'Telegram History Bot'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'google/gemini-2.5-flash-preview-05-20',
|
||||
model: process.env.OPENROUTER_MODEL,
|
||||
// model: 'google/gemini-2.5-flash-preview-05-20',
|
||||
// model: 'google/gemini-2.0-flash-exp:free',
|
||||
// model: 'deepseek/deepseek-chat-v3-0324:free',
|
||||
messages: [
|
||||
@ -491,21 +493,21 @@ ${conversationFlow}`;
|
||||
throw new Error('Пустой ответ от ИИ');
|
||||
}
|
||||
|
||||
console.log('✅ Получен ответ от OpenRouter');
|
||||
logger.info('✅ Получен ответ от OpenRouter');
|
||||
return `🎬 <b>История чата</b>\n\n${aiSummary}`;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при вызове OpenRouter API:', error);
|
||||
logger.error('❌ Ошибка при вызове OpenRouter API:', error);
|
||||
|
||||
// Детальная обработка различных типов ошибок
|
||||
if (error.message.includes('401')) {
|
||||
console.error('❌ Неверный API ключ OpenRouter');
|
||||
logger.error('❌ Неверный API ключ OpenRouter');
|
||||
} else if (error.message.includes('429')) {
|
||||
console.error('❌ Превышен лимит запросов OpenRouter');
|
||||
logger.error('❌ Превышен лимит запросов OpenRouter');
|
||||
} else if (error.message.includes('402')) {
|
||||
console.error('❌ Недостаточно средств на счету OpenRouter');
|
||||
logger.error('❌ Недостаточно средств на счету OpenRouter');
|
||||
} else if (error.code === 'ENOTFOUND') {
|
||||
console.error('❌ Проблемы с сетевым подключением');
|
||||
logger.error('❌ Проблемы с сетевым подключением');
|
||||
}
|
||||
|
||||
return this.generateFallbackSummary(data);
|
||||
@ -558,7 +560,7 @@ ${conversationFlow}`;
|
||||
const BOT_TOKEN = process.env.BOT_TOKEN;
|
||||
|
||||
if (!BOT_TOKEN) {
|
||||
console.error('❌ Укажите токен бота в переменной окружения BOT_TOKEN');
|
||||
logger.error('❌ Укажите токен бота в переменной окружения BOT_TOKEN');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
42
logger.js
Normal file
42
logger.js
Normal file
@ -0,0 +1,42 @@
|
||||
const winston = require('winston');
|
||||
const path = require('path');
|
||||
|
||||
// __dirname уже доступен в CommonJS, нет нужды использовать fileURLToPath
|
||||
|
||||
// Формат для файла (подробный JSON)
|
||||
const fileFormat = winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json()
|
||||
);
|
||||
|
||||
// Формат для консоли (краткий, с цветами)
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.timestamp({ format: 'HH:mm:ss' }),
|
||||
winston.format.printf(({ level, message, timestamp }) => {
|
||||
return `${timestamp} ${level}: ${message}`;
|
||||
})
|
||||
);
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
transports: [
|
||||
// Логирование ошибок в отдельный файл
|
||||
new winston.transports.File({
|
||||
filename: path.join(__dirname, '../logs/error.log'),
|
||||
level: 'error',
|
||||
format: fileFormat
|
||||
}),
|
||||
// Общий лог файл
|
||||
new winston.transports.File({
|
||||
filename: path.join(__dirname, '../logs/combined.log'),
|
||||
format: fileFormat
|
||||
}),
|
||||
// Консольный вывод
|
||||
new winston.transports.Console({
|
||||
format: consoleFormat
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
@ -11,7 +11,8 @@
|
||||
"dotenv": "^16.5.0",
|
||||
"openrouter-kit": "^0.1.65",
|
||||
"process": "^0.11.10",
|
||||
"telegraf": "^4.12.2"
|
||||
"telegraf": "^4.12.2",
|
||||
"winston": "^3.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.1"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user