Skip to main content
Glama
chat.ts9.63 kB
import express from 'express'; import { v4 as uuidv4 } from 'uuid'; import axios from 'axios'; import { database } from '../db/database'; import { AuthenticatedRequest, authenticateToken } from '../middleware/auth'; const router = express.Router(); // Create a new chat session (authenticated - for tenant dashboard) router.post('/sessions', authenticateToken, async (req: AuthenticatedRequest, res) => { try { const { tenantId } = req.user!; const { domain, userAgent } = req.body; const userIp = req.ip || req.connection.remoteAddress; // Verify tenant exists const tenant = await database.get('SELECT id FROM tenants WHERE id = ?', [tenantId]); if (!tenant) { return res.status(404).json({ error: 'Tenant not found' }); } // Generate session token const sessionToken = uuidv4(); // Create chat session const result = await database.run( 'INSERT INTO chat_sessions (tenant_id, domain, user_ip, user_agent, session_token) VALUES (?, ?, ?, ?, ?)', [tenantId, domain, userIp, userAgent, sessionToken] ); // Log analytics event await database.run( 'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)', [tenantId, 'chat_session_started', JSON.stringify({ sessionId: result.lastID, domain })] ); res.status(201).json({ sessionId: result.lastID, sessionToken, tenantId, message: 'Chat session created successfully' }); } catch (error) { console.error('Create session error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // Create a new chat session (public - for widget) router.post('/public/sessions', async (req, res) => { try { const { tenantId, domain, userAgent } = req.body; const userIp = req.ip || req.connection.remoteAddress; if (!tenantId) { return res.status(400).json({ error: 'Tenant ID is required' }); } // Verify tenant exists const tenant = await database.get('SELECT id FROM tenants WHERE id = ?', [tenantId]); if (!tenant) { return res.status(404).json({ error: 'Tenant not found' }); } // Generate session token const sessionToken = uuidv4(); // Create chat session const result = await database.run( 'INSERT INTO chat_sessions (tenant_id, domain, user_ip, user_agent, session_token) VALUES (?, ?, ?, ?, ?)', [tenantId, domain, userIp, userAgent, sessionToken] ); // Log analytics event await database.run( 'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)', [tenantId, 'chat_session_started', JSON.stringify({ sessionId: result.lastID, domain })] ); res.status(201).json({ sessionId: result.lastID, sessionToken, message: 'Chat session created successfully' }); } catch (error) { console.error('Create session error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // Send a message and get AI response router.post('/messages', async (req, res) => { try { const { sessionToken, message, tenantId } = req.body; if (!sessionToken || !message || !tenantId) { return res.status(400).json({ error: 'Session token, message, and tenant ID are required' }); } // Get chat session const session = await database.get( 'SELECT * FROM chat_sessions WHERE session_token = ? AND tenant_id = ?', [sessionToken, tenantId] ); if (!session) { return res.status(404).json({ error: 'Chat session not found' }); } // Save user message await database.run( 'INSERT INTO chat_messages (session_id, sender, message) VALUES (?, ?, ?)', [session.id, 'user', message] ); // Get chat history for context const chatHistory = await database.query( 'SELECT sender, message, timestamp FROM chat_messages WHERE session_id = ? ORDER BY timestamp ASC', [session.id] ); // Get tenant's knowledge base const knowledgeBase = await database.query( 'SELECT name, type, source FROM knowledge_base WHERE tenant_id = ? AND status = "active"', [tenantId] ); try { // Call MCP server for AI response const mcpResponse = await axios.post(`${process.env.MCP_SERVER_URL}/chat`, { message, history: chatHistory, knowledge_base: knowledgeBase, tenant_id: tenantId }, { headers: { 'Authorization': `Bearer ${process.env.MCP_AUTH_TOKEN}`, 'Content-Type': 'application/json' }, timeout: 30000 // 30 second timeout }); const aiResponse = mcpResponse.data.response || 'I apologize, but I encountered an issue processing your request.'; // Save AI response await database.run( 'INSERT INTO chat_messages (session_id, sender, message, metadata) VALUES (?, ?, ?, ?)', [session.id, 'ai', aiResponse, JSON.stringify({ model: mcpResponse.data.model || 'gemini-1.5-flash', confidence: mcpResponse.data.confidence || 0.8 })] ); // Log analytics event await database.run( 'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)', [tenantId, 'message_sent', JSON.stringify({ sessionId: session.id, messageLength: message.length, responseLength: aiResponse.length })] ); res.json({ response: aiResponse, messageId: session.id, timestamp: new Date().toISOString() }); } catch (mcpError) { console.error('MCP Server error:', mcpError); // Fallback response if MCP server is down const fallbackResponse = "I'm sorry, but I'm experiencing technical difficulties at the moment. Please try again in a few minutes or contact support if the issue persists."; await database.run( 'INSERT INTO chat_messages (session_id, sender, message, metadata) VALUES (?, ?, ?, ?)', [session.id, 'ai', fallbackResponse, JSON.stringify({ error: 'mcp_server_unavailable' })] ); res.json({ response: fallbackResponse, messageId: session.id, timestamp: new Date().toISOString(), error: 'Service temporarily unavailable' }); } } catch (error) { console.error('Send message error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // Get chat history router.get('/sessions/:sessionToken/history', async (req, res) => { try { const { sessionToken } = req.params; const { tenantId } = req.query; if (!tenantId) { return res.status(400).json({ error: 'Tenant ID is required' }); } // Get session const session = await database.get( 'SELECT * FROM chat_sessions WHERE session_token = ? AND tenant_id = ?', [sessionToken, tenantId] ); if (!session) { return res.status(404).json({ error: 'Chat session not found' }); } // Get messages const messages = await database.query( 'SELECT sender, message, metadata, timestamp FROM chat_messages WHERE session_id = ? ORDER BY timestamp ASC', [session.id] ); res.json({ sessionId: session.id, messages, session: { started_at: session.started_at, resolved: session.resolved, rating: session.rating } }); } catch (error) { console.error('Get history error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // Rate conversation router.post('/sessions/:sessionToken/rate', async (req, res) => { try { const { sessionToken } = req.params; const { rating, feedback, tenantId } = req.body; if (!tenantId || rating === undefined) { return res.status(400).json({ error: 'Tenant ID and rating are required' }); } if (rating < 1 || rating > 5) { return res.status(400).json({ error: 'Rating must be between 1 and 5' }); } // Update session await database.run( 'UPDATE chat_sessions SET rating = ?, feedback = ?, resolved = TRUE WHERE session_token = ? AND tenant_id = ?', [rating, feedback, sessionToken, tenantId] ); // Log analytics event await database.run( 'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)', [tenantId, 'conversation_rated', JSON.stringify({ sessionToken, rating, hasFeedback: !!feedback })] ); res.json({ message: 'Rating submitted successfully' }); } catch (error) { console.error('Rate conversation error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // End chat session router.post('/sessions/:sessionToken/end', async (req, res) => { try { const { sessionToken } = req.params; const { tenantId } = req.body; if (!tenantId) { return res.status(400).json({ error: 'Tenant ID is required' }); } // Update session await database.run( 'UPDATE chat_sessions SET ended_at = CURRENT_TIMESTAMP WHERE session_token = ? AND tenant_id = ?', [sessionToken, tenantId] ); // Log analytics event await database.run( 'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)', [tenantId, 'chat_session_ended', JSON.stringify({ sessionToken })] ); res.json({ message: 'Chat session ended successfully' }); } catch (error) { console.error('End session error:', error); res.status(500).json({ error: 'Internal server error' }); } }); export default router;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ChiragPatankar/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server