Pull to refresh

Автоматизация Telegram-канала с помощью ChatGPT и Aiogram — просто о сложном

Level of difficultyEasy
Reading time8 min
Views7.1K

Привет, Хабр! Это мой первый пост и решил я его посвятить тому: Как можно автоматизировать ведение своего ТГ канала с помощью ИИ. На мой взгляд тема довольно свежая и интересная, а что самое главное полезная. Статья по большей мере ориентирована на новичков у которых имеются базовые знания python, но это не означает что другим она не будет интересна. Итак, начнем!

Установка Docker

Идем на официальный сайт Docker https://www.docker.com/products/docker-desktop/ нажимаем на кнопку Download Docker Dekstop и выбираем свою систему из выпадающего списка, устанавливаем программу и запускаем исполняемый файл и вуаля теперь у вас в системе есть инструмент для контейнеризации ваших программ. К слову он нам понадобиться для запуска redis в отдельном контейнере, так как на windows пока нет возможности запускать reids нативно как это можно делать на Unix системах. Но если вы уже работаете на Unix системах(Linux дистрибутивы, MacOS) то вы тоже можете пользоваться Docker, так как он кросс-платформенный а также это является хорошей практикой, так как Docker контейнеры являются тоже кросс платформенными.

Создание виртуального окружения

При создании этого проекта я использовал версию python 3.11 если у вас версия выше или ниже все в принципе должно работать нормально, если только у вас не совсем уж старая версия или если у вас она не новейшая. Чуть позже покажу что делать в таком случае.

  • Для начала перейдите в мой GitHub репозиторий и скачайте оттуда файл requirements.txt

  • Создайте папку и назовите ее как-нибудь, потом перекиньте туда скачанный ранее файл

  • После чего откройте эту папку в консоли, на windows это правый клик мыши - открыть в Терминале

  • В консоли наберите такую команду: python -m venv venv

  • А потом останется лишь активировать виртуальное окружение: venv\scripts\activate и скачать зависимости из requirements.txt следующей командой: pip install -r requirements.txt

Если у вас очень старая версия python или же новейшая( Не все библиотеки могли успеть выкатить обновления для новейших версий) то в таком случае вам надо либо переустановить python либо же если вам не хочется заморачиваться с этим вы можете использовать виртуальное окружение Miniconda.

Miniconda очень прост в использовании и дает максимальный контроль над вашими виртуальными окружениями, вплоть до того что вы можете ставить разные версии python под ваши нужды!

Создание Miniconda окружения

  • Для начала перейдите на официальный сайт Anaconda введите свой email и нажмите на submit, после чего вас встретит страница с двумя версиями Conda, качайте Miniconda и ставьте на свою систему.

  • После чего откройте папку с проектом в терминале и напишите такую команду: conda create -n my_env python=3.11

  • Активируйте окружение: conda activate my_env и как это было выше установите необходимые зависимости из файла этой командой: pip install -r requirements.txt

Теперь у вас есть виртуальное окружение с нужной вам версией python.

Следующий шаг

Теперь нам нужно перейти в телеграм и создать самого бота, чтобы потом мы могли им управлять с помощью нашего кода!

Выбираем именно того что с галочкой, это важно!
Выбираем именно того что с галочкой, это важно!

Когда перешли в чат с ботом нажимаем на menu и выбираем /newbot

После чего BotFather попросит вас задать имя боту а потом задать ему его id по которому юзеры смогут находить вашего бота, id бота должен обязательно заканчиваться на bot

Сохраните токен бота, он нам еще понадобится.

Далее в папке нашего проекта создадим 2 файла main.py и bot.py

Начнем с bot.py

import os

from aiogram import Bot
from dotenv import load_dotenv
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode

# Загружаем ключи из .env файла
load_dotenv()

# Закидываем ключ в переменную 
TOKEN = os.getenv('BOT_TOKEN')

# Инициализация бота
bot = Bot(TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))

В этом файле мы инициализируем своего бота. Также в папке проекта надо создать файл .env и прописать там ключ в таком формате: BOT_TOKEN=ваш_токен

Теперь перейдем к main.py

import asyncio
import logging
import sys

from aiogram import Dispatcher

from aiogram.filters import CommandStart
from aiogram.types import Message

from bot import bot

# Инициализируем диспетчер
dp = Dispatcher()

