В этой статье
Telegram-бот с ChatGPT — это не специальная функция Telegram и не подключение подписки ChatGPT. Вы создаёте собственного бота, принимаете его сообщения через Telegram Bot API, передаёте текст на свой сервер, а сервер делает запрос в OpenAI Responses API. Затем ответ возвращается в тот же чат.
Схема короткая:
пользователь → Telegram → getUpdates → Node.js → OpenAI Responses API
↓
пользователь ← Telegram ← sendMessage ← ответ модели
Ниже — минимальный пример без базы данных, webhook, голосовых сообщений и отдельного Telegram-фреймворка. Он подходит, чтобы проверить маршрут на локальном компьютере или небольшом сервере. Для API понадобится собственный ключ OpenAI; постоянная бесплатность, фиксированная цена и конкретная доступность модели не гарантируются — перед запуском проверьте актуальные условия в документации OpenAI.
Что понадобится
Нужны Node.js 20 или новее, аккаунт Telegram, созданный через @BotFather, и ключ OpenAI API. Node.js 20 удобно взять как ориентир: в нём есть встроенный fetch, а официальный JavaScript SDK OpenAI устанавливается обычным npm-пакетом.
Создайте каталог проекта и установите зависимости:
mkdir telegram-chatgpt-bot
cd telegram-chatgpt-bot
npm init -y
npm install openai dotenv
В package.json добавьте режим ES-модулей:
{
"type": "module",
"scripts": {
"start": "node bot.mjs"
}
}
Если в файле уже есть другие поля, не заменяйте весь package.json: достаточно добавить "type": "module" и скрипт start.
Создайте Telegram-бота и сохраните токены
Откройте в Telegram @BotFather, выполните /newbot, задайте отображаемое имя и username, который заканчивается на bot. В ответ BotFather выдаст токен вида 123456:ABC.... Это пароль к вашему боту: не вставляйте его в Git, скриншоты, клиентский JavaScript или сообщения в чате.
Ключ OpenAI создайте в панели API. Он также должен оставаться на сервере. В проекте создайте файл .env:
TELEGRAM_BOT_TOKEN=сюда_токен_от_BotFather
OPENAI_API_KEY=сюда_ключ_OpenAI
OPENAI_MODEL=gpt-5
Добавьте .env в .gitignore:
.env
node_modules/
Если ключ уже попал в репозиторий или переписку, считайте его скомпрометированным: отзовите его и выпустите новый. Маскировка строки в интерфейсе не заменяет отзыв ключа.
Минимальный бот на Node.js
Создайте bot.mjs:
import "dotenv/config";
import OpenAI from "openai";
const telegramToken = process.env.TELEGRAM_BOT_TOKEN;
const openaiKey = process.env.OPENAI_API_KEY;
const model = process.env.OPENAI_MODEL || "gpt-5";
if (!telegramToken || !openaiKey) {
throw new Error(
"Set TELEGRAM_BOT_TOKEN and OPENAI_API_KEY in the environment"
);
}
const telegramBaseUrl = `https://api.telegram.org/bot${telegramToken}`;
const openai = new OpenAI({ apiKey: openaiKey });
async function telegram(method, body = {}) {
const response = await fetch(`${telegramBaseUrl}/${method}`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
const data = await response.json();
if (!response.ok || !data.ok) {
throw new Error(`Telegram ${method}: ${data.description || response.status}`);
}
return data.result;
}
function splitMessage(text, maxLength = 4096) {
const chunks = [];
for (let start = 0; start < text.length; start += maxLength) {
chunks.push(text.slice(start, start + maxLength));
}
return chunks.length ? chunks : ["Модель не вернула текстовый ответ."];
}
async function answerMessage(message) {
if (!message?.chat?.id || typeof message.text !== "string") {
return;
}
const response = await openai.responses.create({
model,
input: message.text,
});
const answer = response.output_text?.trim() ||
"Модель не вернула текстовый ответ.";
for (const chunk of splitMessage(answer)) {
await telegram("sendMessage", {
chat_id: message.chat.id,
text: chunk,
});
}
}
async function main() {
const bot = await telegram("getMe");
console.log(`Started @${bot.username}`);
let offset = 0;
while (true) {
try {
const updates = await telegram("getUpdates", {
offset,
timeout: 30,
allowed_updates: ["message"],
});
for (const update of updates) {
offset = update.update_id + 1;
try {
await answerMessage(update.message);
} catch (error) {
console.error("Message handling failed:", error);
if (update.message?.chat?.id) {
await telegram("sendMessage", {
chat_id: update.message.chat.id,
text: "Не удалось получить ответ. Проверьте журнал процесса и настройки API.",
});
}
}
}
} catch (error) {
console.error("Polling failed:", error);
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Здесь нет скрытого состояния диалога: каждый текст пользователя становится отдельным входом в Responses API. Поэтому бот отвечает на вопросы, но не помнит предыдущие сообщения. Историю можно добавить позже через previous_response_id, Conversations API или собственное хранилище — это уже другая граница ответственности.
Вызов responses.create и свойство output_text соответствуют примеру официального OpenAI JavaScript SDK. Модель вынесена в переменную окружения: это позволяет заменить её без редактирования исходного кода после проверки доступных моделей и условий аккаунта.
Запустите polling и проверьте ответ
Запустите процесс из каталога проекта:
npm start
Сначала код вызывает getMe. При успехе в консоли появится username бота. Затем процесс ждёт обновления через getUpdates с long polling: Telegram может держать запрос до 30 секунд, а не возвращать пустой ответ каждую миллисекунду. Подробнее о методах и формате обновлений — в Telegram Bot API.
Откройте личный чат с ботом, нажмите Start и отправьте обезличенное сообщение, например Объясни разницу между REST и RPC в трёх предложениях. В ответ бот должен вернуть текст модели. Не отправляйте в первую проверку пароли, персональные данные или рабочие секреты: сообщение проходит через Telegram и OpenAI.
offset увеличивается после каждого полученного обновления. Это подтверждает обработанное событие и не даёт одному и тому же сообщению бесконечно попадать в цикл при следующем запросе. message.text проверяется до вызова OpenAI, поэтому стикеры, фото и служебные события не превращаются в пустой API-запрос. Длинный ответ режется на части: у sendMessage есть ограничение длины текста Telegram.
Если кроме собственного API-ключа вам понадобится отдельно оплачиваемый цифровой сервис, после этой технической проверки можно посмотреть каталог Amber Market с подписками и цифровыми товарами. Актуальные условия заказа нужно проверить перед покупкой; оплатить заказ можно через СБП. Каталог не заменяет регистрацию OpenAI API, ключ и оплату запросов к нему.
Если polling не получает сообщения
getUpdates и webhook — взаимоисключающие способы доставки обновлений. Если для бота ранее настраивался webhook, long polling не заработает. Проверьте состояние тем же токеном, который загружает ваш процесс:
curl "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getWebhookInfo"
Если поле url непустое, удалите webhook и перезапустите процесс:
curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/deleteWebhook"
В PowerShell переменная задаётся иначе — $env:TELEGRAM_BOT_TOKEN. Команды выше рассчитаны на оболочку, где переменная уже экспортирована; файл .env сам по себе не экспортирует её в curl. Для диагностики проще выполнить встроенный getMe через тот же Node.js-процесс или использовать корректный синтаксис вашей оболочки. Сам токен не вставляйте в публичную команду и не сохраняйте в истории общего сервера.
Типичная ошибка Telegram 401 Unauthorized означает неверный или отозванный токен. Выпустите новый токен в BotFather и обновите .env.
Если Telegram отвечает, но OpenAI возвращает ошибку
Ошибки 401 со стороны OpenAI обычно указывают на неверный, отозванный или неправильно загруженный OPENAI_API_KEY. Перезапустите процесс после изменения .env: значения окружения читаются при старте.
429, rate limit и insufficient_quota — разные варианты проблемы с лимитом или доступной квотой. Повторять запрос без задержки бессмысленно: можно усилить ограничение. Сначала проверьте модель, квоту, настройки проекта и актуальные лимиты в панели OpenAI. Для разбора таких случаев пригодится инструкция про ошибки 429, rate limit и insufficient_quota.
Если нужен отдельный разбор первого запроса к OpenAI, полезно свериться с инструкцией по первому API-запросу, а хранение ключа — с инструкцией по получению и безопасному использованию ключа OpenAI API.
Что добавить после минимальной проверки
Этот пример намеренно не решает задачи production-сервиса. Следующий слой обычно включает ограничение частоты запросов на пользователя, журналирование без токенов и содержания секретных сообщений, обработку остановки процесса, повтор с backoff для временных сетевых ошибок, хранение истории, команды /start и /help, а затем webhook за HTTPS.
В группах понадобится отдельно учитывать privacy mode и права бота. Для голоса, изображений и файлов меняется как вход Telegram, так и формат запроса к модели. Платежи, база данных и масштабирование не являются частью маршрута «получить текст и вернуть текст», поэтому их не стоит незаметно добавлять в минимальный пример.
После успешного локального теста перенесите проект на сервер, задайте секреты в окружении процесса и оставьте наружу только нужный сетевой доступ. Бот, созданный через BotFather по этой схеме, остаётся вашей интеграцией Telegram Bot API и OpenAI API — он не становится официальным Telegram-ботом OpenAI или ChatGPT.
Источники
- Developer quickstart — OpenAI APIOpenAI Platform
- Telegram Bot APITelegram
- Bots: An introduction for developersTelegram
- Models — OpenAI APIOpenAI Platform