UNPKG

embedia

Version:

Zero-configuration AI chatbot integration CLI - direct file copy with embedded API keys

379 lines (354 loc) • 12.1 kB
const inquirer = require('inquirer'); const chalk = require('chalk'); class ConfigurationWizard { async run(initialConfig = {}) { console.log(chalk.cyan('\nšŸŽØ Embedia Chat Configuration Wizard\n')); const answers = await this.askQuestions(initialConfig); const config = this.buildConfig(answers); // Show preview await this.showPreview(config); // Confirm configuration const confirmed = await this.confirmConfig(); if (confirmed) { return config; } else { // Restart wizard with current config as defaults return this.run(config); } } async askQuestions(defaults) { const questions = [ { type: 'input', name: 'chatbotName', message: 'What should we call your chatbot?', default: defaults.chatbotName || 'AI Assistant', validate: (input) => input.length > 0 || 'Name is required' }, { type: 'input', name: 'subtitle', message: 'Add a subtitle (optional):', default: defaults.subtitle || 'Powered by AI' }, { type: 'editor', name: 'systemPrompt', message: 'Define your chatbot\'s personality and expertise:', default: defaults.systemPrompt || 'You are a helpful AI assistant. Be friendly, professional, and concise in your responses.' }, { type: 'list', name: 'position', message: 'Where should the chat button appear?', choices: [ { name: 'Bottom Right (Recommended)', value: 'bottom-right' }, { name: 'Bottom Left', value: 'bottom-left' }, { name: 'Top Right', value: 'top-right' }, { name: 'Top Left', value: 'top-left' }, { name: 'Custom (CSS selector)', value: 'custom' } ], default: defaults.position || 'bottom-right' } ]; // Add custom position question if needed const answers = await inquirer.prompt(questions); if (answers.position === 'custom') { const customPosition = await inquirer.prompt([ { type: 'input', name: 'customSelector', message: 'Enter CSS selector for chat container:', default: '#chat-container', validate: (input) => input.length > 0 || 'Selector is required' } ]); answers.customSelector = customPosition.customSelector; } // Color scheme questions const colorAnswers = await this.askColorQuestions(defaults); // Advanced options const { wantsAdvanced } = await inquirer.prompt([ { type: 'confirm', name: 'wantsAdvanced', message: 'Configure advanced options?', default: false } ]); let advancedAnswers = {}; if (wantsAdvanced) { advancedAnswers = await this.askAdvancedQuestions(defaults); } return { ...answers, ...colorAnswers, ...advancedAnswers }; } async askColorQuestions(defaults) { const { colorScheme } = await inquirer.prompt([ { type: 'list', name: 'colorScheme', message: 'Choose a color scheme:', choices: [ { name: chalk.blue('ā— Blue (Professional)'), value: 'blue' }, { name: chalk.green('ā— Green (Friendly)'), value: 'green' }, { name: chalk.magenta('ā— Purple (Creative)'), value: 'purple' }, { name: chalk.red('ā— Red (Bold)'), value: 'red' }, { name: chalk.gray('ā— Dark (Elegant)'), value: 'dark' }, { name: chalk.yellow('ā— Light (Minimal)'), value: 'light' }, { name: chalk.gray('ā— Custom'), value: 'custom' } ], default: defaults.colorScheme || 'blue' } ]); if (colorScheme === 'custom') { return await this.askCustomColorQuestions(defaults); } return { colorScheme }; } async askCustomColorQuestions(defaults) { return inquirer.prompt([ { type: 'input', name: 'primaryColor', message: 'Primary color (hex):', default: defaults.primaryColor || '#2563EB', validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Invalid hex color' }, { type: 'input', name: 'primaryHoverColor', message: 'Primary hover color (hex):', default: defaults.primaryHoverColor || '#1D4ED8', validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Invalid hex color' }, { type: 'input', name: 'backgroundColor', message: 'Background color (hex):', default: defaults.backgroundColor || '#FFFFFF', validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Invalid hex color' }, { type: 'input', name: 'textColor', message: 'Text color (hex):', default: defaults.textColor || '#1F2937', validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Invalid hex color' }, { type: 'input', name: 'userMessageColor', message: 'User message bubble color (hex):', default: defaults.userMessageColor || '#3B82F6', validate: (input) => /^#[0-9A-F]{6}$/i.test(input) || 'Invalid hex color' } ]); } async askAdvancedQuestions(defaults) { return inquirer.prompt([ { type: 'input', name: 'avatarUrl', message: 'Avatar URL (leave empty for default):', default: defaults.avatarUrl || '' }, { type: 'input', name: 'backgroundImage', message: 'Chat background image URL (optional):', default: defaults.backgroundImage || '' }, { type: 'list', name: 'aiProvider', message: 'Choose your AI provider:', choices: [ { name: 'Google Gemini (Recommended)', value: 'gemini' }, { name: 'OpenAI (GPT-4)', value: 'openai' }, { name: 'Anthropic Claude', value: 'anthropic' }, { name: 'Custom Endpoint', value: 'custom' } ], default: defaults.aiProvider || 'gemini' }, { type: 'input', name: 'apiEndpoint', message: 'API endpoint:', default: '/api/embedia/chat', when: (answers) => answers.aiProvider === 'custom' }, { type: 'number', name: 'maxTokens', message: 'Maximum response tokens:', default: defaults.maxTokens || 500, validate: (input) => input > 0 && input <= 4000 || 'Must be between 1 and 4000' }, { type: 'number', name: 'temperature', message: 'AI temperature (0-1, higher = more creative):', default: defaults.temperature || 0.7, validate: (input) => input >= 0 && input <= 1 || 'Must be between 0 and 1' }, { type: 'confirm', name: 'enableAnalytics', message: 'Enable usage analytics?', default: defaults.enableAnalytics || false }, { type: 'confirm', name: 'enableSound', message: 'Enable notification sounds?', default: defaults.enableSound || true }, { type: 'confirm', name: 'persistConversations', message: 'Save conversations locally?', default: defaults.persistConversations || true }, { type: 'input', name: 'rateLimit', message: 'Rate limit (messages per minute):', default: defaults.rateLimit || 10, validate: (input) => input > 0 || 'Must be greater than 0' } ]); } buildConfig(answers) { const colorSchemes = { blue: { primary: '#2563EB', primaryHover: '#1D4ED8', background: '#FFFFFF', text: '#1F2937', userBubble: '#3B82F6', aiBubble: '#F3F4F6', userText: '#FFFFFF', aiText: '#1F2937' }, green: { primary: '#10B981', primaryHover: '#059669', background: '#FFFFFF', text: '#1F2937', userBubble: '#34D399', aiBubble: '#F3F4F6', userText: '#FFFFFF', aiText: '#1F2937' }, purple: { primary: '#8B5CF6', primaryHover: '#7C3AED', background: '#FFFFFF', text: '#1F2937', userBubble: '#A78BFA', aiBubble: '#F3F4F6', userText: '#FFFFFF', aiText: '#1F2937' }, red: { primary: '#EF4444', primaryHover: '#DC2626', background: '#FFFFFF', text: '#1F2937', userBubble: '#F87171', aiBubble: '#F3F4F6', userText: '#FFFFFF', aiText: '#1F2937' }, dark: { primary: '#1F2937', primaryHover: '#111827', background: '#111827', text: '#F9FAFB', userBubble: '#374151', aiBubble: '#1F2937', userText: '#F9FAFB', aiText: '#F9FAFB' }, light: { primary: '#6B7280', primaryHover: '#4B5563', background: '#FFFFFF', text: '#1F2937', userBubble: '#E5E7EB', aiBubble: '#F9FAFB', userText: '#1F2937', aiText: '#1F2937' } }; const colors = answers.colorScheme === 'custom' ? { primary: answers.primaryColor, primaryHover: answers.primaryHoverColor, background: answers.backgroundColor, text: answers.textColor, userBubble: answers.userMessageColor, aiBubble: '#F3F4F6', userText: '#FFFFFF', aiText: answers.textColor } : colorSchemes[answers.colorScheme] || colorSchemes.blue; return { chatbotName: answers.chatbotName, subtitle: answers.subtitle, systemPrompt: answers.systemPrompt, position: answers.position, customSelector: answers.customSelector, themeColors: colors, welcomeMessage: `Hello! I'm ${answers.chatbotName}. How can I help you today?`, placeholder: 'Type your message...', avatarUrl: answers.avatarUrl || null, backgroundImage: answers.backgroundImage || null, aiProvider: answers.aiProvider || 'gemini', apiEndpoint: answers.apiEndpoint || '/api/embedia/chat', maxTokens: answers.maxTokens || 500, temperature: answers.temperature || 0.7, enableAnalytics: answers.enableAnalytics || false, enableSound: answers.enableSound !== false, persistConversations: answers.persistConversations !== false, rateLimit: answers.rateLimit || 10, features: { darkMode: colors === colorSchemes.dark, typingIndicator: true, messageTimestamps: true, readReceipts: false, fileUpload: false, voiceInput: false } }; } async showPreview(config) { console.log(chalk.cyan('\nšŸ“‹ Configuration Preview:\n')); console.log(chalk.white('Name: ') + chalk.bold(config.chatbotName)); console.log(chalk.white('Subtitle: ') + config.subtitle); console.log(chalk.white('Position: ') + config.position); console.log(chalk.white('AI Provider: ') + config.aiProvider); console.log(chalk.white('Primary Color: ') + chalk.hex(config.themeColors.primary)('ā–ˆā–ˆā–ˆ')); console.log(chalk.white('Background: ') + chalk.hex(config.themeColors.background)('ā–ˆā–ˆā–ˆ')); console.log(chalk.white('System Prompt: ') + chalk.gray(config.systemPrompt.substring(0, 50) + '...')); if (config.enableAnalytics || config.avatarUrl || config.backgroundImage) { console.log(chalk.yellow('\nAdvanced Features:')); if (config.enableAnalytics) console.log(' āœ“ Analytics enabled'); if (config.avatarUrl) console.log(' āœ“ Custom avatar'); if (config.backgroundImage) console.log(' āœ“ Background image'); if (config.persistConversations) console.log(' āœ“ Conversation persistence'); } } async confirmConfig() { const { confirmed } = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: 'Does this look good?', default: true } ]); return confirmed; } } module.exports = ConfigurationWizard;