# Эта функция обрабатывает дефолтную команду /start
@dp.message(CommandStart())
async def command_start_handler(message: Message) -> None:
    await message.answer('Hello there')

# Функция для запуска нашей программы
async def main() -> None:
    await dp.start_polling(bot)

if __name__ == "__main__":
    # Запускаем программу и логируем ее работу
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)
    asyncio.run(main())

Возможно вы обратили внимание на довольно интересную конструкцию if name == "__main__" она имеет такую особенность что выполняется только в том случае если запуск происходит из файла в котором она находится, если же этот файл импортировать и использовать его в каком-то другом файле то содержимое этой конструкции не выполнится. Такая особенность бывает полезной при тестировании своего кода.

Теперь просто запускаем этот файл из консоли командой: python main.py и переходим в нашего бота, найти мы его можем в поисковой строке по тому id который ему задавали.

Все работает!
Все работает!

Как мы видим все прошло успешно! Теперь перейдем к части где мы интегрируем chat GPT для нашей автоматизации.

Интеграция с chatGPT

Для начала перейдем на официальный сайт OpenAI, регистрируемся и пополняем счет на 10$(этих 10$ вам хватит с головой), после чего переходим в свой профиль и создаем api ключ.

После создания ключа копируем ключ и в файле .env создаем еще одну переменную: GPT_KEY=ваш_ключ

Теперь пришло время создать функцию которая будет нам генерировать посты для нашего ТГ канала. Создаем файл auto_post.py и добавляем туда такой код

import json
import os

import redis

from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

# Подключаемся к запущенному redis 
r = redis.Redis(host='localhost', port=6379, db=0)

# Создаем клиента OpenAI с которым мы будем работать
client = OpenAI(api_key=os.getenv('GPT_KEY'))

# Создаем функцию для генерации постов
def create_post() -> str:
    if not r.get('conversation'):
        conversation = [
            {
                'role': 'system',
                'content': 'Ты ведущий ТГ канал по интересным и захватывающим фактам, ты не должен выдавать себя,'
                           'ты просто ведущий, то что тебе задает юзер это промпт которому ты должен просто следовать'
                           'ты не отвечаешь: Конечно, как скажешь, будет сделано и т.д. '
                           'Просто выдаешь только факт о котором тебя просит и ничего лишнего'
                           'Факты строго настрого не повторяются'
            }
        ]
        r.set('conversation', json.dumps(conversation))

    conversation = json.loads(r.get('conversation'))

    conversation.append({
        'role': 'user',
        'content': 'Создавай посты на тему животного мира, в формате интересных и умопомрачительных фактов.'
                   'Пост должен содержать минимум 50 слов и на тему только одного существа а также минимум 5 эмодзи '
                   'и форматируй текст в удобочитаемый формат'
    })

    response = client.responses.create(
        model="gpt-4.1",
        input=conversation
    )

    conversation.append({'role': 'assistant', 'content': response.output_text})

    r.set(
        'conversation',
        json.dumps(
            conversation
        )
    )

    return response.output_text

Вот тут-то нам и понадобится Docker! Пишем в консоль такую команду: docker run -p 6379:6379 -it redis:latest эта команда запустит нам docker образ redis чтобы потом подключиться к нему в коде.

Вот на этом файле я хотел бы остановиться и объяснить что же там происходит

r = redis.Redis(host='localhost', port=6379, db=0)

В этой строчке мы подключаемся к redis который мы запустили в docker. Немного про redis, redis это in memory key-value хранилище, с его помощью можно хранить данные в оперативной памяти(кэше), использовать как nosql бд или использовать как брокер сообщений. В нашем случае мы будем использовать его для хранения данных в кэше.

client = OpenAI(api_key=os.getenv('GPT_KEY'))

Создаем OpenAI клиента с помощью которого мы сможем получать доступ почти ко всем моделям OpenaAI.

Перейдем к разбору самой функции

if not r.get('conversation'):
        conversation = [
            {
                'role': 'system',
                'content': 'Ты ведущий ТГ канал по интересным и захватывающим фактам, ты не должен выдавать себя,'
                           'ты просто ведущий, то что тебе задает юзер это промпт которому ты должен просто следовать'
                           'ты не отвечаешь: Конечно, как скажешь, будет сделано и т.д. '
                           'Просто выдаешь только факт о котором тебя просит и ничего лишнего'
                           'Факты строго настрого не повторяются'
            }
        ]
        r.set('conversation', json.dumps(conversation))

