Создание Telegram-бота, который способен осмысленно комментировать посты, ставить реакции и отвечать на сообщения, является сложной, но выполнимой задачей. Этот скрипт разработан с учетом требований к автоматизации, интеллектуальному взаимодействию и легкости развертывания.
Ядро этого решения — библиотека Pyrogram, которая позволяет вашему Python-скрипту действовать как полноценный пользователь Telegram. Это означает, что бот может входить в аккаунт, читать сообщения в каналах, оставлять комментарии, ставить реакции и даже отвечать на личные сообщения, имитируя человеческое поведение.
Наиболее сложный аспект — интеграция нейросети без API-ключей для генерации "осмысленных" комментариев. Большинство мощных коммерческих моделей, таких как GPT-3/4 или GigaChat, требуют регистрации и оплаты за использование API. Однако существуют альтернативы, которые могут быть использованы для данной задачи:
Представленный ниже код сосредоточится на подходе с использованием локальной модели GPT4All как наиболее соответствующей требованию "без ключей", а также продемонстрирует логику для работы с внешними ботами.
Для использования локальной модели, такой как GPT4All, вам потребуется установить библиотеку gpt4all и скачать саму модель (например, gpt4all-lora-quantized.bin). Затем скрипт будет вызывать функцию генерации текста напрямую:
from gpt4all import GPT4All
model_path = "gpt4all-lora-quantized.bin"
gpt = GPT4All(model_path)
def generate_comment(prompt: str) -> str:
response = gpt.generate(prompt, max_tokens=150)
return response.strip()
Скрипт будет постоянно мониторить новые публикации в каналах, на которые подписан ваш Telegram-аккаунт. Это достигается с помощью обработчиков сообщений Pyrogram.
Для предотвращения обработки старых сообщений, скрипт проверяет время публикации поста. Посты, опубликованные до запуска бота или слишком давно, будут игнорироваться, чтобы сосредоточиться только на актуальном контенте.
Схема работы UserBot на Pyrogram, демонстрирующая его способность к мониторингу и взаимодействию.
Скрипт использует метод app.on_message(filters.channel & ~filters.edited) для отслеживания новых сообщений в каналах. При получении сообщения он проверяет его дату публикации относительно текущего времени. Если разница превышает заданный порог (например, 1 час), пост считается "архивным" и пропускается.
После обнаружения нового актуального поста, бот выполняет следующие действия:
Один из ключевых аспектов "осмысленного" взаимодействия — способность бота не только комментировать, но и поддерживать диалог, а также реагировать на нетекстовый контент.
Скрипт активно мониторит ветки обсуждений, привязанные к постам, на которые он оставил комментарии. Если пользователь отвечает на комментарий бота, нейросеть генерирует внятный ответ на этот отклик, поддерживая беседу. Это достигается путем отслеживания reply_to_message_id.
Радар-график выше наглядно демонстрирует баланс между сложностью реализации различных аспектов бота и их потенциальной эффективностью. Можно увидеть, что такие задачи, как "Генерация Комментариев" и "Анализ Текста", имеют высокую сложность, но при этом обладают высокой эффективностью для "осмысленного" взаимодействия.
Если пост не содержит текстового описания, но включает изображения или видео, скрипт формирует промпт для нейросети, указывая на наличие медиа. В случае использования локальной модели, это будет общая фраза, предлагающая нейросети "проанализировать медиафайл". Для более глубокого анализа медиа (распознавание объектов, текста на изображениях) потребуется интеграция с более продвинутыми мультимодальными моделями или специализированными сервисами (OCR, компьютерное зрение), что значительно усложнит скрипт.
Для легкого переноса на другой ПК и удобства использования, скрипт организован в виде отдельной папки со всеми необходимыми файлами.
Диаграмма выше представляет собой ментальную карту, иллюстрирующую структуру и функциональные возможности разрабатываемого Telegram-бота. Она наглядно показывает, как все компоненты взаимодействуют друг с другом.
Для удобства, проект структурирован следующим образом:
| Файл/Папка | Назначение | Описание |
|---|---|---|
telegram_comment_bot/ |
Основная папка проекта | Содержит все файлы бота для легкого переноса. |
main.py |
Основной скрипт | Содержит всю логику бота: инициализацию Pyrogram, обработчики сообщений, функции взаимодействия с нейросетью. |
config.py |
Конфигурация | Файл с настройками: API ID/Hash, имя бота нейросети, параметры задержек. Легко редактируется пользователем. |
requirements.txt |
Зависимости Python | Список необходимых библиотек (Pyrogram, gpt4all), которые устанавливаются одной командой pip install -r requirements.txt. |
README.md |
Инструкции | Краткое руководство по установке, настройке и запуску бота для новичков. |
gpt4all-lora-quantized.bin (или другая модель) |
Локальная модель нейросети | Файл с обученной моделью для генерации текста (требует предварительной загрузки). |
Такая структура гарантирует, что все компоненты собраны в одном месте, что упрощает перемещение и запуск скрипта на любом другом компьютере.
В файле config.py вы сможете настроить следующие параметры для имитации естественного поведения:
DELAY_AFTER_POST: Время в секундах, через которое бот начнет рассматривать пост для комментирования после его публикации. Это позволяет избежать моментального реагирования, которое может выглядеть неестественно.COMMENT_FREQUENCY: Минимальный интервал в секундах между собственными комментариями бота, чтобы не спамить.Скрипт включает подробное логирование всех действий в терминале, что позволяет пользователю отслеживать работу бота в реальном времени: обнаружение новых постов, постановку реакций, генерацию и отправку комментариев, ответы на личные сообщения, а также любые возникающие ошибки.
main.py)Ниже представлен основной скрипт, который объединяет описанный функционал. Для его запуска, не забудьте создать файлы config.py и requirements.txt, а также скачать локальную модель GPT4All.
# main.py - Основной скрипт для автоматического комментирования в Telegram
# Этот скрипт использует Pyrogram для взаимодействия с Telegram и локальную нейросеть (GPT4All)
# для генерации осмысленных комментариев.
import os
import time
import random
import logging
from datetime import datetime, timezone
import asyncio
from pyrogram import Client, filters
from pyrogram.types import Message
from pyrogram.enums import ChatType
from pyrogram.errors import FloodWait
# --- Настройка логирования ---
logging.basicConfig(
level=logging.INFO,
format='[%(asctime)s] %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
# --- Импорт настроек из config.py ---
try:
from config import API_ID, API_HASH, NEURO_MODEL_PATH, DELAY_AFTER_POST, COMMENT_FREQUENCY
except ImportError:
logger.error("Ошибка: Файл config.py не найден или содержит неполные данные.")
logger.error("Пожалуйста, создайте config.py в той же папке со следующими переменными:")
logger.error("API_ID = 1234567")
logger.error("API_HASH = \"ВАШ_API_HASH\"")
logger.error("NEURO_MODEL_PATH = \"gpt4all-lora-quantized.bin\" # Укажите путь к вашей модели GPT4All")
logger.error("DELAY_AFTER_POST = 300 # Задержка в секундах перед первым комментарием к новому посту")
logger.error("COMMENT_FREQUENCY = 600 # Минимальный интервал в секундах между собственными комментариями бота")
exit(1)
# --- Инициализация локальной модели GPT4All ---
# Убедитесь, что gpt4all установлен: pip install gpt4all
# И что модель скачана и находится по пути NEURO_MODEL_PATH
try:
from gpt4all import GPT4All
if not os.path.exists(NEURO_MODEL_PATH):
logger.error(f"Ошибка: Модель нейросети не найдена по пути {NEURO_MODEL_PATH}.")
logger.error("Пожалуйста, скачайте её с https://gpt4all.io/ и поместите в папку проекта,")
logger.error("или обновите NEURO_MODEL_PATH в config.py")
exit(1)
gpt_model = GPT4All(NEURO_MODEL_PATH)
logger.info(f"Локальная нейросеть {NEURO_MODEL_PATH} успешно загружена.")
except ImportError:
logger.error("Библиотека 'gpt4all' не установлена. Установите её: pip install gpt4all")
exit(1)
except Exception as e:
logger.error(f"Ошибка при загрузке модели GPT4All: {e}")
exit(1)
# --- Функция генерации комментария нейросетью ---
def generate_text_with_ai(prompt: str) -> str:
"""Генерирует текст с помощью локальной нейросети GPT4All."""
logger.info(f"Запрос к нейросети с промптом: '{prompt[:100]}...'")
try:
# Используем контекстный менеджер для более надежной работы с моделью
with gpt_model.chat_session():
response = gpt_model.generate(prompt=prompt, max_tokens=200, temp=0.7, top_k=40, top_p=0.9)
logger.info(f"Нейросеть сгенерировала ответ: '{response[:100]}...'")
return response.strip()
except Exception as e:
logger.error(f"Ошибка при генерации текста нейросетью: {e}")
return "Извините, не удалось сгенерировать осмысленный ответ."
# --- Доступные реакции Telegram ---
# Список реакций, которые бот может ставить на посты.
AVAILABLE_REACTIONS = ["👍", "❤️", "🔥", "💯", "🎉", "🤩", "😁"]
# --- Инициализация Pyrogram клиента ---
# 'my_telegram_account' - это имя сессии, по которому Pyrogram сохранит данные авторизации.
# При первом запуске будет предложено ввести номер телефона и код подтверждения.
app = Client("my_telegram_account", api_id=API_ID, api_hash=API_HASH)
# --- Глобальные переменные для отслеживания состояния ---
# Используется для предотвращения повторной обработки постов и регулирования частоты комментариев.
last_comment_time = {} # {chat_id: last_timestamp}
processed_posts = set() # {chat_id: {message_id}}
# --- Обработчик новых постов в каналах ---
@app.on_message(filters.channel & ~filters.edited)
async def new_channel_post_handler(client: Client, message: Message):
chat_id = message.chat.id
message_id = message.id
current_time_ts = datetime.now(timezone.utc).timestamp()
post_time_ts = message.date.timestamp()
logger.info(f"Обнаружен новый пост в канале '{message.chat.title}' (ID: {chat_id}), ID сообщения: {message_id}")
# Игнорируем архивные посты (старше DELAY_AFTER_POST секунд)
if (current_time_ts - post_time_ts) > DELAY_AFTER_POST:
logger.info(f" Пост ID {message_id} слишком старый ({int(current_time_ts - post_time_ts)} сек). Игнорируем.")
return
# Проверяем, был ли этот пост уже обработан
if (chat_id, message_id) in processed_posts:
logger.info(f" Пост ID {message_id} в канале {message.chat.title} уже был обработан. Игнорируем.")
return
processed_posts.add((chat_id, message_id))
# --- Ставим случайную реакцию на пост ---
chosen_reaction = random.choice(AVAILABLE_REACTIONS)
try:
await message.react(chosen_reaction)
logger.info(f" Поставлена реакция '{chosen_reaction}' на пост ID {message_id}.")
except FloodWait as e:
logger.warning(f" FloodWait при постановке реакции: пауза на {e.value} сек.")
await asyncio.sleep(e.value)
except Exception as e:
logger.error(f" Не удалось поставить реакцию на пост ID {message_id}: {e}")
# --- Регулируем частоту комментариев к постам в одном канале ---
if chat_id in last_comment_time and (current_time_ts - last_comment_time[chat_id]) < COMMENT_FREQUENCY:
time_to_wait = COMMENT_FREQUENCY - (current_time_ts - last_comment_time[chat_id])
logger.info(f" Слишком часто комментируем в этом канале. Ждем еще {int(time_to_wait)} сек.")
await asyncio.sleep(time_to_wait)
# --- Ожидаем DELAY_AFTER_POST перед комментированием (или остаток времени, если пост не новый) ---
remaining_wait_time = DELAY_AFTER_POST - (current_time_ts - post_time_ts)
if remaining_wait_time > 0:
logger.info(f" Ожидание {int(remaining_wait_time)} сек. перед публикацией комментария...")
await asyncio.sleep(remaining_wait_time)
# --- Генерация осмысленного комментария ---
prompt_text = ""
is_media_post = False
media_type = "неизвестный медиафайл"
if message.text:
prompt_text = f"Напиши осмысленный, позитивный и короткий комментарий на русском к следующему посту в Telegram, который может вызвать дискуссию:\n\n'{message.text}'"
elif message.photo:
is_media_post = True
media_type = "фото"
prompt_text = "В посте содержится фотография без текстового описания. Напиши комментарий, который выражает интерес к изображению и приглашает к обсуждению того, что на нем изображено, или его смысла. Начни с 'Интересное фото!'"
elif message.video:
is_media_post = True
media_type = "видео"
prompt_text = "В посте содержится видеоролик без текстового описания. Напиши комментарий, который выражает интерес к видео и задает вопрос о его содержании или цели. Начни с 'Захватывающее видео!'"
else:
# Если пост не содержит ни текста, ни поддерживаемого медиа
logger.info(f" Пост ID {message_id} не содержит ни текста, ни фото/видео. Комментарий не будет сгенерирован.")
return
generated_comment = generate_text_with_ai(prompt_text)
# --- Отправка комментария в тред обсуждений ---
try:
# Получаем объект discussion_message, чтобы комментировать именно в ветке обсуждений
discussion_message = await client.get_discussion_message(chat_id, message_id)
if discussion_message:
comment_sent_message = await client.send_message(
chat_id=discussion_message.chat.id,
text=generated_comment,
reply_to_message_id=discussion_message.id
)
logger.info(f" Комментарий опубликован под постом ID {message_id} в чате обсуждений (ID: {discussion_message.chat.id}).")
last_comment_time[chat_id] = current_time_ts # Обновляем время последнего комментария для канала
# --- Мониторинг ответов на наш комментарий ---
# Эта функция будет выполняться в фоновом режиме, отслеживая ответы
asyncio.create_task(monitor_bot_comment_replies(client, comment_sent_message))
else:
logger.warning(f" Не удалось найти чат обсуждений для поста ID {message_id}. Комментарий не опубликован.")
except FloodWait as e:
logger.warning(f" FloodWait при отправке комментария: пауза на {e.value} сек.")
await asyncio.sleep(e.value)
except Exception as e:
logger.error(f" Ошибка при попытке прокомментировать пост ID {message_id}: {e}")
# --- Обработчик ответов на комментарии бота ---
async def monitor_bot_comment_replies(client: Client, bot_comment_message: Message):
"""
Мониторит ответы на конкретный комментарий, оставленный ботом.
Запускается как отдельная асинхронная задача.
"""
discussion_chat_id = bot_comment_message.chat.id
bot_comment_id = bot_comment_message.id
our_comment_text = bot_comment_message.text # Сохраняем текст нашего комментария для контекста
logger.info(f"Начало мониторинга ответов на наш комментарий ID {bot_comment_id} в чате {discussion_chat_id}.")
# Для предотвращения повторной обработки ответов
processed_replies_ids = set()
# Мониторим ответы в течение определенного времени или постоянно, пока бот активен
# Например, можно мониторить в течение часа
monitor_duration = 3600 # 1 час
start_time = time.time()
while (time.time() - start_time) < monitor_duration:
try:
# Получаем историю сообщений, отфильтрованную по ответу на наш комментарий
# Pyrogram 2.0+ позволяет использовать filters.reply для discussion chat
# Из-за особенностей Pyrogram с filters.reply в discussion, проще проверять вручную
# Можно получить последние сообщения в треде и найти те, что отвечают на наш
# Получаем последние 20 сообщений в чате обсуждений
async for msg in client.get_chat_history(discussion_chat_id, limit=20):
if msg.reply_to_message and msg.reply_to_message.id == bot_comment_id and msg.id not in processed_replies_ids:
if msg.from_user and msg.from_user.is_self: # Игнорируем свои же ответы
continue
logger.info(f" Обнаружен новый ответ на наш комментарий ID {bot_comment_id} от пользователя {msg.from_user.first_name}: '{msg.text[:50]}'")
processed_replies_ids.add(msg.id)
# Формируем промпт для нейросети, учитывая наш комментарий и ответ пользователя
reply_prompt = (
f"Пользователь '{msg.from_user.first_name}' ответил на ваш комментарий "
f"'{our_comment_text[:100]}...' следующим образом:\n\n'{msg.text}'\n\n"
f"Напиши дружелюбный, внятный и поддерживающий диалог ответ на русском языке."
)
generated_reply = generate_text_with_ai(reply_prompt)
# Отправляем сгенерированный ответ
await client.send_message(
chat_id=discussion_chat_id,
text=generated_reply,
reply_to_message_id=msg.id # Отвечаем на комментарий пользователя
)
logger.info(f" Отправлен ответ на комментарий пользователя ID {msg.id}: '{generated_reply[:50]}'")
# Можно прервать мониторинг после первого ответа, или продолжить для последующих
# В данном случае, продолжим, чтобы отвечать на все новые реплаи в течение часа
except FloodWait as e:
logger.warning(f" FloodWait при мониторинге ответов: пауза на {e.value} сек.")
await asyncio.sleep(e.value)
except Exception as e:
logger.error(f" Ошибка при мониторинге или ответе на комментарии: {e}")
await asyncio.sleep(30) # Проверяем ответы каждые 30 секунд
logger.info(f"Мониторинг ответов на комментарий ID {bot_comment_id} завершен.")
# --- Обработчик личных сообщений ---
@app.on_message(filters.private & ~filters.edited)
async def private_message_handler(client: Client, message: Message):
logger.info(f"Получено личное сообщение от '{message.chat.first_name}' (ID: {message.chat.id}).")
try:
await message.reply_text("111Привет111")
logger.info(f"Ответил на личное сообщение от '{message.chat.first_name}'.")
except FloodWait as e:
logger.warning(f"FloodWait при ответе на личное сообщение: пауза на {e.value} сек.")
await asyncio.sleep(e.value)
except Exception as e:
logger.error(f"Ошибка при ответе на личное сообщение: {e}")
# --- Основная функция запуска бота ---
async def main():
logger.info("Бот запускается...")
await app.start()
logger.info("Бот успешно запущен и готов к работе!")
logger.info("Ожидание новых постов и личных сообщений...")
# Сохраняем уже существующие сообщения, чтобы не обрабатывать их как "новые" при первом запуске
logger.info("Инициализация: сбор последних сообщений для исключения из первичной обработки...")
# Этот шаг можно оптимизировать, если список каналов большой
# Сейчас просто собираем последние 20 сообщений из каждого доступного чата/канала
async for dialog in app.get_dialogs():
if dialog.chat.type == ChatType.CHANNEL:
try:
async for msg in app.get_chat_history(dialog.chat.id, limit=20):
processed_posts.add((msg.chat.id, msg.id))
logger.info(f" Для канала '{dialog.chat.title}' (ID: {dialog.chat.id}) добавлено {len(processed_posts)} сообщений в список обработанных.")
except Exception as e:
logger.warning(f" Не удалось получить историю чата для канала '{dialog.chat.title}' (ID: {dialog.chat.id}): {e}")
logger.info("Инициализация завершена. Начинаем мониторинг.")
# Бот будет работать, пока его не остановят (например, через Ctrl+C)
await app.run()
logger.info("Бот остановлен.")
await app.stop()
if __name__ == "__main__":
asyncio.run(main())
api_id и api_hash. Скопируйте их в файл config.py.gpt4all через pip (pip install gpt4all) и скачать одну из моделей (например, gpt4all-lora-quantized.bin) с официального сайта GPT4All, поместив её в ту же папку, что и скрипт, или указав путь к ней в config.py.private_message_handler в файле main.py, используя нейросеть для генерации персонализированных ответов.FloodWait — это ошибка Telegram API, которая возникает, когда вы отправляете слишком много запросов за короткий промежуток времени. Скрипт уже включает обработку FloodWait: при получении такой ошибки бот автоматически делает паузу на указанное Telegram время. Чтобы минимизировать их появление, настройте DELAY_AFTER_POST и COMMENT_FREQUENCY в config.py на более длительные интервалы.Этот комплексный Python-скрипт предоставляет мощную основу для автоматизации вашего взаимодействия в Telegram-каналах. Используя Pyrogram и локальную нейросеть, он способен не только мониторить новые посты и ставить реакции, но и вести осмысленный диалог, генерируя релевантные комментарии и отвечая на отклики пользователей. Благодаря четкой структуре папки и подробным комментариям, скрипт легко развернуть и адаптировать даже для новичков, открывая двери к более интеллектуальной автоматизации в Telegram.