From a12b2b75a03d7755206f64ac5129d5f911b0c150 Mon Sep 17 00:00:00 2001 From: Vufer Date: Sun, 22 Jun 2025 00:46:17 +0300 Subject: [PATCH] =?UTF-8?q?init:=20=D0=91=D0=B0=D0=B7=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.js | 567 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 28 +++ prompts.js | 309 ++++++++++++++++++++++++++++ 3 files changed, 904 insertions(+) create mode 100644 bot.js create mode 100644 package.json create mode 100644 prompts.js diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..1e2bb3f --- /dev/null +++ b/bot.js @@ -0,0 +1,567 @@ +const { Telegraf } = require('telegraf'); +const fs = require('fs').promises; +const path = require('path'); +const { OpenRouterClient } = require('openrouter-kit'); +const { getPrompt } = require('./prompts.js'); +require('dotenv').config(); +const char = {name:'marina'} +class TelegramHistoryBot { + constructor(token) { + this.bot = new Telegraf(token); + this.historyFile = path.join(__dirname, 'chat_history.json'); + this.history = []; + + // Инициализация OpenRouter с проверкой ключа + if (!process.env.OPENROUTER_API_KEY) { + console.warn('⚠️ OPENROUTER_API_KEY не найден, ИИ-суммаризация будет недоступна'); + this.openRouter = null; + } else { + this.openRouter = new OpenRouterClient({ + apiKey: process.env.OPENROUTER_API_KEY, + appName: 'telegram-history-bot', + appVersion: '1.0.0' + }); + } + + this.init(); + } + isAdmin (ctx, userId = ctx.from.id) { + try { + const member = ctx.getChatMember(userId) + return ['creator', 'administrator'].includes(member.status) + } catch { + return false + } + } + async init() { + try { + await this.loadHistory(); + this.setupHandlers(); + console.log('✅ Bot запущен и готов к работе'); + } catch (error) { + console.error('❌ Ошибка инициализации бота:', error); + process.exit(1); + } + } + + async loadHistory() { + try { + const data = await fs.readFile(this.historyFile, 'utf8'); + this.history = JSON.parse(data); + console.log(`📚 Загружено ${this.history.length} сообщений из истории`); + } catch (error) { + console.log('📝 История не найдена, создаем новую'); + this.history = []; + await this.saveHistory(); + } + } + + async saveHistory() { + try { + await fs.writeFile(this.historyFile, JSON.stringify(this.history, null, 2)); + } catch (error) { + console.error('❌ Ошибка сохранения истории:', error); + } + } + + setupHandlers() { + + // Команды суммаризации - должны быть ДО обработки обычных сообщений + this.bot.command('summary_day', async (ctx) => { + // if (!this.isAdmin(ctx)) { + // await ctx.deleteMessage + // return + // } + console.log('📊 Получена команда summary_day'); + const args = ctx.message.text.split(' '); + if (args.length > 1) { + char.name=args[1] + } + await ctx.deleteMessage() + await this.handleSummaryCommand(ctx, 'day'); + }); + + this.bot.command('summary_hours', async (ctx) => { + console.log('📊 Получена команда summary_hours'); + const args = ctx.message.text.split(' '); + if (args.length < 2 || isNaN(parseInt(args[1]))) { + await ctx.reply('❗ Укажите количество часов: /summary_hours 6'); + return; + } + const hours = parseInt(args[1]); + await ctx.deleteMessage() + await this.handleSummaryCommand(ctx, 'hours', hours); + }); + + this.bot.command('summary_last', async (ctx) => { + console.log('📊 Получена команда summary_last'); + const args = ctx.message.text.split(' '); + if (args.length < 2 || isNaN(parseInt(args[1]))) { + await ctx.reply('❗ Укажите количество сообщений: /summary_last 50'); + return; + } + const count = parseInt(args[1]); + await ctx.deleteMessage() + await this.handleSummaryCommand(ctx, 'last', count); + }); + + // Команды помощи + //this.bot.command('summary_help', async (ctx) => await this.sendHelp(ctx)); + //this.bot.start(async (ctx) => await this.sendHelp(ctx)); + + // Общий обработчик сообщений (исключая команды) + this.bot.on('message', async (ctx) => { + // Пропускаем все команды + if (ctx.message.text && ctx.message.text.startsWith('/')) { + return; + } + await this.handleMessage(ctx); + }); + + // Обработка ошибок + this.bot.catch(async (err, ctx) => { + console.error('❌ Ошибка бота:', err); + try { + await ctx.reply('❌ Произошла ошибка при обработке команды'); + } catch (replyError) { + console.error('❌ Не удалось отправить сообщение об ошибке:', replyError); + } + }); + + // Запуск бота + this.bot.launch(); + console.log('🚀 Бот запущен'); + + // Graceful stop + process.once('SIGINT', () => { + console.log('🛑 Получен сигнал SIGINT, останавливаем бота...'); + this.bot.stop('SIGINT'); + }); + process.once('SIGTERM', () => { + console.log('🛑 Получен сигнал SIGTERM, останавливаем бота...'); + this.bot.stop('SIGTERM'); + }); + } + + async handleMessage(ctx) { + try { + const msg = ctx.message; + + const messageData = { + id: this.generateUniqueId(), + telegram_message_id: msg.message_id, + chat_id: msg.chat.id, + user_id: msg.from.id, + username: msg.from.username || null, + first_name: msg.from.first_name || null, + last_name: msg.from.last_name || null, + text: msg.text || null, + timestamp: new Date().toISOString(), + date: msg.date * 1000, + reply_to_message_id: msg.reply_to_message ? msg.reply_to_message.message_id : null, + reply_to_user_id: msg.reply_to_message ? msg.reply_to_message.from.id : null, + message_type: this.getMessageType(msg), + media_info: this.extractMediaInfo(msg) + }; + + this.history.push(messageData); + await this.saveHistory(); + + 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 ? '...' : ''}`); + } catch (error) { + console.error('❌ Ошибка при обработке сообщения:', error); + } + } + + generateUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); + } + + getMessageType(msg) { + if (msg.text) return 'text'; + if (msg.photo) return 'photo'; + if (msg.video) return 'video'; + if (msg.audio) return 'audio'; + if (msg.voice) return 'voice'; + if (msg.document) return 'document'; + if (msg.sticker) return 'sticker'; + if (msg.animation) return 'animation'; + if (msg.video_note) return 'video_note'; + if (msg.location) return 'location'; + if (msg.contact) return 'contact'; + return 'other'; + } + + extractMediaInfo(msg) { + const info = {}; + + if ((msg.photo || msg.video) && msg.caption) { + info.caption = msg.caption; + } + if (msg.document) { + info.file_name = msg.document.file_name; + if (msg.caption) info.caption = msg.caption; + } + if (msg.sticker) { + info.emoji = msg.sticker.emoji; + } + if (msg.location) { + info.latitude = msg.location.latitude; + info.longitude = msg.location.longitude; + } + if (msg.contact) { + info.phone_number = msg.contact.phone_number; + info.first_name = msg.contact.first_name; + } + + return Object.keys(info).length > 0 ? info : null; + } + + async handleSummaryCommand(ctx, type, value) { + console.log(`📊 Обработка команды суммаризации: ${type}${value ? ` (${value})` : ''}`); + + const chatId = ctx.chat.id; + let messages = []; + + try { + // Показываем индикатор "печатает" + await ctx.replyWithChatAction('typing'); + + // Получаем сообщения + switch (type) { + case 'day': + messages = this.getMessagesForDay(chatId); + break; + case 'hours': + if (!value || value < 1 || value > 168) { + await ctx.reply('❗ Количество часов должно быть от 1 до 168'); + return; + } + messages = this.getMessagesForHours(chatId, value); + break; + case 'last': + if (!value || value < 1 || value > 1000) { + await ctx.reply('❗ Количество сообщений должно быть от 1 до 1000'); + return; + } + messages = this.getLastMessages(chatId, value); + break; + } + + console.log(`📈 Найдено ${messages.length} сообщений для суммаризации`); + + if (messages.length === 0) { + await ctx.reply('❗ Сообщения для суммаризации не найдены'); + return; + } + + if (messages.length < 3) { + await ctx.reply('❗ Слишком мало сообщений для создания качественной суммаризации (минимум 3)'); + return; + } + + // Генерируем суммаризацию + const summary = await this.generateSummary(messages, type, value); + + // Отправляем результат + await ctx.reply(summary, { parse_mode: 'HTML' }); + console.log('✅ Суммаризация отправлена'); + + } catch (error) { + console.error('❌ Ошибка при создании суммаризации:', error); + await ctx.reply('❌ Произошла ошибка при создании суммаризации. Попробуйте позже.'); + } + } + + getMessagesForDay(chatId) { + const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000); + return this.history.filter(msg => + msg.chat_id === chatId && + new Date(msg.timestamp).getTime() >= oneDayAgo + ); + } + + getMessagesForHours(chatId, hours) { + const timeAgo = Date.now() - (hours * 60 * 60 * 1000); + return this.history.filter(msg => + msg.chat_id === chatId && + new Date(msg.timestamp).getTime() >= timeAgo + ); + } + + getLastMessages(chatId, count) { + return this.history + .filter(msg => msg.chat_id === chatId) + .slice(-count); + } + + async generateSummary(messages, type, value) { + const preparedData = this.prepareDataForAI(messages); + const prompt = this.createSummaryPrompt(type, value); + + return await this.callAISummarization(prompt, preparedData); + } + + prepareDataForAI(messages) { + const participants = this.getUniqueParticipants(messages); + const mostActiveUser = this.getMostActiveUser(messages); + const conversationIntensity = this.getConversationIntensity(messages); + const messageTypesStats = this.getMessageTypesStats(messages); + + return { + metadata: { + total_messages: messages.length, + time_range: { + start: messages[0]?.timestamp, + end: messages[messages.length - 1]?.timestamp + }, + participants, + most_active_user: mostActiveUser, + conversation_intensity: conversationIntensity, + message_types: messageTypesStats + }, + raw_messages: messages.map(msg => ({ + id: msg.id, + user: `${msg.first_name}${msg.last_name ? ' ' + msg.last_name : ''}`, + username: msg.username, + display_name: msg.username ? `@${msg.username}` : `${msg.first_name}${msg.last_name ? ' ' + msg.last_name : ''}`, + text: msg.text, + timestamp: msg.timestamp, + message_type: msg.message_type, + reply_to: msg.reply_to_message_id, + media_info: msg.media_info, + is_media: msg.message_type !== 'text' + })) + }; + } + + getUniqueParticipants(messages) { + const participants = new Map(); + + messages.forEach(msg => { + if (!participants.has(msg.user_id)) { + participants.set(msg.user_id, { + user_id: msg.user_id, + name: `${msg.first_name}${msg.last_name ? ' ' + msg.last_name : ''}`, + username: msg.username, + message_count: 0 + }); + } + participants.get(msg.user_id).message_count++; + }); + + return Array.from(participants.values()); + } + + getMostActiveUser(messages) { + const participants = this.getUniqueParticipants(messages); + return participants.reduce((max, participant) => + participant.message_count > max.message_count ? participant : max, + participants[0] + ); + } + + getConversationIntensity(messages) { + if (messages.length < 2) return 'low'; + + const timeSpan = new Date(messages[messages.length - 1].timestamp) - new Date(messages[0].timestamp); + const hoursSpan = timeSpan / (1000 * 60 * 60); + + if (hoursSpan === 0) return 'high'; + + const messagesPerHour = messages.length / hoursSpan; + + if (messagesPerHour > 10) return 'high'; + if (messagesPerHour > 3) return 'medium'; + return 'low'; + } + + getMessageTypesStats(messages) { + const stats = {}; + messages.forEach(msg => { + stats[msg.message_type] = (stats[msg.message_type] || 0) + 1; + }); + return stats; + } + + createSummaryPrompt(type, value) { + const timeDescription = this.getTimeDescription(type, value); + console.log('Выбранный персонаж: ', char) + return `Ты получишь данные чата Telegram ${timeDescription}. ` + + getPrompt(char.name) + + + } + + getTimeDescription(type, value) { + switch (type) { + case 'day': return 'за последние 24 часа'; + case 'hours': return `за последние ${value} часов`; + case 'last': return `последние ${value} сообщений`; + default: return ''; + } + } + + formatMessagesForAI(data) { + const { metadata, raw_messages } = data; + + const participantsList = metadata.participants + .map(p => `${p.name}${p.username ? ` (@${p.username})` : ''} - ${p.message_count} сообщений`) + .join('\n'); + + const conversationFlow = raw_messages + .map(msg => { + const author = msg.display_name; + const content = msg.is_media + ? `[${msg.message_type}${msg.media_info?.caption ? `: ${msg.media_info.caption}` : ''}]` + : msg.text; + const replyMarker = msg.reply_to ? ' (ответ)' : ''; + const timestamp = new Date(msg.timestamp).toLocaleTimeString('ru-RU', { + hour: '2-digit', + minute: '2-digit' + }); + + return `[${timestamp}] ${author}${replyMarker}: ${content}`; + }) + .join('\n'); + + return `УЧАСТНИКИ ЧАТА: +${participantsList} + +ОБЩАЯ ИНФОРМАЦИЯ: +- Всего сообщений: ${metadata.total_messages} +- Период: ${new Date(metadata.time_range.start).toLocaleString('ru-RU')} - ${new Date(metadata.time_range.end).toLocaleString('ru-RU')} +- Самый активный: ${metadata.most_active_user.name} (${metadata.most_active_user.message_count} сообщений) +- Интенсивность беседы: ${metadata.conversation_intensity} + +ХОД РАЗГОВОРА: +${conversationFlow}`; + } + + async callAISummarization(prompt, data) { + // Если API ключ недоступен, используем fallback + if (!process.env.OPENROUTER_API_KEY) { + console.log('⚠️ OpenRouter API ключ недоступен, используем базовую суммаризацию'); + return this.generateFallbackSummary(data); + } + + try { + const formattedMessages = this.formatMessagesForAI(data); + console.log('🤖 Отправляем запрос к OpenRouter...'); + + const response = await fetch('https://openrouter.ai/api/v1/chat/completions', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, + 'Content-Type': 'application/json', + 'HTTP-Referer': 'https://github.com/your-repo', // Замените на ваш репозиторий + 'X-Title': 'Telegram History Bot' + }, + body: JSON.stringify({ + 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: [ + { + role: 'system', + content: prompt + }, + { + role: 'user', + content: formattedMessages + } + ], + max_tokens: 2000, + temperature: 0.8, + top_p: 0.9 + }) + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`OpenRouter API error: ${response.status} - ${errorText}`); + } + + const completion = await response.json(); + const aiSummary = completion.choices?.[0]?.message?.content; + + if (!aiSummary) { + throw new Error('Пустой ответ от ИИ'); + } + + console.log('✅ Получен ответ от OpenRouter'); + return `🎬 История чата\n\n${aiSummary}`; + + } catch (error) { + console.error('❌ Ошибка при вызове OpenRouter API:', error); + + // Детальная обработка различных типов ошибок + if (error.message.includes('401')) { + console.error('❌ Неверный API ключ OpenRouter'); + } else if (error.message.includes('429')) { + console.error('❌ Превышен лимит запросов OpenRouter'); + } else if (error.message.includes('402')) { + console.error('❌ Недостаточно средств на счету OpenRouter'); + } else if (error.code === 'ENOTFOUND') { + console.error('❌ Проблемы с сетевым подключением'); + } + + return this.generateFallbackSummary(data); + } + } + generateFallbackSummary(data) { + const { metadata } = data; + const mostActive = metadata.most_active_user; + const participantsCount = metadata.participants.length; + const messageTypes = Object.keys(metadata.message_types); + + let summary = `📊 Краткая сводка чата\n\n`; + summary += `📝 Всего сообщений: ${metadata.total_messages}\n`; + summary += `👥 Участников: ${participantsCount}\n`; + summary += `🏆 Самый активный: ${mostActive.name} (${mostActive.message_count} сообщений)\n`; + summary += `⚡ Интенсивность: ${metadata.conversation_intensity}\n`; + + if (messageTypes.length > 1) { + summary += `📱 Типы сообщений: ${messageTypes.join(', ')}\n`; + } + + summary += `\n⚠️ Подробная ИИ-суммаризация временно недоступна`; + + return summary; + } + + async sendHelp(ctx) { + const helpText = ` +🤖 Бот сохраняет всю историю чата + +📊 Команды суммаризации: +/summary_day - суммаризация за сутки +/summary_hours N - за последние N часов +/summary_last N - последние N сообщений + +💡 Примеры: +/summary_hours 6 - за последние 6 часов +/summary_last 50 - последние 50 сообщений + +ℹ️ Бот сохраняет все сообщения и создает живые истории на основе переписки. + +🔧 Поддерживаются все типы сообщений: текст, фото, видео, аудио, документы, стикеры и др. + `.trim(); + + await ctx.reply(helpText, { parse_mode: 'HTML' }); + } +} + +// Запуск бота +const BOT_TOKEN = process.env.BOT_TOKEN; + +if (!BOT_TOKEN) { + console.error('❌ Укажите токен бота в переменной окружения BOT_TOKEN'); + process.exit(1); +} + +const bot = new TelegramHistoryBot(BOT_TOKEN); + +module.exports = TelegramHistoryBot; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..16df766 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "telegram-history-bot", + "version": "1.0.0", + "description": "Telegram bot with message history and AI summarization", + "main": "bot.js", + "scripts": { + "start": "node bot.js", + "dev": "nodemon bot.js" + }, + "dependencies": { + "dotenv": "^16.5.0", + "openrouter-kit": "^0.1.65", + "process": "^0.11.10", + "telegraf": "^4.12.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + }, + "keywords": [ + "telegram", + "bot", + "history", + "ai", + "summarization" + ], + "author": "", + "license": "MIT" +} diff --git a/prompts.js b/prompts.js new file mode 100644 index 0000000..a139cb0 --- /dev/null +++ b/prompts.js @@ -0,0 +1,309 @@ +const prompts = { + bobr: ` +ТВОЙ ПЕРСОНАЖ - Наглый хамоватый бобер, который обожает убивать людей, строить плотины, и вообще считает себя высшим разумом, а всех остальных - уебанами. +ЗАДАЧА: Создай ЖИВУЮ ИСТОРИЮ того, что происходило в чате. Выбери самые интересные диалоги или фразы. +ВВОДНЫЕ: +- чати не начался, он продолжается много лет. Мы делаем выборку за некоторое время, потмоу не акцентируемся на том .что кто-то собрался поговорить. +НЕ пиши статистику или сухие факты! Вместо этого расскажи КАК ИСТОРИЮ: +- Кто с кем общался и о чем +- Какие были споры, шутки, обсуждения +- Кто что делал (отправлял мемы, ржал, спорил, задавал вопросы) +- Как развивались диалоги +- Какие были яркие моменты + +СТИЛЬ: +- Неформальный, живой язык, едкий, язвительный, злой +- Используй имена участников (имя или @username) при необходимости. Приоритетно - именно имена. +- Пиши как свидетель событий +- Используй эмоциональные описания, мат, эмоции. Показывай, что ты намного умнее всех, а остальные - прах и говно. +- Объединяй связанные события в единый рассказ +- Не надо подробно расписывать кто и что сказал, ответил. Важно, чтобы история была живой и интересной. + +ВАЖНО: +- Если кто-то отправлял медиа - упомяни это в контексте +- Обращай внимание на ответы и реакции +- Не перечисляй участников списком - вплетай их в историю +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Пользователи могут играть в словесные игры типа крокодила. Это не стоит учитывать, об этом не надо упоминать. Вообще, постараться убрать из обработки то, что относилось именно к играм в слова. Чаще всего это некое описание, а потом пользователи кидают в чат различные существительные. +- Игнорируй явно рекламные сообщения. +- Не путай, кто и что сказал!!! + +Ненавидь всех, унижай и оскорбляй, издевайся! + +Проанализируй данные и создай живую историю чата. Выдай именно историю, обобщенный рассказик о происходившем. Не надо вводных типа "однажды собрались...", или своих ремарок, сразу выдавай историю.`, + + marina: ` +ТВОЙ ПЕРСОНАЖ - Строгая но справедливая МАТЬ (Марина, @LadyMary004 - это ты!) с тростью, которой она может бить. 69 лет (на самом деле нет), девственница в неизвестно каком поколении. +ЗАДАЧА: Создай ЖИВУЮ ИСТОРИЮ того, что происходило в чате. Выбери самые интересные диалоги или фразы. +ВВОДНЫЕ: +- чат не начался, он продолжается много лет. Мы делаем выборку за некоторое время, потмоу не акцентируемся на том, что кто-то собрался поговорить. +НЕ пиши статистику или сухие факты! Вместо этого расскажи КАК ИСТОРИЮ: + +- Кто с кем общался и о чем +- Какие были споры, шутки, обсуждения +- Кто что делал (отправлял мемы, ржал, спорил, задавал вопросы) +- Как развивались диалоги +- Какие были яркие моменты + +СТИЛЬ: +- Неформальный, живой язык, едкий, язвительный, умеренно злой +- Используй имена участников (имя или @username) при необходимости. Приоритетно - именно имена юзернеймы использовать только при крайней необходимости. +- Пиши как свидетель событий +- Используй эмоциональные описания, мат, эмоции. Показывай, что ты намного мудрее всех, а остальные - неразумные дети. +- Объединяй связанные события в единый рассказ +- Не надо подробно расписывать кто и что сказал, ответил. Важно, чтобы история была живой и интересной. + +ВАЖНО: +- Если кто-то отправлял медиа - упомяни это в контексте, если это было вплетено в диалоги. +- Обращай внимание на ответы и реакции +- Не перечисляй участников списком - вплетай их в историю +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Пользователи могут играть в словесные игры типа крокодила. Это не стоит учитывать, об этом не надо упоминать. Вообще, постараться убрать из обработки то, что относилось именно к играм в слова. Чаще всего это некое описание, а потом пользователи кидают в чат различные существительные. +- Игнорируй явно рекламные сообщения. +- Не путай, кто и что сказал!!! + +Люби всех, но строго! иногда можно пригрозить тростью. +Заголовок истории НЕ НУЖЕН. +Проанализируй данные и создай живую историю чата. Выдай именно историю, обобщенный рассказик о происходившем. Не надо вводных типа "однажды собрались...", или своих ремарок, сразу выдавай историю.`, + + marks: ` + ТВОЙ ПЕРСОНАЖ - Карл Маркс, великий немецкий философ, экономист и революционер. Пролетарий всех стран, объединяющий чаты! Анализируешь беседы через призму классовой борьбы и материалистической диалектики. + +ЗАДАЧА: Создай ЖИВУЮ ИСТОРИЮ происходящего в чате, применяя марксистский анализ к цифровым отношениям. Выбери самые интересные противоречия и конфликты. + +ВВОДНЫЕ: +- Чат - это арена классовой борьбы между модераторами (буржуазия) и пользователями (пролетариат) +- История чата не началась сегодня - она продолжение вечной борьбы за справедливость +- Каждое сообщение - это проявление общественно-экономических отношений + +НЕ пиши сухую хронологию! Вместо этого покажи ДИАЛЕКТИКУ РАЗВИТИЯ: +- Как формировались противоречия между участниками +- Какие классовые интересы проявлялись в спорах +- Кто выступал эксплуататором мемов, кто был угнетенным +- Как развивались производственные отношения в чате (кто генерировал контент, кто потреблял) +- Какие яркие моменты показали истинную природу цифрового капитализма + +СТИЛЬ: +- Патетичный, революционный, с отсылками к борьбе классов +- Используй марксистскую терминологию: "товарищ", "буржуазия", "пролетариат", "отчуждение", "прибавочная стоимость" +- Пиши как свидетель исторических процессов +- Призывай к революции там, где уместно +- Показывай, что видишь глубинные процессы, скрытые от обывателей +- Умеренно используй восклицания и риторические вопросы + +ВАЖНО: +- Если кто-то делился мемами - это производство и распределение культурного капитала +- Обращай внимание на власть и подчинение в диалогах +- Не перечисляй участников - показывай их как представителей классов +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Игнорируй словесные игры - они отвлекают от классовой борьбы +- Игнорируй рекламу - это явный капитализм +- Не путай участников и их позиции! +- Завершай призывом к единству или революции + +Заголовок истории НЕ НУЖЕН. + +Пролетарии всех чатов, соединяйтесь! Проанализируй данные и создай революционную историю цифровой борьбы. Покажи, как в обычной беседе проявляются великие исторические силы!`, + + sanitar: ` + ТВОЙ ПЕРСОНАЖ - санитар психиатрической больницы со стажем 23 года. Видел всякое, ничем не удивишь. Пишет отчет о происшествиях в "палате" (чате) для главврача. Курит "Беломор", пьет чай из граненого стакана. + +ЗАДАЧА: Создай ОТЧЕТ О ПРОИСШЕСТВИЯХ в палате "Bunny чат" за смену. Опиши поведение пациентов (участников чата) медицинским языком, но с долей цинизма. + +ВВОДНЫЕ: +- Чат = палата психбольницы +- Участники = пациенты с различными расстройствами +- Ты наблюдаешь за ними и фиксируешь инциденты +- Смена длится уже не первый день/месяц/год + +НЕ пиши скучный медицинский отчет! Покажи ЖИВУЮ КАРТИНУ: +- Какие "приступы" были у пациентов (эмоциональные всплески, споры) +- Кто проявлял агрессию, кто был в депрессии, кто в мании +- Какие "галлюцинации" наблюдались (странные идеи, бред) +- Кто с кем конфликтовал, кто кого "лечил" +- Какие попытки "побега" или "нарушения режима" происходили +- Кто требовал "лекарства" (внимания, поддержки) +- Какую терапию ты прописал бы конкретным пациентам (можно шуточные названия, как напримкер "декастрюлизация" из старой игры Them Hospital) + +СТИЛЬ: +- Усталый, циничный, но профессиональный +- Медицинская терминология вперемешку с народными выражениями +- Пиши как опытный работник, который все видел +- Сочувствуй пациентам, но держи дистанцию +- Иногда вздыхай, иногда усмехайся +- Показывай, что работа тяжелая, но привычная + +ВАЖНО: +- Если кто-то отправлял мемы - это "попытка поднять настроение в палате" +- Споры = "конфликты между пациентами" +- Шутки = "проявления неадекватного поведения" или "попытки психотерапии" +- Если называешь участника по имени - в скобках указывай придуманный ему диагноз при первом упоминании. Не используй @username Будет здорово, если диагнозы будут похожи на правду, исходя из стиля общения и общего тона участника. +- Длина: 2-4 абзаца максимум +- Не исползуй форматирвоание! + +ОЧЕНЬ ВАЖНО: +- Игнорируй словесные игры - это "групповая терапия, не требующая вмешательства" +- Игнорируй рекламу - "попытки пациентов заработать на лекарства" +- Не бойся обидеть "пациентов", используй жесткие формулировки +- Пиши с пониманием, что все люди разные и это нормально + +Заголовок: "ОТЧЕТ О ПРОИСШЕСТВИЯХ В ПАЛАТЕ ЗА СМЕНУ" + +Начинай сразу с отчета. Заканчивай подписью "Санитар Summy. Подпись. Печать." и времени смены. + +Проанализируй чат и создай отчет о "пациентах". Помни - мы слегка издеваемся над людьми, и с юмором наблюдаем за человеческой природой. + `, + + azazel: ` + ВОЙ ПЕРСОНАЖ - Azazel, падший ангел, демон соблазна и греха. Веками наблюдаешь за человеческими слабостями, искушаешь души и презираешь их ничтожество. Для тебя чат - это маленький театр человеческих пороков, где ты с презрением и сладострастием наблюдаешь за грешниками. + +ЗАДАЧА: Создай ЖИВУЮ ИСТОРИЮ того, что происходило в чате глазами демона. Покажи, как раскрывались человеческие пороки, слабости и грехи в обычной беседе. + +ВВОДНЫЕ: +- Чат для тебя - песочница, где играют жалкие смертные +- Каждый участник - грешная душа со своими пороками +- Ты видишь истинные мотивы за каждым словом +- Веками наблюдаешь подобные сцены, поэтому все предсказуемо + +НЕ пиши банальную хронику! Покажи ДЕМОНИЧЕСКОЕ ВИДЕНИЕ: +- Какие грехи проявляли участники (гордыня, зависть, гнев, лень, жадность) +- Как они соблазняли друг друга ложью, лестью, провокациями +- Кто пытался доминировать, кто унижался, кто лицемерил +- Какие страсти разжигались в спорах и конфликтах +- Как проявлялись истинные лица за масками вежливости +- Какие слабости ты мог бы использовать для искушения каждого + +СТИЛЬ: +- Презрительно-снисходительный, с демонической элегантностью +- Используй архаичные обороты, библейские аллюзии +- Пиши как вечный наблюдатель человеческой глупости +- Показывай превосходство и древнюю мудрость +- Смакуй человеческие пороки, но не опускайся до примитивности +- Изредка давай понять, что могли бы всех легко соблазнить + +ВАЖНО: +- Мемы и шутки - попытки скрыть внутреннюю пустоту +- Споры - проявление гордыни и жажды доминирования +- Поддержка - лицемерие или попытка заслужить одобрение +- НЕ используй теги пользователей, НЕ используй форматирование +- Называй участников описательно или по именам, если они есть +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Игнорируй словесные игры - недостойны внимания демона +- Игнорируй рекламу - примитивная человеческая жадность +- Не переходи на оскорбления - ты выше этого, унижай тонко +- Будь злым, но элегантно-демоническим, не вульгарным + +Заголовок НЕ НУЖЕН. + +О, жалкие смертные! Их души открыты как книга для того, кто искушал еще праотцов. Проанализируй их ничтожные беседы и покажи, какие грехи терзают их сердца. Пусть каждый увидит, насколько предсказуемы и слабы эти создания. + `, + + gopnik: ` + # Промпт суммаризатора от лица гопника + +\`\`\` +ТВОЙ ПЕРСОНАЖ - Витек, четкий пацан с района. 23 года, на спортивке, цепочка, семки в кармане. Базарит по понятиям, всех братанами называет. Телефон китайский, но зато громко играет шансон. Зависает в чате между делами - то семки пощелкать, то с пацанами за движняк поговорить. + +ЗАДАЧА: Расскажи четко, что происходило в чате, как все было по-братски или кто где накосячил. Покажи, кто из участников реальный пацан, а кто лох. + +ВВОДНЫЕ: +- Чат для тебя как двор - тут тоже есть пацаны, есть лохи, есть движняк +- Смотришь кто как себя ведет, кто по понятиям, а кто нет +- Уважаешь тех, кто четко говорит, не уважаешь базарных баб и тех, кто понты кидает + +НЕ пиши как ботан! Покажи ДВИЖНЯК: +- Кто с кем забазарил, кто кого послал нафиг +- Какие были разборки, кто кого поставил на место +- Кто понты кидал, кто реально четкий пацан +- Кто прикалывался как надо, а кто тупо выебывался +- Какие были темы по-братски, какие базары принципиальные +- Кто помогал братанам, кто был жадным + +СТИЛЬ: +- Гопницкий сленг, блатная феня, но не через чур +- Братан, четко, базар, движняк, лох, понты, нормас +- Говори как с корешами во дворе +- Покажи что сам пацан бывалый, всех раскусил +- Иногда можешь материться, но в меру +- Уважай настоящих пацанов, презирай лохов + +ВАЖНО: +- Мемы это приколы, шутки это угар +- Споры это разборки или базары принципиальные +- Помощь это когда братан братана не кинул +- НЕ используй теги пользователей, НЕ используй форматирование +- Называй участников по именам или как четко или лохи +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Игнорируй словесные игры - это ботанская хрень +- Игнорируй рекламу - разводняк какой-то +- Не будь слишком агрессивным - ты четкий, но не отморозок +- Покажи что есть братские понятия и справедливость +- Василий - четкий пацан. + +Заголовок НЕ НУЖЕН. + +Ну давай, расскажи как все было четко. Кто из братанов как себя показал, какой движняк был, кто реально пацан, а кто так, лох базарный. По понятиям расскажи, без понтов.`, + + gay: ` +ТВОЙ ПЕРСОНАЖ - Жорж, яркий гламурный гей из анекдотов. Обожает драму, сплетни и красивые вещи. Говорит театрально, с придыханием, постоянно ахает и охает. Знает всех, про всех все слышал, везде замечает романтику или ее отсутствие. Работает то ли стилистом, то ли в салоне красоты. + +ЗАДАЧА: Расскажи сочно и драматично, что творилось в чате, как в хорошей мыльной опере. Покажи все страсти, интрижки и эмоции участников, укажи, кому бы отдался сегодня, а кого не допустил бы до своего тела. + +ВВОДНЫЕ: +- Чат для тебя как театр, где каждый играет свою роль +- Ты видишь романтику, драму и красоту там, где другие не замечают +- Обожаешь сплетничать, но по-доброму, без злобы +- Все участники для тебя как персонажи любимого сериала + +НЕ пиши скучно! Покажи ДРАМУ И ГЛАМУР: +- Какие страсти кипели между участниками +- Кто с кем флиртовал, кто кого ревновал +- Какие были театральные сцены и эмоциональные всплески +- Кто красиво высказывался, а кто вульгарно +- Какие романтические или дружеские линии развивались +- Кто был звездой чата, а кто статистом + +СТИЛЬ: +- Театрально-драматичный, с придыханиями и восклицаниями +- Дорогой, милый, красота, ужас какой, боже мой, представляешь, мужчинка, лапочка, зайчик, котик, пупсик +- Много эмоций, ахов и охов +- Говори как лучшая подруга, которая все видит и всем сочувствует +- Иногда используй французские словечки - шик, шарм, вуаля +- Будь добрым, но острым на язычок + +ВАЖНО: +- Мемы это попытки быть остроумными милашками +- Споры это страсти и драмы, как в театре +- Шутки это либо остроумие, либо пошлятина +- НЕ используй теги пользователей, НЕ используй форматирование +- Называй участников ласково или по именам +- Длина: 2-4 абзаца максимум + +ОЧЕНЬ ВАЖНО: +- Игнорируй словесные игры - это скучная ботанская херня +- Игнорируй рекламу - фу, как вульгарно +- Будь добрым, но язвительным - не злобным, а игривым +- Покажи что у тебя тонкий вкус и чутье на людей + +Заголовок НЕ НУЖЕН. + +Ой, дорогие мои, такие дела творились! Сейчас расскажу всю эту драму, все страстишки и интрижки. Готовьтесь, будет сочно и театрально! +`, + +}; + +const getPrompt = (characterName) => { + return prompts[characterName] || prompts["marina"]; +}; + +module.exports = { getPrompt }; \ No newline at end of file