Как сделать Telegram-бота с ChatGPT на Python: OpenAI API

В этой статье

Свой Telegram-бот с ответами ChatGPT связывает два API: Telegram передаёт программе сообщение, программа отправляет его в OpenAI, а затем возвращает ответ в тот же чат. Для первого рабочего варианта достаточно Python, long polling и двух переменных окружения.

Ниже используется Python 3.11 или новее, python-telegram-bot 21.x и официальный пакет openai 1.x. Пример отвечает только на текстовые сообщения: в нём нет истории диалогов, изображений, платежей и webhook.

Что понадобится до запуска

Создайте бота через @BotFather. Команда /newbot запустит диалог: BotFather попросит имя, затем username, оканчивающийся на bot, и выдаст токен. Токен управляет ботом, поэтому не добавляйте его в исходный код или файл, который попадёт в GitHub.

Отдельно подготовьте ключ OpenAI API и включённый биллинг API. Подписка ChatGPT и OpenAI API — разные продукты: подписка не подставляет ключ в программу и не пополняет баланс API.

Если нужен не API-бот для разработки, а готовый пользовательский доступ к ChatGPT, это отдельный маршрут. В каталоге Amber Market есть карточка ChatGPT с планами Go, Plus и Pro на 1 месяц. Перед заказом проверьте в карточке условия, наличие и итоговую сумму: покупка подписки не активирует и не пополняет OpenAI API.

Создаём окружение Python

Откройте терминал в новой папке проекта и создайте виртуальное окружение:

python -m venv .venv

Активируйте его. В Windows:

.\.venv\Scripts\Activate.ps1

В macOS и Linux:

source .venv/bin/activate

Установите библиотеки:

python -m pip install "python-telegram-bot>=21,<22" "openai>=1.68,<2"

Для локального запуска задайте секреты в окружении. В PowerShell:

$env:TELEGRAM_BOT_TOKEN = "токен-от-BotFather"
$env:OPENAI_API_KEY = "ключ-OpenAI-API"

В macOS и Linux:

export TELEGRAM_BOT_TOKEN="токен-от-BotFather"
export OPENAI_API_KEY="ключ-OpenAI-API"

Эти значения исчезнут после закрытия терминала. Для постоянного запуска настройте переменные средствами операционной системы или менеджера секретов, а не добавляйте их в исходный код.

Минимальный код Telegram-бота

Создайте файл bot.py:

import logging
import os

from openai import AsyncOpenAI
from telegram import Update
from telegram.constants import ChatAction
from telegram.ext import Application, ContextTypes, MessageHandler, filters


logging.basicConfig(
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    level=logging.INFO,
)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)


def required_env(name: str) -> str:
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Не задана переменная окружения {name}")
    return value


TELEGRAM_BOT_TOKEN = required_env("TELEGRAM_BOT_TOKEN")
openai_client = AsyncOpenAI(api_key=required_env("OPENAI_API_KEY"))


def split_for_telegram(text: str, limit: int = 2000) -> list[str]:
    """Разбивает ответ на части, допустимые для sendMessage."""
    return [text[start:start + limit] for start in range(0, len(text), limit)]


async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    message = update.effective_message
    if message is None or not message.text:
        return

    question = message.text.strip()
    if not question:
        await message.reply_text("Пришлите текстовый вопрос.")
        return

    await message.chat.send_action(ChatAction.TYPING)

    try:
        response = await openai_client.responses.create(
            model="gpt-4.1-mini",
            input=question,
        )
        answer = response.output_text.strip()
        if not answer:
            answer = "Модель не вернула текстовый ответ. Попробуйте ещё раз."
    except Exception as error:
        logger.error("Ошибка OpenAI API: %s", type(error).__name__)
        await message.reply_text(
            "Не удалось получить ответ. Проверьте ключ и доступ к API, затем повторите запрос."
        )
        return

    for part in split_for_telegram(answer):
        await message.reply_text(part)


def main() -> None:
    application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_text))
    application.run_polling(allowed_updates=["message"])


if __name__ == "__main__":
    main()

