В этой статье
Соберём своего Telegram-бота, который принимает сообщение и отправляет его в ChatGPT. В примере не будет фреймворка для Telegram, базы данных и вебхука: Node.js сам будет опрашивать Telegram через getUpdates, а ответ OpenAI вернётся через Responses API.
Что понадобится
Проверьте версии перед началом. Для примера подойдёт Node.js 24 LTS и официальный пакет openai версии 7.20.0. В актуальном снимке SDK требует Node.js не ниже 22, но версии пакетов меняются, поэтому перед установкой стоит свериться с релизами Node.js и описанием пакета.
Нужны два токена:
- токен Telegram-бота, который выдаёт
@BotFather; - ключ OpenAI API из кабинета OpenAI.
Это разные ключи. Токен Telegram разрешает обращаться к Bot API от имени вашего бота, а ключ OpenAI — к модели через API. Не вставляйте их в исходный код и не отправляйте в репозиторий.
Создайте бота и проверьте токен Telegram
Откройте Telegram, найдите @BotFather и отправьте команду /newbot. Он попросит имя, затем username, который должен заканчиваться на bot. В ответ BotFather выдаст строку вроде 123456:AA... — это токен. Порядок создания бота также описан в официальном руководстве Telegram.
Сначала проверим его отдельным запросом. В Windows PowerShell можно выполнить:
$env:TELEGRAM_BOT_TOKEN="123456:AA..."
Invoke-RestMethod "https://api.telegram.org/bot$env:TELEGRAM_BOT_TOKEN/getMe"
В Linux или macOS команда выглядит так:
export TELEGRAM_BOT_TOKEN='123456:AA...'
curl "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/getMe"
Успешный ответ содержит ok: true и данные бота. Метод getMe предназначен как раз для проверки токена; список методов Telegram Bot API находится в официальной документации.
После проверки откройте своего бота по username и нажмите Start. Без первого сообщения бот не получит нужный нам чат в очереди обновлений.
Подготовьте проект Node.js
Создайте пустую папку и установите официальный SDK:
mkdir telegram-chatgpt-bot
cd telegram-chatgpt-bot
npm init -y
npm install openai@7.20.0
Создайте файл .env рядом с package.json:
TELEGRAM_BOT_TOKEN=123456:AA...
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-5-mini
В Node.js 24 файл можно загрузить встроенным флагом --env-file=.env, поэтому отдельный пакет для чтения переменных окружения не нужен. Добавьте секреты в .gitignore:
.env
node_modules/
Название модели в примере вынесено в переменную: доступность и стоимость моделей зависят от аккаунта и текущих условий OpenAI. Если в вашем аккаунте используется другая доступная модель, замените значение OPENAI_MODEL.
Свяжите Telegram с Responses API
Создайте файл bot.mjs:
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-mini";
if (!telegramToken || !openaiKey) {
throw new Error("Нужны TELEGRAM_BOT_TOKEN и OPENAI_API_KEY в .env");
}
const openai = new OpenAI({ apiKey: openaiKey });
const telegramApi = `https://api.telegram.org/bot${telegramToken}`;
async function telegram(method, body) {
const response = await fetch(`${telegramApi}/${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}: ${JSON.stringify(data)}`);
}
return data.result;
}
function splitTelegramText(text, maxLength = 4096) {
const chunks = [];
for (let start = 0; start < text.length; start += maxLength) {
chunks.push(text.slice(start, start + maxLength));
}
return chunks;
}
async function sendText(chatId, text) {
for (const chunk of splitTelegramText(text || "Модель не вернула текстовый ответ.")) {
await telegram("sendMessage", {
chat_id: chatId,
text: chunk,
});
}
}
async function answerWithChatGPT(text) {
const response = await openai.responses.create({
model,
instructions:
"Отвечай по-русски, кратко и понятно. Если вопрос неясен, задай один уточняющий вопрос.",
input: text,
});
return response.output_text.trim();
}
let offset = 0;
console.log("Бот запущен. Откройте его в Telegram и отправьте сообщение.");
while (true) {
try {
const updates = await telegram("getUpdates", {
offset,
timeout: 30,
allowed_updates: ["message"],
});
for (const update of updates) {
offset = update.update_id + 1;
const message = update.message;
const text = message?.text;
const chatId = message?.chat?.id;
if (!text || chatId === undefined) continue;
await sendText(chatId, "Думаю...");
const answer = await answerWithChatGPT(text);
await sendText(chatId, answer);
}
} catch (error) {
console.error(error);
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
Здесь есть четыре заметных места. getUpdates получает новые сообщения и ждёт до 30 секунд, поэтому программа не делает частые пустые запросы. chat.id становится значением chat_id для отправки ответа. Функция splitTelegramText делит длинный ответ на части размером не более 4096 символов — такой предел действует для текста sendMessage. Наконец, вызов openai.responses.create() обращается к Responses API, а готовый текст берётся из response.output_text — именно так это показано в официальном примере JavaScript SDK и документации Responses API.
Запустите и проверьте результат
Запустите файл с загрузкой .env:
node --env-file=.env bot.mjs
В консоли появится сообщение Бот запущен. Теперь отправьте боту, например, Объясни одним предложением, что такое REST API. Сначала Telegram покажет Думаю..., затем появится ответ модели.
Если ответа нет, смотрите на место, где остановилась проверка:
- ошибка
401или сообщение о неверном токене указывает наTELEGRAM_BOT_TOKENилиOPENAI_API_KEY; - ошибка Telegram с
chat_idозначает, что сообщение не содержит обычного чата — минимальный пример намеренно пропускает такие обновления; - ошибка OpenAI требует проверить имя модели, доступ API и лимиты аккаунта;
- если
getUpdatesне получает сообщения, проверьте, не настроен ли для бота вебхук: в минимальном примере используется long polling; - если бот повторяет старые сообщения, убедитесь, что одновременно не запущен второй процесс с тем же токеном.
Самый простой тест — остановить процесс Ctrl+C, снова запустить его и отправить новую фразу. Переменная offset хранится только в памяти, поэтому после перезапуска Telegram может отдать накопившиеся обновления; код последовательно сдвигает offset после каждого обработанного сообщения.
Если нужен доступ к ChatGPT для ручной проверки
Собранный бот использует OpenAI API, а подписка ChatGPT — другая услуга: она не пополняет баланс API и не подключается автоматически к вашему Telegram-боту. Если вы хотите отдельно вручную проверять промпты в ChatGPT, можно посмотреть доступные предложения сервисов ИИ в каталоге Amber Market. На карточке проверьте актуальные условия и итоговую сумму; по подтверждённым условиям доступна оплата через СБП, автоматических списаний нет.
Что добавить после минимального примера
Long polling удобен для первого запуска, но для постоянного сервиса обычно переходят к вебхуку и добавляют перезапуск процесса. Следующими слоями будут хранение контекста диалога, ограничение длины входных сообщений, обработка ошибок и модерация. Групповой режим и база данных здесь намеренно не нужны: сначала проверьте одну связку — Telegram-сообщение, вызов Responses API и sendMessage с результатом.
Если Node.js вам не подходит, соседний вариант той же задачи разобран в примере Telegram-бота ChatGPT на Python. Для Node.js-сценария важны именно официальный пакет openai, встроенный fetch и Responses API, а не дополнительный Telegram-фреймворк.
Источники
- OpenAI TypeScript and JavaScript API LibraryOpenAI
- Responses APIOpenAI
- openai package.jsonOpenAI
- Node.js ReleasesNode.js
- Telegram Bot APITelegram
- Telegram Bot API: getUpdatesTelegram
- From BotFather to Hello WorldTelegram