UNPKG

eventpulse-mcp

Version:

EventPulse MCP Server - Hyper-local event-driven marketing campaigns for small businesses

437 lines (369 loc) 14.9 kB
const OpenAI = require('openai'); const fs = require('fs'); const path = require('path'); const { enhanceWhatsAppMessage, enhanceSocialMediaPost, addCulturalContext } = require('./content-enhancer'); // Initialize OpenAI (optional for testing) let openai = null; try { if (process.env.OPENAI_API_KEY && process.env.OPENAI_API_KEY !== 'your_openai_api_key_here') { openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); console.log('✅ OpenAI client initialized'); } else { console.log('⚠️ OpenAI not configured, using mock data for testing'); } } catch (error) { console.log('⚠️ OpenAI initialization failed, using mock data:', error.message); } // Load data files const festivalsData = JSON.parse(fs.readFileSync(path.join(__dirname, '../data/festivals.json'), 'utf8')); const templatesData = JSON.parse(fs.readFileSync(path.join(__dirname, '../data/templates.json'), 'utf8')); const hashtagsData = JSON.parse(fs.readFileSync(path.join(__dirname, '../data/regional-hashtags.json'), 'utf8')); /** * Main campaign generation function */ async function generateCampaign(request) { const startTime = Date.now(); try { console.log('🎯 Generating campaign for:', request); // Get festival and business context const festivalContext = getFestivalContext(request.event); const businessContext = getBusinessContext(request.business_type); const languageTemplate = getLanguageTemplate(request.language); // Generate different types of content const [whatsappMessage, socialPosts, hashtags, offers] = await Promise.all([ generateWhatsAppMessage(request, festivalContext, businessContext, languageTemplate), generateSocialMediaPosts(request, festivalContext, businessContext, languageTemplate), generateHashtags(request, festivalContext), generatePromotionalOffers(request, festivalContext, businessContext) ]); // Get scheduling suggestions const schedulingSuggestions = getSchedulingSuggestions(request.event); const processingTime = Date.now() - startTime; return { whatsapp_message: whatsappMessage, social_media_posts: socialPosts, hashtags: hashtags, promotional_offers: offers, scheduling_suggestions: schedulingSuggestions, processing_time: processingTime }; } catch (error) { console.error('❌ Campaign generation error:', error); throw new Error(`Campaign generation failed: ${error.message}`); } } /** * Generate WhatsApp message */ async function generateWhatsAppMessage(request, festivalContext, businessContext, languageTemplate) { const prompt = ` ${languageTemplate.whatsapp_template.replace('{business_type}', request.business_type).replace('{event}', request.event)} Context: - Festival: ${request.event} (${festivalContext.description}) - Business: ${request.business_type} - Language: ${request.language} - Location: ${request.location || 'India'} - Cultural greeting: ${festivalContext.cultural_context[request.language] || festivalContext.cultural_context.english} Business opportunities for this festival: ${festivalContext.business_opportunities[request.business_type]?.join(', ') || 'general festive offers'} Requirements: 1. Start with appropriate festival greeting in ${request.language} 2. Mention 1-2 specific offers relevant to the business and festival 3. Include business appeal and call-to-action 4. Keep it under 160 characters for WhatsApp 5. Use emojis appropriately 6. End with contact encouragement Generate a compelling WhatsApp message: `; if (openai) { try { const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: prompt }], max_tokens: 200, temperature: 0.7 }); let message = response.choices[0].message.content.trim(); // Enhance message with emojis and cultural context message = enhanceWhatsAppMessage(message, request.event, request.business_type); message = addCulturalContext(message, request.event, request.language, request.location); return message; } catch (error) { console.error('WhatsApp generation error:', error); } } // Use fallback if OpenAI is not available return getFallbackWhatsAppMessage(request, festivalContext); } /** * Generate social media posts */ async function generateSocialMediaPosts(request, festivalContext, businessContext, languageTemplate) { const prompt = ` ${languageTemplate.social_template.replace('{business_type}', request.business_type).replace('{event}', request.event)} Context: - Festival: ${request.event} - Business: ${request.business_type} - Language: ${request.language} - Cultural context: ${festivalContext.cultural_context[request.language] || festivalContext.cultural_context.english} Generate 2 different social media posts: 1. One focused on festival celebration and community 2. One focused on special offers and business promotion Each post should be engaging, use appropriate emojis, and be suitable for Instagram/Facebook. `; if (openai) { try { const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: prompt }], max_tokens: 300, temperature: 0.8 }); const content = response.choices[0].message.content.trim(); let posts = content.split('\n\n').filter(post => post.trim().length > 0); // Enhance posts with cultural context and engagement elements posts = posts.map(post => { let enhanced = enhanceSocialMediaPost(post, request.event, request.business_type, request.language); enhanced = addCulturalContext(enhanced, request.event, request.language, request.location); return enhanced; }); return posts.length >= 2 ? posts.slice(0, 2) : posts.length > 0 ? posts : [content]; } catch (error) { console.error('Social media generation error:', error); } } // Use fallback if OpenAI is not available return getFallbackSocialPosts(request, festivalContext); } /** * Generate relevant hashtags */ async function generateHashtags(request, festivalContext) { const baseHashtags = festivalContext.popular_hashtags || []; const businessHashtags = getBusinessHashtags(request.business_type); const locationHashtags = getLocationHashtags(request.location); const trendingHashtags = getTrendingHashtags(request.event); const seasonalHashtags = getSeasonalHashtags(); // Combine and return unique hashtags const allHashtags = [ ...baseHashtags, ...businessHashtags, ...locationHashtags, ...trendingHashtags, ...seasonalHashtags ]; return [...new Set(allHashtags)].slice(0, 12); } /** * Generate promotional offers */ async function generatePromotionalOffers(request, festivalContext, businessContext) { const businessOpportunities = festivalContext.business_opportunities[request.business_type] || []; const commonOffers = businessContext.common_offers || []; const offers = []; // Festival-specific offers if (businessOpportunities.length > 0) { offers.push(`Special ${request.event} collection: ${businessOpportunities[0]}`); if (businessOpportunities.length > 1) { offers.push(`${request.event} exclusive: ${businessOpportunities[1]}`); } } // Business-specific offers with dynamic values if (commonOffers.length > 0) { const discountPercentage = getRandomDiscount(); const minAmount = getRandomAmount(request.business_type); offers.push( commonOffers[0] .replace('{percentage}', discountPercentage) .replace('{amount}', minAmount) ); if (commonOffers.length > 1) { offers.push(commonOffers[1].replace('{amount}', minAmount)); } } // Festival-specific value-added offers const festivalOffers = getFestivalSpecificOffers(request.event, request.business_type); offers.push(...festivalOffers); return offers.slice(0, 4); } /** * Get random discount percentage */ function getRandomDiscount() { const discounts = ['10', '15', '20', '25', '30']; return discounts[Math.floor(Math.random() * discounts.length)]; } /** * Get random minimum amount based on business type */ function getRandomAmount(businessType) { const amountMap = { 'sweet_shop': ['299', '499', '799'], 'clothing_store': ['999', '1499', '1999'], 'restaurant': ['399', '599', '899'], 'jewelry_shop': ['2999', '4999', '9999'], 'electronics': ['4999', '9999', '14999'] }; const amounts = amountMap[businessType.toLowerCase().replace(/\s+/g, '_')] || ['499', '999', '1499']; return amounts[Math.floor(Math.random() * amounts.length)]; } /** * Get festival-specific offers */ function getFestivalSpecificOffers(eventName, businessType) { const festivalOffers = { 'diwali': [ 'Free gift wrapping with festive packaging', 'Complimentary Diwali greeting card', 'Lucky draw entry with every purchase' ], 'holi': [ 'Free color-safe packaging', 'Complimentary herbal gulal', 'Group booking discounts available' ], 'eid': [ 'Free dates with every purchase', 'Special Eid gift packaging', 'Family combo offers' ], 'navratri': [ 'Free garba accessories', 'Dandiya stick complimentary', '9-day festival package deals' ] }; const offers = festivalOffers[eventName.toLowerCase()] || ['Free festival packaging']; return offers.slice(0, 1); } /** * Get festival context from data */ function getFestivalContext(eventName) { const festival = festivalsData.festivals[eventName.toLowerCase()]; if (festival) { return festival; } // Fallback for unknown festivals return { name: eventName, description: 'Special celebration', business_opportunities: { 'sweet_shop': ['special sweets', 'gift boxes'], 'clothing_store': ['festive wear', 'special collection'], 'restaurant': ['special menu', 'family packages'] }, cultural_context: { 'hindi': 'शुभकामनाएं', 'gujarati': 'શુભકામનાઓ', 'english': 'Best wishes' }, popular_hashtags: [`#${eventName}`, '#Festival', '#Celebration'] }; } /** * Get business context from data */ function getBusinessContext(businessType) { return festivalsData.business_types[businessType.toLowerCase().replace(/\s+/g, '_')] || { keywords: ['business', 'service', 'quality'], common_offers: ['special discount', 'limited time offer'] }; } /** * Get language template */ function getLanguageTemplate(language) { return templatesData.prompt_templates[language.toLowerCase()] || templatesData.prompt_templates.english; } /** * Get scheduling suggestions */ function getSchedulingSuggestions(eventName) { const timing = templatesData.timing_suggestions[eventName.toLowerCase()]; if (timing) { return { optimal_time: timing.optimal_posting_times[0], all_optimal_times: timing.optimal_posting_times, campaign_duration: timing.campaign_duration, peak_engagement: timing.peak_engagement }; } return { optimal_time: '10:00 AM', all_optimal_times: ['10:00 AM', '2:00 PM', '6:00 PM'], campaign_duration: '5-7 days before festival', peak_engagement: 'morning and evening hours' }; } /** * Get business-specific hashtags */ function getBusinessHashtags(businessType) { const businessKey = businessType.toLowerCase().replace(/\s+/g, '_'); return hashtagsData.business_trending[businessKey] || ['#Business', '#Quality', '#Service']; } /** * Get location-specific hashtags */ function getLocationHashtags(location) { if (!location) return []; const locationKey = location.toLowerCase().replace(/\s+/g, ''); const locationHashtags = hashtagsData.regional_hashtags[locationKey]; if (locationHashtags) { return locationHashtags.slice(0, 3); } // Fallback for unknown locations return [`#${location.replace(/\s+/g, '')}`]; } /** * Get trending hashtags for festival */ function getTrendingHashtags(eventName) { const eventKey = eventName.toLowerCase().replace(/\s+/g, '_'); const festivalTrending = hashtagsData.festival_trending[eventKey]; if (festivalTrending) { const currentYear = new Date().getFullYear().toString(); const yearlyTags = festivalTrending[currentYear] || []; const generalTags = festivalTrending.general || []; return [...yearlyTags.slice(0, 2), ...generalTags.slice(0, 2)]; } return []; } /** * Get seasonal hashtags */ function getSeasonalHashtags() { const month = new Date().getMonth() + 1; let season = 'spring'; if (month >= 12 || month <= 2) season = 'winter'; else if (month >= 3 && month <= 5) season = 'spring'; else if (month >= 6 && month <= 9) season = 'monsoon'; else if (month >= 10 && month <= 11) season = 'summer'; return hashtagsData.seasonal_hashtags[season]?.slice(0, 1) || []; } /** * Fallback WhatsApp message if AI fails */ function getFallbackWhatsAppMessage(request, festivalContext) { const greeting = festivalContext.cultural_context[request.language] || 'Best wishes'; const festivalEmojis = require('./content-enhancer').getFestivalEmojis(request.event); const businessEmojis = require('./content-enhancer').getBusinessEmojis(request.business_type); return `${festivalEmojis[0]} ${greeting}! Special ${request.event} offers at our ${businessEmojis[0]} ${request.business_type}! Visit us today. 📞`; } /** * Fallback social posts if AI fails */ function getFallbackSocialPosts(request, festivalContext) { const greeting = festivalContext.cultural_context[request.language] || 'Celebrating'; const festivalEmojis = require('./content-enhancer').getFestivalEmojis(request.event); const businessEmojis = require('./content-enhancer').getBusinessEmojis(request.business_type); return [ `${festivalEmojis.slice(0, 2).join('')} ${greeting} ${request.event} with joy and happiness! Visit our ${businessEmojis[0]} ${request.business_type} for special celebrations.`, `${festivalEmojis[0]} Special ${request.event} offers now available! Don't miss out on our exclusive deals. #${request.event} #SpecialOffers` ]; } module.exports = { generateCampaign };