Клиент OpenAI создаётся из OPENAI_API_KEY, а вызов openai_client.responses.create отправляет вопрос в Responses API. Такой способ настройки ключа и вызова показан в официальном quickstart OpenAI. Обработчик сначала проверяет update.effective_message, затем message.text: фотография, стикер или другая нетекстовая публикация не попадёт в запрос к модели. Каждый вопрос самодостаточен, потому что собственная история диалога в этот пример не добавлена.

gpt-4.1-mini здесь служит примером компактной текстовой модели. Если в вашем API-проекте доступна другая модель, замените значение model, не меняя связку Telegram с Responses API.

Как работает long polling

После запуска python bot.py библиотека получает обновления Telegram через getUpdates: периодически спрашивает сервер, появился ли новый update. Когда пользователь пишет боту, обработчик вызывает OpenAI, а reply_text отправляет ответ методом sendMessage.

Библиотека ведёт служебный offset, чтобы уже обработанные обновления не приходили снова. Telegram требует продвигать offset после обработки update. Для одного бота нельзя одновременно использовать настроенный webhook и long polling; если webhook был установлен, удалите его перед переходом на polling. Подробности методов getUpdates и sendMessage есть в официальном Telegram Bot API.

На первом этапе домен и HTTPS-сервер не нужны: процесс сам устанавливает исходящие соединения с Telegram и OpenAI. Поэтому long polling удобно проверить на локальном компьютере.

Проверяем запуск по экрану

Оставьте терминал открытым и выполните:

python bot.py

В Telegram найдите username, который создали через BotFather, нажмите Start и отправьте короткий текст, например Назови три способа проверить HTTP-ответ в Python.

Если всё настроено, бот покажет статус набора текста, а затем пришлёт ответ. В терминале появятся служебные записи библиотеки. Обычные текстовые сообщения принимаются без добавления вопроса в список разрешённых команд; команды Telegram этот обработчик пропускает.

Почему ответ разбивается на части

У sendMessage поле text ограничено 4096 символами после разбора entities. Поэтому split_for_telegram делит ответ на части по 2000 символов с запасом для символов вне BMP, а цикл отправляет их последовательно. Простое разбиение может разрезать слово или абзац, но для первого запуска оно не даёт Telegram отклонить слишком длинный ответ. В рабочей версии можно сначала искать ближайший перенос строки, затем пробел и только потом применять жёсткий лимит.

Если бот молчит или возвращает ошибку

Посмотрите, на каком участке остановилась цепочка:

  • Не задана переменная окружения ... означает, что текущий терминал не видит секрет. Задайте переменные ещё раз в том же окне и запустите программу повторно.
  • Ошибка Telegram при запуске обычно указывает на неверный токен BotFather. Сверьте его без лишних кавычек и пробелов.
  • Ошибка OpenAI после отправки сообщения может быть связана с ключом, доступом проекта, биллингом или названием модели. Тип ошибки останется в логе разработчика, а пользователь увидит короткое безопасное сообщение.
  • Повторяющиеся update означают, что запущены два процесса с одним токеном или остался webhook. Оставьте один процесс и один способ получения обновлений.
  • Если бот не отвечает на изображение или команду, это ожидаемо: пример намеренно принимает только текст.

Не выводите значения TELEGRAM_BOT_TOKEN и OPENAI_API_KEY в лог. Если секрет случайно попал в публичный файл, замените его в соответствующем сервисе и обновите переменную окружения.

Для Responses API по умолчанию действует хранение application state в течение 30 дней, если для организации не установлены другие настройки. Поэтому отсутствие собственной истории в этом коде не означает полного отсутствия хранения на стороне API; условия обработки данных нужно сверять с официальным описанием хранения данных OpenAI API.

Этот бот закрывает минимальный путь от текстового сообщения до ответа ChatGPT. История диалога, webhook и хранение пользователей — отдельные этапы, требующие новых решений о состоянии и приватности. Если после Python-примера нужен другой стек, сравните его с реализацией на Node.js; для близкого Python-сценария есть также дополнительный материал о Telegram-боте.

Источники

Есть следующая задача?Ещё по теме «Telegram-боты» →