协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
telegram-bot-builder【开发与工程】Builds Telegram bots using the Bot API (grammy/telegraf/python-telegram-bot). Use when the user wants to create a Telegram bot, handle commands, build inline keyboards, process callbacks, send media, build conversational flows, handle payments (Telegram Stars), or create Mini Apps. Trigger words: telegram bot, telegram integration, telegram commands,…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Builds production-ready Telegram bots covering the full Bot API surface: commands, inline keyboards, callback queries, conversations with state machines, media handling, group management, payments, and Mini Apps. Supports both long polling (development) and webhooks (production).
/newbot, choose name and username123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)/setcommands, /setdescription, /setabouttextRecommended frameworks by language:
Node.js — grammY (recommended):
npm init -y && npm install grammy @grammyjs/conversations
Node 20.6+ loads env files natively: node --env-file=.env bot.js (no dotenv needed).
Node.js — Telegraf (4.16.3 is its latest release; it lags behind newer Bot API features, so prefer grammY for new bots):
npm install telegraf
Python — python-telegram-bot:
pip install python-telegram-bot # v22, async API, Python 3.10+
# bot.py
import os
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Welcome!")
app = Application.builder().token(os.environ["BOT_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.run_polling()
Standard project structure:
telegram-bot/
├── bot.js # Entry point, bot initialization
├── handlers/
│ ├── commands.js # /start, /help, custom commands
│ ├── callbacks.js # Inline keyboard callback handlers
│ ├── conversations.js # Multi-step conversation flows
│ └── middleware.js # Auth, logging, rate limiting
├── keyboards/ # Inline and reply keyboard builders
├── services/ # Business logic
├── .env # BOT_TOKEN, WEBHOOK_URL, WEBHOOK_SECRET, ADMIN_ID (gitignored)
└── package.json
Bot setup (ESM, "type": "module" in package.json):
import { Bot, InlineKeyboard, InputFile, session, webhookCallback } from 'grammy';
import { conversations, createConversation } from '@grammyjs/conversations';
const bot = new Bot(process.env.BOT_TOKEN);
bot.catch((err) => console.error('Update failed:', err.error));
Basic command handler:
bot.command('start', async (ctx) => {
await ctx.reply('Welcome!', {
reply_markup: {
inline_keyboard: [[
{ text: '📊 Dashboard', callback_data: 'dashboard' },
{ text: '⚙️ Settings', callback_data: 'settings' }
]]
}
});
});
Callback query handler:
bot.callbackQuery('dashboard', async (ctx) => {
await ctx.answerCallbackQuery();
await ctx.editMessageText('Here is your dashboard...', {
reply_markup: backButton
});
});
Conversation (conversations plugin v2; no session needed):
async function onboarding(conversation, ctx) {
await ctx.reply('What is your name?');
const name = await conversation.waitFor('message:text');
await ctx.reply('What is your email?');
const email = await conversation.waitFor('message:text');
await ctx.reply(`Thanks ${name.message.text}! Registered with ${email.message.text}`);
}
bot.use(conversations());
bot.use(createConversation(onboarding, 'onboarding')); // function first, name second
bot.command('register', (ctx) => ctx.conversation.enter('onboarding'));
Register conversations() after any session() middleware and before the conversation. Code in a conversation is replayed, so wrap side effects (database writes, API calls) in conversation.external(...).
Middleware for auth:
function adminOnly(ctx, next) {
if (ctx.from?.id !== Number(process.env.ADMIN_ID)) {
return ctx.reply('⛔ Not authorized');
}
return next();
}
bot.command('admin', adminOnly, handleAdmin); // grammY: bot.command(name, ...middleware)
Inline Keyboard (attached to message):
callback_data) — triggers callbackQuery handlerurl) — opens a linkweb_app) — opens a Mini Appswitch_inline_query) — triggers inline modeReply Keyboard (replaces phone keyboard):
one_time_keyboard: true to auto-hide after selectionresize_keyboard: true for compact displayRemove Keyboard:
{ reply_markup: { remove_keyboard: true } }
Long Polling (development):
bot.start(); // Calls getUpdates in a loop
Webhooks (production):
import express from 'express';
const app = express();
app.use(express.json());
// A secret header proves the request comes from Telegram; keep the token out of the URL
app.post('/telegram/webhook', webhookCallback(bot, 'express', { secretToken: process.env.WEBHOOK_SECRET }));
app.listen(3000);
await bot.api.setWebhook('https://bots.northwind.dev/telegram/webhook', {
secret_token: process.env.WEBHOOK_SECRET,
});
getUpdates are mutually exclusive: call bot.api.deleteWebhook() before going back to polling// Send photo
await ctx.replyWithPhoto(new InputFile('./image.png'), { caption: 'Check this out' });
// Send document
await ctx.replyWithDocument(new InputFile(buffer, 'report.pdf'));
// Handle received photos
bot.on('message:photo', async (ctx) => {
const file = await ctx.getFile();
const url = `https://api.telegram.org/file/bot${process.env.BOT_TOKEN}/${file.file_path}`;
});
Current Bot API is 10.x (10.3, August 2026); check the changelog at core.telegram.org/bots/api-changelog for new features.
retry_after; honor it (grammY: @grammyjs/auto-retry)Input: "Build a Telegram bot for my team to manage tasks. Users should be able to create tasks, assign them, set deadlines, and get reminders."
Output: A grammY bot with:
/newtask command opening a conversation flow (title → description → assignee → deadline)/mytasks showing personal task list with inline navigationInput: "Create a Telegram bot that lets me draft posts, preview them, schedule them to a channel, and track engagement."
Output: A grammY bot with:
bot.api.sendMessage(channelId, ...)/drafts command listing scheduled posts with edit/delete optionsbot.catch(...) — unhandled errors in handlers stop the botctx.answerCallbackQuery() to dismiss the loading indicator on buttons/revoke in @BotFatherXTR); answer pre_checkout_query within 10 secondsparse_mode: 'HTML' or 'MarkdownV2' for rich text (MarkdownV2 requires escaping special chars)bot.stop() on SIGINT/SIGTERMmy_chat_member updates to track when bot is added/removedbot.api.setMyCommands() for autocompleteawait ctx.replyWithChatAction('typing') (or the auto-chat-action plugin) for long operations