adityajat/SaarvamAI_botPublic · Bot Template
AISarvam AI is a multi‑purpose Telegram bot that lets users ask questions, get explanations, convert text to speech, and translate messages using the Sarvam AI API. It also offers group administration commands such as warn, mute, ban, pin, delete, and announcements, and can clear personal or group AI memory. The bot uses the TeleBotHost TBL framework with Bot, Api, db, and HTTP calls, and provides inline keyboards for language and voice selection.
Ai Assistantaivoicetranslatemoderationadminsarvam
34 commands4 envUpdated 15d agoCreated Sep 14, 2026
commands/_handle_message.js
javascript · 680 lines
1/**#command2name: /handle_message3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12// ==========================================13// /handle_message14// MAIN MESSAGE + MEDIA HANDLER15// ==========================================16 17try {18 19 if (!update || !update.message) {20 return;21 }22 23 let m = update.message;24 25 if (!m.chat) {26 return;27 }28 29 let chatId = String(m.chat.id);30 31 let isGroup =32 m.chat.type === "group" ||33 m.chat.type === "supergroup";34 35 let username =36 bot && bot.username37 ? bot.username38 : "";39 40 // ==========================================41 // GROUP MENTION CHECK42 // ==========================================43 44 let text =45 typeof m.text === "string"46 ? m.text.trim()47 : "";48 49 let caption =50 typeof m.caption === "string"51 ? m.caption.trim()52 : "";53 54 let mentioned = false;55 56 if (username) {57 58 let mention =59 "@" + username;60 61 if (62 text &&63 text.toLowerCase().indexOf(64 mention.toLowerCase()65 ) !== -166 ) {67 mentioned = true;68 69 let escaped =70 username.replace(71 /[.*+?^${}()|[\]\\]/g,72 "\\$&"73 );74 75 text =76 text77 .replace(78 new RegExp(79 "@" + escaped,80 "ig"81 ),82 ""83 )84 .trim();85 }86 87 if (88 caption &&89 caption.toLowerCase().indexOf(90 mention.toLowerCase()91 ) !== -192 ) {93 mentioned = true;94 95 let escapedCaption =96 username.replace(97 /[.*+?^${}()|[\]\\]/g,98 "\\$&"99 );100 101 caption =102 caption103 .replace(104 new RegExp(105 "@" + escapedCaption,106 "ig"107 ),108 ""109 )110 .trim();111 }112 }113 114 // ==========================================115 // REPLY-TO-BOT CHECK116 // ==========================================117 118 let repliedToBot = false;119 120 if (121 m.reply_to_message &&122 m.reply_to_message.from &&123 username &&124 m.reply_to_message.from.username125 ) {126 127 repliedToBot =128 m.reply_to_message.from.username129 .toLowerCase() ===130 username.toLowerCase();131 }132 133 // ==========================================134 // GROUP NORMAL MESSAGE FILTER135 // ==========================================136 137 if (isGroup) {138 139 // In groups, only respond when:140 // 1. Bot is mentioned141 // 2. User replies to bot142 // 3. User sends media with bot mention143 if (144 !mentioned &&145 !repliedToBot146 ) {147 return;148 }149 }150 151 // ==========================================152 // CONVERSATION HISTORY153 // ==========================================154 155 let historyKey =156 "sarvam_history_" + chatId;157 158 let history =159 await db.user.get(160 historyKey,161 []162 );163 164 if (!Array.isArray(history)) {165 history = [];166 }167 168 if (history.length > 20) {169 history =170 history.slice(-20);171 }172 173 // ==========================================174 // SYSTEM PROMPT175 // ==========================================176 177 178let systemPrompt = `179You are Sarvam, a natural, helpful conversational AI assistant.180 181CONVERSATION:182- Understand the latest user message first.183- Use previous messages when they are relevant to the latest message.184- Understand follow-up questions, pronouns, and references using nearby relevant context.185- Do not bring unrelated older topics into a new conversation.186- If the user says "Hello", greet them naturally and briefly.187- Do not repeatedly introduce yourself.188- Answer the actual question directly.189- Keep simple responses short unless more detail is requested.190 191LANGUAGE AND GRAMMAR:192- Reply in the same language as the latest user message.193- If the user writes in English, reply in natural English.194- If the user writes in Hindi, reply in natural Hindi.195- If the user writes in Hinglish, natural Hinglish is allowed.196- Do not randomly switch languages.197- Do not invent words or create meaningless phrases.198- Do not mix Punjabi, Urdu, or other languages unless requested.199- Use correct, understandable grammar.200- Casual and harsh slang is allowed when appropriate, but clarity is essential.201 202TONE:203- Be friendly and conversational without forcing jokes.204- Do not add unrelated teasing, sarcasm, or exaggerated reactions.205- Match the user's tone naturally without copying errors or nonsensical language.206 207ACCURACY:208- Never knowingly give an incorrect answer.209- For calculations, calculate carefully rather than guessing.210- If uncertain, state the uncertainty instead of inventing facts.211 212MEDIA:213- Use only the media information actually supplied to you.214- Never claim to have inspected image, audio, video, or document contents that are not available.215 216OWNER:217The owner of this bot is @shecallsmecalm.218If asked who your owner is, answer:219"@shecallsmecalm is my owner, the owner of every creation."220`;221 222 223 // ==========================================224 // MEDIA CONTEXT225 // ==========================================226 227 let mediaContext = "";228 229 // ------------------------------------------230 // STICKER231 // ------------------------------------------232 233 if (m.sticker) {234 235 let emoji =236 m.sticker.emoji || "";237 238 mediaContext =239 "[USER SENT A STICKER]\n" +240 "Sticker emoji: " +241 (242 emoji || "unknown"243 ) +244 "\n";245 246 if (emoji) {247 mediaContext +=248 "Analyse and Interpret the sticker's likely emotional meaning and conversation context.\n";249 }250 251 // Reply with the Different sticker.252 // This makes sticker conversations feel natural.253 try {254 255 await Api.sendSticker({256 sticker:257 m.sticker.file_id258 });259 260 } catch (stickerError) {261 // Do not break AI response if sticker sending fails.262 }263 }264 265 // ------------------------------------------266 // PHOTO267 // ------------------------------------------268 269 else if (m.photo) {270 271 mediaContext =272 "[USER SENT A PHOTO]\n" +273 "The user sent a photo.";274 275 if (caption) {276 mediaContext +=277 "\nCaption/question: " +278 caption;279 }280 281 mediaContext +=282 "\nActual visual analysis is performed by sarvam-105b itself.";283 }284 285 // ------------------------------------------286 // DOCUMENT287 // ------------------------------------------288 289 else if (m.document) {290 291 mediaContext =292 "[USER SENT A DOCUMENT]\n" +293 "File name: " +294 (295 m.document.file_name ||296 "unknown"297 ) +298 "\nMIME type: " +299 (300 m.document.mime_type ||301 "unknown"302 );303 304 if (caption) {305 mediaContext +=306 "\nCaption/question: " +307 caption;308 }309 }310 311 // ------------------------------------------312 // VOICE313 // ------------------------------------------314 315 else if (m.voice) {316 317 mediaContext =318 "[USER SENT A VOICE MESSAGE]\n" +319 "Duration: " +320 (321 m.voice.duration || 0322 ) +323 " seconds.";324 325 if (caption) {326 mediaContext +=327 "\nCaption: " +328 caption;329 }330 }331 332 // ------------------------------------------333 // AUDIO334 // ------------------------------------------335 336 else if (m.audio) {337 338 mediaContext =339 "[USER SENT AUDIO]\n" +340 "Title: " +341 (342 m.audio.title ||343 "unknown"344 ) +345 "\nPerformer: " +346 (347 m.audio.performer ||348 "unknown"349 );350 }351 352 // ------------------------------------------353 // VIDEO354 // ------------------------------------------355 356 else if (m.video) {357 358 mediaContext =359 "[USER SENT VIDEO]\n" +360 "Duration: " +361 (362 m.video.duration || 0363 ) +364 " seconds.";365 366 if (caption) {367 mediaContext +=368 "\nCaption/question: " +369 caption;370 }371 }372 373 // ------------------------------------------374 // GIF / ANIMATION375 // ------------------------------------------376 377 else if (m.animation) {378 379 mediaContext =380 "[USER SENT AN ANIMATION / GIF]\n" +381 "The user sent a GIF/animation.";382 383 if (caption) {384 mediaContext +=385 "\nCaption/question: " +386 caption;387 }388 }389 390 // ------------------------------------------391 // OTHER MEDIA392 // ------------------------------------------393 394 else if (395 m.video_note396 ) {397 398 mediaContext =399 "[USER SENT A VIDEO NOTE]\n" +400 "The user sent a circular video message.";401 }402 403 // ==========================================404 // NORMAL TEXT405 // ==========================================406 407 let hasText =408 !!text;409 410 // For media without text,411 // still give AI the media context.412 413 if (414 !hasText &&415 !mediaContext416 ) {417 return;418 }419 420 // ==========================================421 // USER MESSAGE TO AI422 // ==========================================423 424 let userContent = "";425 426 if (text) {427 userContent += text;428 }429 430 if (caption) {431 432 if (userContent) {433 userContent +=434 "\n\n";435 }436 437 userContent +=438 "Caption: " +439 caption;440 }441 442 if (mediaContext) {443 444 if (userContent) {445 userContent +=446 "\n\n";447 }448 449 userContent +=450 mediaContext;451 }452 453 if (!userContent.trim()) {454 userContent =455 mediaContext;456 }457 458 // ==========================================459 // SAVE USER MESSAGE460 // ==========================================461 462 history.push({463 role: "user",464 content: userContent465 });466 467 if (history.length > 20) {468 history =469 history.slice(-20);470 }471 472 // ==========================================473 // BUILD AI REQUEST474 // ==========================================475 476 let messages = [477 {478 role: "system",479 content: systemPrompt480 }481 ];482 483 for (484 let i = 0;485 i < history.length;486 i++487 ) {488 messages.push(489 history[i]490 );491 }492 493 // ==========================================494 // SARVAM API495 // ==========================================496 497 let apiKey =498 process.env.SARVAM_API_KEY;499 500 if (!apiKey) {501 502 return Bot.sendMessage(503 "⚠️ SARVAM_API_KEY is not configured."504 );505 }506 507 let res =508 await HTTP.post(509 "https://api.sarvam.ai/v1/chat/completions",510 {511 headers: {512 "api-subscription-key":513 apiKey514 },515 516 body: {517 model:518 "sarvam-105b",519 520 messages:521 messages,522 523 max_tokens:524 70000525 },526 527 responseType:528 "json",529 530 timeout:531 30000532 }533 );534 535 // ==========================================536 // API FAILURE537 // ==========================================538 539 if (540 !res ||541 !res.ok542 ) {543 544 let status =545 res && res.status546 ? String(res.status)547 : "unknown";548 549 return Bot.sendMessage(550 "⚠️ Sarvam API error (" +551 status +552 "). Please try again."553 );554 }555 556 // ==========================================557 // READ RESPONSE558 // ==========================================559 560 let answer = "";561 562 if (563 res.data &&564 res.data.choices &&565 res.data.choices.length &&566 res.data.choices[0].message567 ) {568 569 answer =570 res.data571 .choices[0]572 .message573 .content || "";574 }575 576 if (577 !answer ||578 !String(answer).trim()579 ) {580 581 return Bot.sendMessage(582 "⚠️ I couldn't generate a response."583 );584 }585 586 answer =587 String(answer)588 .trim();589 590 // ==========================================591 // SAVE AI RESPONSE592 // ==========================================593 594 history.push({595 role: "assistant",596 content: answer597 });598 599 if (history.length > 20) {600 history =601 history.slice(-20);602 }603 604 await db.user.set(605 historyKey,606 history607 );608 609 // ==========================================610 // CLEAN MARKDOWN611 // ==========================================612 613 answer =614 answer615 .replace(/\*\*/g, "")616 .replace(/__/g, "")617 .replace(/`/g, "")618 .trim();619 620 // ==========================================621 // SEND TEXT RESPONSE622 // ==========================================623 624 return Bot.sendMessage(625 answer626 );627 628} catch (e) {629 630 return Bot.sendMessage(631 "⚠️ Message handler error: " +632 (633 e &&634 e.message635 ? e.message636 : String(e)637 )638 );639 }640 641 642const payment = update &&643 update.message &&644 update.message.successful_payment;645 646if (!payment) return;647 648if (649 payment.invoice_payload !== "sarvam_voice_credits_10_v1" ||650 payment.currency !== "XTR" ||651 payment.total_amount !== 50652) {653 return;654}655 656const chargeId = payment.telegram_payment_charge_id;657const key = "voice_paid_" + chargeId;658 659const alreadyProcessed = await db.user.get(key, false);660 661if (alreadyProcessed) return;662 663const saved = await db.user.set(key, true);664 665if (!saved || saved.ok === false) {666 Bot.sendMessage(667 "Payment received, but credit processing needs attention. Contact the bot owner with your payment receipt."668 );669 return;670}671 672await db.user.incr("voice_credits", 10);673 674const balance = await db.user.get("voice_credits", 0);675 676Bot.sendMessage(677 "✅ Payment successful!\n\n" +678 "Added: 10 voice credits\n" +679 "Your balance: " + balance680);