Skip to main content
Glama
chatbot.service.ts9.36 kB
/** * Chatbot Service * Provides support responses and FAQ handling */ import { SupportFAQ, ChatbotResponse } from '../types/index.js'; import { logger } from '../utils/logger.js'; import { OpenAIService } from './openai.service.js'; export class ChatbotService { private faqs: SupportFAQ[]; private readonly openAIService?: OpenAIService; constructor(openAIService?: OpenAIService) { this.faqs = this.initializeFAQs(); this.openAIService = openAIService; } /** * Initialize FAQ database */ private initializeFAQs(): SupportFAQ[] { return [ // Account & Registration { question: 'Como criar uma conta no FitSlot?', answer: 'Para criar uma conta, acesse o aplicativo ou website, clique em "Registrar" e preencha seus dados pessoais. Você receberá um email de confirmação.', category: 'conta', keywords: ['criar', 'conta', 'registrar', 'cadastro', 'sign up'] }, { question: 'Como recuperar minha senha?', answer: 'Na tela de login, clique em "Esqueci minha senha", digite seu email cadastrado e siga as instruções enviadas por email.', category: 'conta', keywords: ['senha', 'recuperar', 'esqueci', 'password', 'reset'] }, { question: 'Como atualizar meus dados cadastrais?', answer: 'Acesse o menu "Perfil" no aplicativo, clique em "Editar Dados" e atualize as informações desejadas. Não esqueça de salvar as alterações.', category: 'conta', keywords: ['atualizar', 'dados', 'perfil', 'editar', 'update'] }, // Scheduling { question: 'Como agendar um horário?', answer: 'Vá para "Agendamentos", selecione o serviço desejado, escolha data e horário disponível, e confirme o agendamento. Você receberá uma confirmação.', category: 'agendamento', keywords: ['agendar', 'marcar', 'horário', 'scheduling', 'appointment'] }, { question: 'Como cancelar um agendamento?', answer: 'Acesse "Meus Agendamentos", selecione o agendamento que deseja cancelar e clique em "Cancelar". É possível cancelar até 24 horas antes.', category: 'agendamento', keywords: ['cancelar', 'desmarcar', 'agendamento', 'cancel'] }, { question: 'Como reagendar um horário?', answer: 'Você pode cancelar o agendamento atual e criar um novo, ou entrar em contato com o suporte para reagendar mantendo sua prioridade.', category: 'agendamento', keywords: ['reagendar', 'remarcar', 'trocar', 'reschedule'] }, // Bioimpedance { question: 'O que é bioimpedância?', answer: 'Bioimpedância é um exame não invasivo que avalia a composição corporal, medindo percentual de gordura, massa muscular, água corporal e outros indicadores.', category: 'bioimpedancia', keywords: ['bioimpedância', 'bioimpedance', 'composição', 'corporal', 'exame'] }, { question: 'Como me preparar para o exame de bioimpedância?', answer: 'Esteja em jejum de 4 horas, evite exercícios intensos 24h antes, esvazie a bexiga antes do exame, e evite consumo de álcool e cafeína no dia anterior.', category: 'bioimpedancia', keywords: ['preparar', 'jejum', 'bioimpedância', 'exame', 'preparation'] }, { question: 'Como visualizar meus resultados de bioimpedância?', answer: 'Os resultados ficam disponíveis em "Meus Exames" após processamento. Você pode baixar o PDF ou visualizar online com as análises detalhadas.', category: 'bioimpedancia', keywords: ['resultado', 'visualizar', 'exame', 'pdf', 'results'] }, // Support & Technical { question: 'O aplicativo não está funcionando, o que fazer?', answer: 'Primeiro, tente fechar e abrir o app novamente. Se persistir, verifique sua conexão de internet, atualize o app para última versão ou reinstale.', category: 'suporte', keywords: ['não funciona', 'erro', 'problema', 'bug', 'error'] }, { question: 'Como entrar em contato com o suporte?', answer: 'Você pode abrir um ticket através do menu "Suporte" no app, enviar email para suporte@fitslot.com, ou ligar para (11) 1234-5678.', category: 'suporte', keywords: ['contato', 'suporte', 'ajuda', 'contact', 'support', 'help'] }, // Payment & Plans { question: 'Quais são as formas de pagamento aceitas?', answer: 'Aceitamos cartão de crédito, débito, PIX, boleto bancário e pagamento através da plataforma. Consulte as taxas específicas de cada serviço.', category: 'pagamento', keywords: ['pagamento', 'pagar', 'payment', 'cartão', 'pix', 'boleto'] }, { question: 'Como solicitar reembolso?', answer: 'Para solicitar reembolso, acesse "Meus Pagamentos", selecione a transação e clique em "Solicitar Reembolso". Analisaremos em até 5 dias úteis.', category: 'pagamento', keywords: ['reembolso', 'devolução', 'refund', 'estorno'] } ]; } /** * Search for relevant FAQs based on query */ searchFAQs(query: string, limit: number = 5): SupportFAQ[] { const normalizedQuery = query.toLowerCase().trim(); // Score each FAQ based on relevance const scoredFAQs = this.faqs.map(faq => { let score = 0; // Check if query matches keywords for (const keyword of faq.keywords) { if (normalizedQuery.includes(keyword.toLowerCase())) { score += 10; } } // Check if query matches question or answer if (faq.question.toLowerCase().includes(normalizedQuery)) { score += 20; } if (faq.answer.toLowerCase().includes(normalizedQuery)) { score += 5; } // Check individual words const queryWords = normalizedQuery.split(/\s+/); for (const word of queryWords) { if (word.length > 3) { // Ignore short words if (faq.question.toLowerCase().includes(word)) { score += 3; } if (faq.keywords.some(k => k.toLowerCase().includes(word))) { score += 2; } } } return { faq, score }; }); // Sort by score and return top results return scoredFAQs .filter(item => item.score > 0) .sort((a, b) => b.score - a.score) .slice(0, limit) .map(item => item.faq); } /** * Get chatbot response for a user query */ async getChatbotResponse(query: string): Promise<ChatbotResponse> { logger.info('Processing chatbot query', { query }); const relatedFAQs = this.searchFAQs(query, 3); let message: string; const suggestedActions: string[] = []; if (relatedFAQs.length > 0) { // Found relevant FAQs message = 'Encontrei algumas informações que podem ajudar você:'; suggestedActions.push('Ver FAQs relacionadas'); // Add context-specific suggestions const categories = new Set(relatedFAQs.map(faq => faq.category)); if (categories.has('agendamento')) { suggestedActions.push('Criar novo agendamento'); suggestedActions.push('Ver meus agendamentos'); } if (categories.has('conta')) { suggestedActions.push('Editar perfil'); } if (categories.has('bioimpedancia')) { suggestedActions.push('Ver meus exames'); suggestedActions.push('Agendar bioimpedância'); } if (categories.has('suporte')) { suggestedActions.push('Abrir ticket de suporte'); } } else { // No relevant FAQs found message = 'Não encontrei uma resposta específica para sua pergunta. Posso ajudar você de outras formas:'; suggestedActions.push( 'Abrir ticket de suporte', 'Falar com atendente', 'Ver todas as FAQs', 'Buscar na central de ajuda' ); } const fallbackResponse: ChatbotResponse = { message, relatedFAQs: relatedFAQs.length > 0 ? relatedFAQs : undefined, suggestedActions }; logger.debug('Chatbot fallback response generated', { relatedFAQsCount: relatedFAQs.length, suggestedActionsCount: suggestedActions.length }); if (!this.openAIService?.isConfigured()) { return fallbackResponse; } try { const aiMessage = await this.openAIService.generateSupportAnswer({ query, relatedFAQs, suggestedActions }); if (aiMessage) { logger.debug('Chatbot response enhanced with OpenAI'); return { ...fallbackResponse, message: aiMessage }; } } catch (error) { logger.warn('Failed to enhance chatbot response with OpenAI', error); } return fallbackResponse; } /** * Get FAQs by category */ getFAQsByCategory(category: string): SupportFAQ[] { return this.faqs.filter(faq => faq.category.toLowerCase() === category.toLowerCase() ); } /** * Get all FAQ categories */ getCategories(): string[] { return [...new Set(this.faqs.map(faq => faq.category))]; } /** * Get all FAQs */ getAllFAQs(): SupportFAQ[] { return this.faqs; } }

Implementation Reference

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/osmarsant/fitslot-mcp'

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