Closed adolfousier closed 5 months ago
New update to the code, now it have falloff measure to send plain text if fails to escape character:
const axios = require('axios');
require('dotenv').config(); // Load environment variables from a .env file
const TelegramBot = require('node-telegram-bot-api');
// Telegram bot token (replace it with your own token)
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
// API URL
const API_URL = process.env.API_URL;
// Function to make the query
async function query(data) {
try {
const response = await axios.post(API_URL, data, {
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
'Content-Type': 'application/json',
},
});
return response.data;
} catch (error) {
console.error('Error in the query:', error.message);
throw error;
}
}
function escapeSpecialCharacters(text) {
return text
.replace(/([_*[\]()~`>#+=|{}.!-])/g, '\\$1')
.replace(/```/g, '\\`\\`\\`')
.replace(/\./g, '\\.')
.replace(/@/g, '\\@');
}
function preserveCodeBlocks(text) {
const codeBlocks = [];
const preservedText = text.replace(/```[\s\S]*?```/g, (match) => {
codeBlocks.push(match);
return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
});
return { preservedText, codeBlocks };
}
function restoreCodeBlocks(text, codeBlocks) {
return text.replace(/__CODE_BLOCK_(\d+)__/g, (_, index) => {
const block = codeBlocks[parseInt(index)];
return '```\n' + escapeSpecialCharacters(block.slice(3, -3)) + '\n```';
});
}
function formatText(text) {
const { preservedText, codeBlocks } = preserveCodeBlocks(text);
let formattedText = preservedText
.replace(/\*\*(.*?)\*\*/g, '*$1*') // Bold
.replace(/\*(.*?)\*/g, '_$1_') // Italic
.replace(/`(.*?)`/g, '`$1`'); // Inline code
formattedText = escapeSpecialCharacters(formattedText);
// Unescape formatting characters
formattedText = formattedText
.replace(/\\_/g, '_')
.replace(/\\\*/g, '*')
.replace(/\\`/g, '`');
// Handle email addresses and usernames
formattedText = formattedText
.replace(/(\\@[\w-]+)/g, (match) => match.replace('\\@', '@'))
.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g, (match) =>
match.replace(/\\\./g, '.'));
// Ensure all periods are escaped, including those at the end of sentences
formattedText = formattedText.replace(/\./g, '\\.');
return restoreCodeBlocks(formattedText, codeBlocks);
}
// Function to handle Telegram messages
async function handleTelegramMessage(message) {
const chatId = message.chat.id;
const text = message.text;
try {
console.log(`Incoming message: ${text}`);
const result = await query({ question: text });
const responseText = result.text || 'Could not retrieve response text';
console.log('Raw response:', responseText);
const finalText = formatText(responseText);
console.log(`Processed response: ${finalText}`);
try {
const telegramResponse = await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
chat_id: chatId,
text: finalText,
parse_mode: 'MarkdownV2',
});
console.log('Telegram API response:', telegramResponse.data);
console.log(`Sent response to Telegram chat ${chatId}`);
} catch (markdownError) {
console.error('Error sending MarkdownV2 message:', markdownError.response.data);
// Fallback to sending without formatting
const plainText = responseText.replace(/[_*[\]()~`>#+=|{}.!-]/g, '');
await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
chat_id: chatId,
text: plainText,
});
console.log(`Sent plain text response to Telegram chat ${chatId}`);
}
} catch (error) {
console.error('Error handling Telegram message:', error);
if (error.response) {
console.error('Error details:', error.response.data);
console.error('Request data:', error.response.config.data);
}
// Send a fallback message without formatting
try {
await axios.post(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, {
chat_id: chatId,
text: 'Sorry, there was an error processing your message. Please try again.',
});
} catch (fallbackError) {
console.error('Error sending fallback message:', fallbackError);
}
}
}
// Configure the Telegram bot
const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, { polling: true });
// Handle Telegram messages
bot.on('message', handleTelegramMessage);
// Port to listen on (uses the port defined by the PORT environment variable or defaults to port 3000)
const port = process.env.PORT || 3000;
// Startup message
console.log(`Telegram bot started. Listening on port ${port}...`);
Bro, thank you for updating and getting better the code.
Thank you bro! It was a good starting point but now we have a client that need proper formatting on Telegram and markdownv2 was the best option for me but still have some bugs, I'm fixing another escaped character which I will update soon and push if you want I will keep contributing to your code, thank you!
Fixed MarkdownV2 text formatting and code formatting to ensure proper rendering on Telegram. This update resolves formatting issues for most cases on Telegram with MarkdownV2. Highly recommended.