
POST /tg-webhook برای دریافت و پردازش بهروزرسانیهای ورودی Telegram.wrangler init، ساختار اولیه پروژه را ایجاد کنید.webhook و قابلیت پایه بازتاب پیام (echo) را پیادهسازی کنید.wrangler.toml را با مقادیر KV و secrets مورد نیاز تنظیم کنید.workers.dev منتشر کنید.Telegram API ثبت نمایید.
مسیرwebhook URLدر فراخوانیsetWebhookنادرست است.
API tokensگم شده یا نامعتبر هستند.
فراموش کردن استقرار مجدد (deploy) پس از اعمال تغییرات.
عدم بررسیlogsبرای یافتن خطاها.
ناتوانی در مدیریت صحیحTelegram's message format.چکلیست پیش از عملیات
Telegram tokenبا استفاده ازgetMeتایید شده است.
دامنهWorkersقابل دسترسی و دارایHTTPSاست.
الگویRouteباwebhook pathمطابقت دارد.
KV namespaceبه درستی پیکربندی شده است.
Secretsبه درستی تنظیم شدهاند.
re-deploy کرده و webhook را دوباره تنظیم کنید. Logs بهترین ابزار شما برای troubleshooting و یافتن راه حل هستند.You are a helpful assistant in a Telegram bot. Keep responses under 4000 characters.// OpenAI client with retries and streaming
async function callOpenAI(message, options = {}) {
const {
model = "gpt-5-pro",
temperature = 0.7,
max_tokens = 1000,
timeout_ms = 15000,
max_retries = 3
} = options;
let retries = 0;
while (retries <= max_retries) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout_ms);
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${OPENAI_API_KEY}`
},
body: JSON.stringify({
model,
messages: [
{ role: "system", content: "You are a helpful assistant in a Telegram bot. Keep responses concise." },
{ role: "user", content: message }
],
temperature,
max_tokens,
stream: true
}),
signal: controller.signal
});
clearTimeout(timeoutId);
// Handle streaming response and aggregate
let fullResponse = "";
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// Parse SSE format and extract content
const lines = chunk.split("\n");
for (const line of lines) {
if (line.startsWith("data: ") && line !== "data: [DONE]") {
try {
const data = JSON.parse(line.substring(6));
const content = data.choices[0]?.delta?.content || "";
fullResponse += content;
} catch (e) {
// Skip invalid JSON
}
}
}
}
return fullResponse;
} catch (error) {
retries++;
if (retries > max_retries) throw error;
// Exponential backoff
const delay = Math.pow(2, retries) * 100;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}ارسال به gpt-5-pro با پارامترهای model, temperature, max_tokens و system prompt ثابت:
"You are a helpful assistant in a Telegram bot. Keep responses concise."
استریمینگ: دریافت تدریجی، تجمیع صحیح؛ نادیدهگرفتن خطوط data: [DONE] و JSON نامعتبر.
قابلیت اطمینان: Retry با exponential backoff (شروع از 100ms) تا max_retries + ثبت در لاگ.
Timeout هر درخواست (مثلاً 15000ms) و لغو در صورت عبور از مهلت.
خروجی: برگرداندن متن نهایی بهصورت string.
هدف کارایی: ترجیحاً پاسخ < ۵ ثانیه.
امضای پیشنهادی تابع (نمونه):
async function chat({ input, model='gpt-5-pro', temperature=0.7, maxTokens=512, timeoutMs=15000, maxRetries=3 }): Promise<string>Welcome! I'm your AI assistant powered by GPT-5 Pro. Ask me anything or try /help for more information.Available commands:
/help - Show this message
/settings - View current settings
/settings_tone [formal|friendly|technical] - Change response styleCurrent settings:
Tone: Friendly
Model: GPT-5 Pro
Messages today: 15/50Tone changed to technical. Responses will now use precise terminology and provide detailed explanations.// User settings handler
async function handleSettings(chatId, command, param) {
// Get current settings or initialize defaults
let settings = await getUserSettings(chatId);
if (!settings) {
settings = {
tone: "friendly",
model: "gpt-5-pro",
messageCount: 0,
lastReset: Date.now()
};
}
// Handle different settings commands
if (command === "/settings") {
return `Current settings:
Tone: ${settings.tone}
Model: ${settings.model}
Messages today: ${settings.messageCount}/50`;
}
else if (command === "/settings_tone") {
const validTones = ["friendly", "formal", "technical"];
if (!param || !validTones.includes(param)) {
return `Please specify a valid tone: /settings_tone [${validTones.join('|')}]`;
}
settings.tone = param;
await storeUserSettings(chatId, settings);
return `Tone updated to ${param}. Future responses will reflect this style.`;
}
return "Unknown settings command. Try /help for available options.";
}
// KV helper functions
async function getUserSettings(chatId) {
return await USER_SETTINGS.get(`user:${chatId}`, "json");
}
async function storeUserSettings(chatId, settings) {
await USER_SETTINGS.put(`user:${chatId}`, JSON.stringify(settings));
}
API خود را بهینه و محافظت کنید:Chat ID.async function checkRateLimit(chatId) {
const settings = await getUserSettings(chatId);
// Reset counter if needed
const dayInMs = 24 * 60 * 60 * 1000;
if (Date.now() - settings.lastReset > dayInMs) {
settings.messageCount = 0;
settings.lastReset = Date.now();
}
// Check if over limit
if (settings.messageCount >= 50) {
return false;
}
// Increment counter
settings.messageCount++;
await storeUserSettings(chatId, settings);
return true;
}
// Main message handler with command routing
async function handleUpdate(update) {
try {
// Extract message details
const message = update.message;
if (!message || !message.text) {
return { ok: true, text: "متن پیام یافت نشد" };
}
const chatId = message.chat.id;
const text = message.text.trim();
// Check if it's a command
if (text.startsWith('/')) {
const [command, ...params] = text.split(' ');
const param = params.join(' ');
// Route to appropriate handler
switch (command) {
case '/start':
return {
method: 'sendMessage',
chat_id: chatId,
text: "به ربات هوش مصنوعی خود خوش آمدید! من با قدرت GPT-5 Pro هر پرسشی را پاسخ میدهم. برای آشنایی بیشتر، دستور /help را امتحان کنید."
};
case '/help':
return {
method: 'sendMessage',
chat_id: chatId,
text: `دستورات موجود:
/help - نمایش این راهنما
/settings - مشاهده تنظیمات فعلی
/settings_tone [formal|friendly|technical] - تغییر لحن پاسخگویی`
};
case '/settings':
case '/settings_tone':
const response = await handleSettings(chatId, command, param);
return {
method: 'sendMessage',
chat_id: chatId,
text: response
};
default:
return {
method: 'sendMessage',
chat_id: chatId,
text: "دستور وارد شده نامعتبر است. برای مشاهده گزینهها، از /help استفاده کنید."
};
}
}
// Check rate limit for AI responses
const withinLimit = await checkRateLimit(chatId);
if (!withinLimit) {
return {
method: 'sendMessage',
chat_id: chatId,
text: "شما به سقف مجاز پیامهای روزانه خود رسیدهاید. لطفاً فردا دوباره تلاش کنید."
};
}
// Handle as normal message to AI
const settings = await getUserSettings(chatId);
const aiResponse = await callOpenAI(text, {
temperature: settings.tone === 'technical' ? 0.3 : 0.7
});
return {
method: 'sendMessage',
chat_id: chatId,
text: aiResponse
};
} catch (error) {
console.error('Error handling update:', error);
return {
method: 'sendMessage',
chat_id: update.message?.chat.id,
text: "با عرض پوزش، مشکلی رخ داده است. لطفاً کمی بعد مجدداً امتحان کنید."
};
}
}
# راهنمای پیادهسازی ربات تلگرام: دستورات و تنظیمات
**هدف:** پیادهسازی کامل بخش مدیریت دستورات و تنظیمات کاربران برای یک ربات تلگرام مبتنی بر API. این شامل مدیریت ورودیهای کاربر، ذخیرهسازی ترجیحات، محدودیت نرخ و ادغام با مدل AI است.
---
**۱. ساختار اصلی کد:**
* `handleUpdate(update)`: تابع اصلی برای پردازش هر بهروزرسانی دریافتی از تلگرام.
* باید `chatId` و `text` پیام را استخراج کند.
* دستورات (که با `/` شروع میشوند) را از پیامهای عادی تشخیص دهد.
* ورودیهای خالی یا نامعتبر را مدیریت کند.
* همه پاسخها باید در قالب `{"method": "sendMessage", "chat_id": chatId, "text": "..."}` برگردانده شوند.
* مدیریت خطا (try-catch) برای جلوگیری از کرش شدن ربات در صورت بروز مشکل.
---
**۲. پیادهسازی دستورات (Commands):**
* `/start`:
* پاسخ خوشآمدگویی: "به ربات هوش مصنوعی خود خوش آمدید! من با قدرت GPT-5 Pro هر پرسشی را پاسخ میدهم. برای آشنایی بیشتر، دستور /help را امتحان کنید."
* `/help`:
* پاسخ راهنما: `دستورات موجود:\n/help - نمایش این راهنما\n/settings - مشاهده تنظیمات فعلی\n/settings_tone [formal|friendly|technical] - تغییر لحن پاسخگویی`
* `/settings`:
* باید تنظیمات فعلی کاربر (لحن (tone)، مدل (model)، تعداد پیامهای امروز/محدودیت) را از KV بازیابی کرده و نمایش دهد.
* قالب نمایش: `Current settings:\nTone: [tone]\nModel: [model]\nMessages today: [count]/50`
* `/settings_tone [param]`:
* پارامتر `param` باید یکی از "friendly", "formal", "technical" باشد. در غیر این صورت، پیام خطا نمایش داده شود: `Please specify a valid tone: /settings_tone [friendly|formal|technical]`
* اگر پارامتر معتبر بود، لحن کاربر را در KV بهروزرسانی کند.
* پاسخ تأیید: `Tone updated to [param]. Future responses will reflect this style.`
* دستورات نامعتبر:
* اگر دستوری شناخته نشد، پیام `دستور وارد شده نامعتبر است. برای مشاهده گزینهها، از /help استفاده کنید.` نمایش داده شود.
---
**۳. مدیریت تنظیمات کاربر (User Settings) با KV:**
* **فضای نام (Namespace):** `USER_SETTINGS` (فرض میشود از قبل تعریف شده است).
* **کلید (Key) در KV:** `user:{chatId}`.
* **ساختار دادهها در KV:** یک شی JSON شامل:
* `tone`: (پیشفرض: "friendly") - "friendly", "formal", "technical"
* `model`: (پیشفرض: "gpt-5-pro") - مدل AI مورد استفاده
* `messageCount`: (پیشفرض: 0) - تعداد پیامهای AI کاربر در روز جاری
* `lastReset`: (پیشفرض: `Date.now()`) - زمان آخرین بازنشانی شمارنده پیامها
* **توابع کمکی:**
* `async function getUserSettings(chatId)`: تنظیمات کاربر را از KV بازیابی میکند. اگر وجود نداشت، تنظیمات پیشفرض را برمیگرداند.
* `async function storeUserSettings(chatId, settings)`: تنظیمات بهروز شده کاربر را در KV ذخیره میکند.
---
**۴. پیادهسازی محدودیت نرخ (Rate Limiting):**
* **تابع:** `async function checkRateLimit(chatId)`
* **منطق:**
* تنظیمات کاربر را بازیابی کند.
* اگر `lastReset` مربوط به روز قبل بود، `messageCount` را به 0 و `lastReset` را به `Date.now()` بازنشانی کند (هر 24 ساعت).
* سقف پیامها: 50 پیام در روز.
* اگر `messageCount` کمتر از 50 بود، `messageCount` را یکی افزایش داده و تنظیمات را ذخیره کند، سپس `true` برگرداند.
* اگر `messageCount` به 50 یا بیشتر رسیده بود، `false` برگرداند و `messageCount` را افزایش ندهد.
* **ادغام با `handleUpdate`:**
* قبل از هر فراخوانی به `callOpenAI`، `checkRateLimit` را اجرا کند.
* اگر `checkRateLimit` مقدار `false` برگرداند، پیامی به کاربر نمایش دهد: "شما به سقف مجاز پیامهای روزانه خود رسیدهاید. لطفاً فردا دوباره تلاش کنید." و `callOpenAI` را فراخوانی نکند.
---
**۵. ادغام با AI (OpenAI):**
* **تابع:** `async function callOpenAI(prompt, options)` (فرض میشود از قبل تعریف شده است).
* **تنظیم لحن (Tone):**
* مقدار `temperature` برای `callOpenAI` باید بر اساس `settings.tone` تنظیم شود.
* اگر `tone` برابر با "technical" بود، `temperature` باید `0.3` باشد.
* برای سایر لحنها، `temperature` باید `0.7` باشد.
---
**۶. معیارهای تست و اعتبارسنجی:**
* تمام دستورات (`/start`, `/help`, `/settings`, `/settings_tone`) باید پاسخهای صحیح و مورد انتظار را ارائه دهند.
* تغییر لحن از طریق `/settings_tone` باید بهدرستی در KV ذخیره شود و پس از راهاندازی مجدد ربات نیز پایدار بماند.
* شمارنده پیامها برای محدودیت نرخ باید با هر پیام AI افزایش یابد و پس از رسیدن به 50، از ارسال پیامهای بیشتر جلوگیری کند.
* شمارنده پیامها باید به صورت خودکار هر 24 ساعت بازنشانی شود.
* تغییر لحن (`tone`) باید به وضوح بر سبک پاسخهای تولید شده توسط `callOpenAI` تأثیر بگذارد (مثلاً لحن "technical" پاسخهای فنیتری تولید کند).
* مدیریت خطا باید از کرش شدن ربات در مواجهه با ورودیهای غیرمنتظره یا خطاهای داخلی جلوگیری کند.
در نظر دارم قابلیتی برای خلاصهسازی به ربات تلگرام خود، که از OpenAI استفاده میکند، اضافه کنم.
دو ویژگی کلیدی باید به آن افزوده شود:
1. خلاصهسازی خودکار: هر پیامی که بیش از 800 characters طول دارد، به صورت خودکار خلاصه شود.
2. دستور /summarize: افزودن یک دستور /summarize که متن ورودی را دریافت کرده و خلاصهای از آن ارائه دهد.
خلاصه تولید شده باید:
- مختصر باشد (در قالب 3 تا 5 bullet points یا حداکثر 120 words).
- با تنظیمات لحن کاربر (ذخیره شده در settings.tone) مطابقت داشته باشد.
- ظرف 20 seconds تکمیل شود.
- در صورت عدم موفقیت در خلاصهسازی، با نمایش یک پیام جایگزین، به درستی خطا را مدیریت کند.
لطفاً یک minimal patch ارائه دهید که این ویژگیها را با رعایت ساختار کد موجود ما پیادهسازی کند. این patch باید حداقل شامل دو تست باشد: یکی برای خلاصهسازی خودکار و دیگری برای دستور /summarize.
در اینجا بخشهای کلیدی از پایگاه کد موجود ما آورده شده است:
- تابع `callOpenAI(message, options)` برای ارتباط با OpenAI وجود دارد.
- تنظیمات کاربر در `KV` ذخیره شده و از طریق `getUserSettings(chatId)` قابل دسترسی است.
- مسیریابی دستورات در تابع `handleUpdate()` انجام میشود که `update.message` را تجزیه و تحلیل میکند.
patch باید حداقل و متمرکز بر ویژگی خلاصهسازی باشد.
// افزودن توابع خلاصهسازی
async function summarizeText(text, tone = "friendly") {
const systemPrompt = `You are a summarization assistant. Summarize the following text in ${tone} tone.
Use 3-5 bullet points or keep it under 120 words. Focus on key points only.`;
try {
const summary = await callOpenAI(text, {
model: "gpt-5-pro",
temperature: tone === "technical" ? 0.3 : 0.5,
max_tokens: 250,
timeout_ms: 18000, // 18 seconds to allow for network overhead
system_prompt: systemPrompt
});
return summary;
} catch (error) {
console.error("Summarization failed:", error);
return "قادر به تولید خلاصه نبودم. ممکن است متن بیش از حد پیچیده باشد یا در پردازش آن خطایی رخ داده باشد."; // I couldn't generate a summary. The text might be too complex or there was a processing error.
}
}
// بررسی نیاز به خلاصهسازی خودکار متن
function needsSummarization(text) {
return text.length > 800;
}
// بهروزرسانی تابع handleUpdate برای مدیریت خلاصهسازی
async function handleUpdate(update) {
try {
// استخراج جزئیات پیام (کد موجود)
const message = update.message;
if (!message || !message.text) {
return { ok: true, text: "متنی در پیام یافت نشد." };
}
const chatId = message.chat.id;
const text = message.text.trim();
// بررسی اینکه آیا پیام یک دستور است
if (text.startsWith('/')) {
const [command, ...params] = text.split(' ');
const param = params.join(' ');
// مدیریت دستور summarize
if (command === '/summarize') {
if (!param) {
return {
method: 'sendMessage',
chat_id: chatId,
text: "لطفاً متنی برای خلاصهسازی ارائه دهید: /summarize [متن شما در اینجا]" // Please provide text to summarize: /summarize [your text here]
};
}
// بررسی محدودیت نرخ
const withinLimit = await checkRateLimit(chatId);
if (!withinLimit) {
return {
method: 'sendMessage',
chat_id: chatId,
text: "شما به سقف پیامهای روزانه خود رسیدهاید. لطفاً فردا دوباره امتحان کنید." // You've reached your daily message limit. Please try again tomorrow.
};
}
// دریافت ترجیحات لحن کاربر
const settings = await getUserSettings(chatId);
// تولید خلاصه
const summary = await summarizeText(param, settings.tone);
return {
method: 'sendMessage',
chat_id: chatId,
text: `خلاصه:\n${summary}` // Summary:
};
}
// مدیریت سایر دستورات (کد موجود)
// ...
}
// خلاصهسازی خودکار برای پیامهای طولانی
if (needsSummarization(text)) {
// بررسی محدودیت نرخ
const withinLimit = await checkRateLimit(chatId);
if (!withinLimit) {
return {
method: 'sendMessage',
chat_id: chatId,
text: "شما به سقف پیامهای روزانه خود رسیدهاید. لطفاً فردا دوباره امتحان کنید." // You've reached your daily message limit. Please try again tomorrow.
};
}
// دریافت تنظیمات کاربر
const settings = await getUserSettings(chatId);
// تولید خلاصه
const summary = await summarizeText(text, settings.tone);
// ابتدا پاسخ هوش مصنوعی را به پیام اصلی ارسال کنید
const aiResponse = await callOpenAI(text, {
temperature: settings.tone === 'technical' ? 0.3 : 0.7
});
// سپس خلاصه را به عنوان یک پیام پیگیری ارسال کنید
await sendTelegramMessage(chatId, aiResponse);
return {
method: 'sendMessage',
chat_id: chatId,
text: `خلاصه پیام شما:\n${summary}` // Summary of your message:
};
}
// مدیریت پیامهای عادی به هوش مصنوعی (کد موجود)
// ...
} catch (error) {
console.error('Error handling update:', error);
return {
method: 'sendMessage',
chat_id: update.message?.chat.id,
text: "متأسفم، مشکلی پیش آمد. لطفاً بعداً دوباره تلاش کنید." // Sorry, something went wrong. Please try again later.
};
}
}
// توابع تست
function testAutoSummarize() {
const longText = "Lorem ipsum ".repeat(100); // ایجاد متنی طولانیتر از 800 کاراکتر
console.log("تست خلاصهسازی خودکار"); // Testing auto-summarization
console.log(`طول ورودی: ${longText.length}`); // Input length:
console.log(`نیاز به خلاصهسازی: ${needsSummarization(longText)}`); // Needs summarization:
// شیء `update` ساختگی
const update = {
message: {
chat: { id: "test-chat-123" },
text: longText
}
};
// فراخوانی هندلر و بررسی نتایج
handleUpdate(update).then(result => {
console.log("نتیجه خلاصهسازی خودکار:", result); // Auto-summarize result:
console.assert(
result.text.includes("خلاصه پیام شما:"), // باید شامل پیشوند خلاصه باشد
"باید شامل پیشوند خلاصه باشد" // Should include summary prefix
);
});
}
function testSummarizeCommand() {
const textToSummarize = "This is a test message that should be summarized when using the command.";
console.log("تست دستور /summarize"); // Testing /summarize command
// شیء `update` ساختگی
const update = {
message: {
chat: { id: "test-chat-123" },
text: `/summarize ${textToSummarize}`
}
};
// فراخوانی هندلر و بررسی نتایج
handleUpdate(update).then(result => {
console.log("نتیجه خلاصهسازی دستور:", result); // Command summarize result:
console.assert(
result.text.includes("خلاصه:"), // باید شامل پیشوند خلاصه باشد
"باید شامل پیشوند خلاصه باشد" // Should include summary prefix
);
});
}
دستورالعملهای تست و اعتبارسنجی
برای اطمینان از صحت پیادهسازی قابلیت خلاصهسازی، مراحل تست زیر را دنبال کنید: تست خلاصهسازی خودکار: یک پیام با بیش از 800 کاراکتر ارسال کنید. اعتبارسنجی: بررسی کنید که آیا یک پیام خلاصهسازی جداگانه (با پیشوند "خلاصه پیام شما:") به صورت خودکار بازگردانده میشود و محتوای آن واقعاً خلاصهای از متن اصلی است. تست دستور /summarize: دستور /summarize را با یک متن طولانی (مثلاً 500 کاراکتر) ارسال کنید: /summarize [متن شما در اینجا]. اعتبارسنجی: بررسی کنید که آیا پاسخی با پیشوند "خلاصه:" دریافت میکنید و متن بازگردانده شده، خلاصهای مختصر و مفید از ورودی شماست. تست مورد خطا: دستور /summarize را بدون هیچ متنی ارسال کنید. اعتبارسنجی: بررسی کنید که پیام خطای "لطفاً متنی برای خلاصهسازی ارائه دهید..." دریافت شود. تست تطابق لحن: اگر رابط کاربری برای تنظیم لحن (tone) وجود دارد، لحن را به "technical" و سپس به "friendly" تغییر دهید. متنهای طولانی را برای خلاصهسازی ارسال کنید (چه از طریق خلاصهسازی خودکار و چه با دستور /summarize). اعتبارسنجی: لحن خلاصههای تولید شده را ارزیابی کنید تا مطمئن شوید با لحن انتخابی شما (فنی یا دوستانه) مطابقت دارد. تست عملکرد زمانی: یک پیام طولانی (بیش از 800 کاراکتر) یا یک دستور /summarize با متن پیچیده ارسال کنید. اعتبارسنجی: زمان پاسخدهی را اندازهگیری کنید. مطمئن شوید که خلاصه در عرض 20 ثانیه بازگردانده میشود. تست مدیریت خطا: تلاش کنید یک متن بسیار طولانی و/یا پیچیده که ممکن است باعث مشکل در پردازش شود را برای خلاصهسازی ارسال کنید (مثلاً متنی شامل کاراکترهای نامتعارف یا ساختار پیچیده). اعتبارسنجی: بررسی کنید که در صورت بروز خطا، پیام کاربرپسند "قادر به تولید خلاصه نبودم..." یا "متأسفم، مشکلی پیش آمد..." دریافت شود و برنامه از کار نیفتد. تستهای داخلی کد: تابعهای تست داخلی testAutoSummarize() و testSummarizeCommand() را اجرا کنید. اعتبارسنجی: خروجی کنسول را بررسی کنید و مطمئن شوید که هر دو تست با موفقیت ("باید شامل پیشوند خلاصه باشد") به پایان میرسند و هیچ خطایی گزارش نمیشود.
req.beginreq.endreq.errortg.webhook.receivedtg.command.executedtg.send.successtg.send.errorai.call.beginai.call.endai.call.errorai.call.retrykv.getkv.putkv.errorrate.limit.exceededrequestId را در هر رویداد برای همبستگی (correlation) در میان سرویسها لحاظ کنید.// Structured logger with request ID tracking
class Logger {
constructor(requestId = null) {
this.requestId = requestId || crypto.randomUUID();
this.startTime = Date.now();
}
log(event, data = {}) {
const timestamp = new Date().toISOString();
const duration = Date.now() - this.startTime;
const logEntry = JSON.stringify({
timestamp,
requestId: this.requestId,
event,
duration_ms: duration,
...data
});
console.log(logEntry);
}
error(event, error, data = {}) {
const errorData = {
error_message: error.message,
error_stack: error.stack,
...data
};
this.log(`${event}.error`, errorData);
}
}
// Usage in request handler
async function handleRequest(request) {
const logger = new Logger();
logger.log('req.begin', { url: request.url });
try {
const result = await processRequest(request, logger);
logger.log('req.end', { status: 'success' });
return result;
} catch (error) {
logger.error('req.error', error);
return new Response(
JSON.stringify({ ok: false, error: "Internal server error" }),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
);
}
}
// Example OpenAI call with logging
async function callOpenAIWithLogging(message, options = {}, logger) {
logger.log('ai.call.begin', {
model: options.model || "gpt-5-pro",
message_length: message.length
});
let retries = 0;
const maxRetries = options.max_retries || 3;
while (retries <= maxRetries) {
try {
const response = await callOpenAI(message, options);
logger.log('ai.call.end', {
success: true,
tokens: response.length / 4, // Approximate token count
retries
});
return response;
} catch (error) {
retries++;
logger.log('ai.call.retry', {
attempt: retries,
max_retries: maxRetries,
error: error.message
});
if (retries > maxRetries) {
logger.error('ai.call.error', error, {
final: true,
after_retries: retries - 1
});
throw error;
}
// Exponential backoff
const delay = Math.pow(2, retries) * 100;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Graceful error handling
try {
// Normal processing
} catch (error) {
// Log detailed error
logger.error('process.error', error);
// Always return 200 to Telegram
return new Response(
JSON.stringify({ ok: true }),
{ status: 200 }
);
// Send friendly message to user
await sendTelegramMessage(
chatId,
"Sorry, I couldn't process that request. " +
"Please try again in a moment."
);
}
curl https://your-worker.workers.dev/healthwrangler tail --format=jsonwrangler publish --env=prod// wrangler.toml configuration for multiple environments
name = "telegram-bot"
main = "src/index.js"
compatibility_date = "2023-12-01"
[env.dev]
kv_namespaces = [
{ binding = "USER_SETTINGS", id = "dev-kv-id" }
]
vars = { ENVIRONMENT = "dev", LOG_LEVEL = "debug" }
[env.prod]
kv_namespaces = [
{ binding = "USER_SETTINGS", id = "prod-kv-id" }
]
vars = { ENVIRONMENT = "prod", LOG_LEVEL = "info" }
route = { pattern = "bot.example.com/*", custom_domain = true }
git tag v1.0.0
git push origin v1.0.0wrangler publish --env=prodcurl https://bot.example.com/health
# Test /start command via Telegramcurl "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook?url=https://bot.example.com/tg-webhook"# Revert to previous tag
git checkout v0.9.0
# Deploy the previous version
wrangler publish --env=prod
# Deploy to alternate route
wrangler publish --env=blue
# Switch traffic via Cloudflare dashboard
# or with API/CLI commands to update routes