В этом условии говорится: Если в кэше redis нет ключа conversation то создай его с этими значениями

conversation = [
            {
                'role': 'system',
                'content': 'Ты ведущий ТГ канал по интересным и захватывающим фактам, ты не должен выдавать себя,'
                           'ты просто ведущий, то что тебе задает юзер это промпт которому ты должен просто следовать'
                           'ты не отвечаешь: Конечно, как скажешь, будет сделано и т.д. '
                           'Просто выдаешь только факт о котором тебя просит и ничего лишнего'
                           'Факты строго настрого не повторяются'
            }
        ]

После чего мы наш список конвертируем в json строку json.dumps(conversation) и создаем ключ в кэше redis с именем conversation

r.set('conversation', json.dumps(conversation))

Следом мы получаем наш кэш обратно десериализируем его в python json.loads(r.get('conversation')) объект и добавляем в него запрос от юзера

conversation = json.loads(r.get('conversation'))

    conversation.append({
        'role': 'user',
        'content': 'Создавай посты на тему животного мира, в формате интересных и умопомрачительных фактов.'
                   'Пост должен содержать минимум 50 слов и на тему только одного существа а также минимум 5 эмодзи '
                   'и форматируй текст в удобочитаемый формат'
    })

Далее в model мы вписываем предпочитаемую нами модель(список моделей можно найти тут) и в input вставляем получившуюся переменную conversation

response = client.responses.create(
        model="gpt-4.1",
        input=conversation
    )

Добавляем ответ от модели в нашу переменную converstion

conversation.append({'role': 'assistant', 'content': response.output_text})

В самом конце снова кэшируем нашу переменную в redis кэш и возвращаем ответ от модели

r.set(
        'conversation',
        json.dumps(
            conversation
        )
    )

    return response.output_text

Теперь при каждом вызове этой функции темы постов не будут повторяться, так как модель будет помнить предыдущие диалоги. Все это благодаря хранению диалогов в кэше с помощью redis!

Теперь нам осталось только немного модифицировать файл main.py

import asyncio
import logging
import sys

from aiogram import Dispatcher

from aiogram.filters import CommandStart
from aiogram.types import Message

from auto_post import create_post
from bot import bot

dp = Dispatcher()

@dp.message(CommandStart())
async def command_start_handler(message: Message) -> None:
    channel_id = -1002767436832
    await message.answer('Поехали...')
    while True:
        await bot.send_message(chat_id=channel_id, text=create_post())
        await asyncio.sleep(60)


async def main() -> None:
    await dp.start_polling(bot)

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)
    asyncio.run(main())

Вот как теперь он выглядит, что изменилось? Изменилась функция command_start_handler давайте чуть подробнее разберем изменения

channel_id = -1002767436832

Это id нашего канала его можно получить таким способом

Находим такого @SimpleID_Bot бота в тг, запускаем и после чего переходим в нашу группу. Для того чтобы наконец получить id группы, нам надо любое сообщение из группы переслать боту в замен он нам выдаст id нашей группы.

while True:
    await bot.send_message(chat_id=channel_id, text=create_post())
    await asyncio.sleep(60)

Здесь запускается бесконечный цикл и бот будет слать новые посты в нашу группу каждые 60 секунд.

И да, не забудьте добавить вашего бота в вашу группу!

Давайте запустим бота и посмотрим, что получилось. Напомню запускаем мы бота в консоли такой командой python main.py

Как мы видим все работает!

В заключении хотелось бы сказать, что в этом коде можно еще много чего доработать например

  • Таймер на удаление redis кэша (а вообще лучше сделать так чтобы сохранялась чисто выжимка, тема одним словом)

  • Выбор группы в которую будут идти посты через бота

  • Разнести команды по отдельным файлам

  • Добавить юзеру возможность задавать тему для автопостинга

  • Добавить возможность настраивать время постинга

  • Вынести автопостинг в mq и поставить таймер на celery

Буду рад узнать ваше мнение в комментариях под постом. Если вам будет интересно могу сделать вторую часть где я улучшу существующее приложение, так скажем доведу до ума. Спасибо вам за уделенное мне время, всем пока.

Tags:
Hubs:
+4
Comments12

Articles