UNPKG

@myea/aem-mcp-handler

Version:

Advanced AEM MCP request handler with intelligent search, multi-locale support, and comprehensive content management capabilities

241 lines (235 loc) • 9.33 kB
import express from 'express'; import axios from 'axios'; import dotenv from 'dotenv'; import { handleChatMessage } from './llm-integration.js'; dotenv.config(); const router = express.Router(); // Telegram Bot configuration const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; const TELEGRAM_API_URL = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}`; // Authorized Telegram user IDs (for security) const AUTHORIZED_USERS = process.env.TELEGRAM_AUTHORIZED_USERS?.split(',').map(id => parseInt(id.trim())) || []; // Store conversation history for each chat const chatHistory = new Map(); // Helper to send Telegram message with typing indicator async function sendTelegramMessage(chatId, text, parseMode = 'Markdown') { if (!TELEGRAM_BOT_TOKEN) { console.log('[Telegram] Bot token not configured, would send:', text); return; } try { // First, send typing action await axios.post(`${TELEGRAM_API_URL}/sendChatAction`, { chat_id: chatId, action: 'typing' }); const response = await axios.post(`${TELEGRAM_API_URL}/sendMessage`, { chat_id: chatId, text: text, parse_mode: parseMode, disable_web_page_preview: true }); console.log('[Telegram] Message sent successfully:', response.status); } catch (error) { console.error('[Telegram] Failed to send message:', error.response?.data || error.message); // Fallback: send without markdown if parsing failed if (error.response?.data?.error_code === 400 && parseMode === 'Markdown') { try { await axios.post(`${TELEGRAM_API_URL}/sendMessage`, { chat_id: chatId, text: text, disable_web_page_preview: true }); console.log('[Telegram] Message sent successfully (fallback)'); } catch (fallbackError) { console.error('[Telegram] Fallback send also failed:', fallbackError.message); throw fallbackError; } } else { throw error; } } } // Main message handling in the /telegram POST endpoint router.post('/telegram', async (req, res) => { let chatId = null; try { const update = req.body; if (!update.message) { res.sendStatus(200); return; } const message = update.message; chatId = message.chat.id; const userId = message.from.id; const userName = message.from.username || message.from.first_name; const text = message.text || ''; console.log(`[Telegram] Message from ${userName} (${userId}): ${text}`); // Security check if (AUTHORIZED_USERS.length > 0 && !AUTHORIZED_USERS.includes(userId)) { console.log(`[Telegram] Unauthorized user: ${userId}`); await sendTelegramMessage(chatId, '🚫 Unauthorized access. Contact admin for access.'); res.sendStatus(200); return; } // Get chat history let history = chatHistory.get(chatId) || []; // Handle commands if (text.startsWith('/')) { const [command] = text.slice(1).split(/\s+/); switch (command.toLowerCase()) { case 'help': case 'start': await sendTelegramMessage(chatId, `šŸ¤– *Welcome to AEM ChatGPT!* I can help you explore and modify your Adobe Experience Manager content. Try asking me things like: **šŸ” Search & Explore:** • "Find signin page under language-masters en" • "List pages under /content/wknd" • "What components are in the home page?" **šŸ“ Content Management:** • "Change text from 'Sign In' to 'Hello World' in signin XF" • "Update image path to /content/dam/new-image.jpg" • "Get all text content from about page" **šŸ› ļø Advanced Features:** • Universal site discovery (works with any AEM instance) • Deep component scanning in Experience Fragments • Bulk content updates across multiple pages • AI-powered search with fuzzy matching **Commands:** /help - Show this help /clear - Clear our conversation /status - Check system status`); return; case 'clear': chatHistory.delete(chatId); await sendTelegramMessage(chatId, "✨ Conversation history cleared!"); return; case 'status': // Use a simple health check instead of duplicating MCP logic try { const healthResponse = await axios.get('http://localhost:3000/api/health'); const health = healthResponse.data; await sendTelegramMessage(chatId, `šŸ¤– *System Status:*\n\n` + `*Telegram:* āœ… Connected\n` + `*MCP Server:* ${health.mcp === 'connected' ? 'āœ… Connected' : 'āŒ Disconnected'}\n` + `*OpenAI:* ${health.openai ? 'āœ… Connected' : 'āŒ Not Configured'}\n` + `*Chat History:* ${history.length} messages\n` + `*Time:* ${new Date().toLocaleString()}`); } catch (error) { await sendTelegramMessage(chatId, `šŸ¤– *System Status:*\n\n` + `*Telegram:* āœ… Connected\n` + `*System:* āŒ Error checking status\n` + `*Time:* ${new Date().toLocaleString()}`); } return; default: break; } } // Show typing indicator await axios.post(`${TELEGRAM_API_URL}/sendChatAction`, { chat_id: chatId, action: 'typing' }); // Process message through the ChatGPT integration (no duplication!) console.log('[Telegram] Processing through ChatGPT with MCP:', text); const response = await handleChatMessage(text, history); // Update history history.push({ role: "user", content: text }, { role: "assistant", content: response }); // Keep history manageable if (history.length > 20) { history = history.slice(-20); } chatHistory.set(chatId, history); await sendTelegramMessage(chatId, response); } catch (error) { console.error('[Telegram] Error:', error); if (chatId) { try { await sendTelegramMessage(chatId, `āŒ Sorry, I encountered an error: ${error.message}`); } catch (sendError) { console.error('[Telegram] Failed to send error message:', sendError); } } } res.sendStatus(200); }); // Telegram webhook verification endpoint router.get('/telegram', (req, res) => { res.send('Telegram webhook endpoint is ready'); }); // Status endpoint for Telegram integration router.get('/telegram/status', async (req, res) => { try { const healthResponse = await axios.get('http://localhost:3000/api/health'); const health = healthResponse.data; const status = { telegram: 'ready', bot: { configured: !!TELEGRAM_BOT_TOKEN, token: TELEGRAM_BOT_TOKEN ? `${TELEGRAM_BOT_TOKEN.substring(0, 10)}...` : 'not configured' }, mcp: health.mcp, mcpUrl: 'http://localhost:3000/mcp', authorized_users: AUTHORIZED_USERS.length, timestamp: new Date().toISOString() }; res.json(status); } catch (error) { res.status(500).json({ error: 'Failed to check system health', timestamp: new Date().toISOString() }); } }); // Webhook setup helper endpoint router.post('/telegram/webhook', async (req, res) => { try { const { webhookUrl } = req.body; if (!webhookUrl) { res.status(400).json({ error: 'webhookUrl is required' }); return; } if (!TELEGRAM_BOT_TOKEN) { res.status(400).json({ error: 'TELEGRAM_BOT_TOKEN not configured' }); return; } // Set webhook URL const response = await axios.post(`${TELEGRAM_API_URL}/setWebhook`, { url: webhookUrl }); res.json({ success: true, message: 'Webhook set successfully', data: response.data }); } catch (error) { res.status(500).json({ error: error.response?.data || error.message }); } }); // Test endpoint to send a Telegram message router.post('/telegram/test', async (req, res) => { try { const { chatId, message } = req.body; if (!chatId || !message) { res.status(400).json({ error: 'Both "chatId" and "message" are required' }); return; } await sendTelegramMessage(chatId, message); res.json({ success: true, message: 'Telegram message sent' }); } catch (error) { res.status(500).json({ error: error.message }); } }); export default router;