UNPKG

embedia

Version:

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

907 lines (750 loc) â€ĸ 26.2 kB
const BaseAdapter = require('../BaseAdapter'); const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); class UniversalAdapter extends BaseAdapter { async integrate(embediaFiles) { const componentType = embediaFiles.componentType || 'react'; console.log(chalk.yellow(`đŸ“Ļ Using universal integration for ${componentType === 'webcomponent' ? 'web components' : 'React components'}\n`)); const results = { success: false, framework: this.framework.name || 'unknown', universal: true, componentType: componentType, files: [], errors: [], instructions: [] }; try { if (componentType === 'webcomponent') { // Handle web component integration await this.integrateWebComponent(embediaFiles, results); } else { // Handle React component integration (legacy) await this.integrateReactComponent(embediaFiles, results); } results.success = true; } catch (error) { results.errors.push({ type: 'integration_error', message: error.message }); } return results; } async integrateWebComponent(embediaFiles, results) { // Create web component files in project root or public directory const publicDir = path.join(this.projectPath, 'public'); const hasPublic = await fs.pathExists(publicDir); const webComponentDir = hasPublic ? publicDir : this.projectPath; // Copy web component bundle const webComponentPath = path.join(webComponentDir, 'embedia-chatbot.js'); await fs.writeFile(webComponentPath, embediaFiles.component); results.files.push(hasPublic ? 'public/embedia-chatbot.js' : 'embedia-chatbot.js'); // Create example HTML const examplePath = await this.createWebComponentExample(embediaFiles, webComponentDir); results.files.push(examplePath); // Create integration examples for different frameworks const examplesDir = await this.createWebComponentIntegrationExamples(embediaFiles); results.files.push(`${examplesDir}/*`); // Create comprehensive guide const guidePath = await this.createWebComponentGuide(embediaFiles); results.files.push(guidePath); results.instructions = [ 'Web component integration complete!', '✨ Universal chatbot works in any framework', '', '🚀 Quick Start:', '1. Open embedia-example.html to test', '2. Copy integration code from embedia-examples/', '3. See EMBEDIA_WEB_COMPONENT_GUIDE.md for details', '', '📱 Works with: React, Vue, Angular, WordPress, Vanilla HTML' ]; } async integrateReactComponent(embediaFiles, results) { // Original React component integration logic await this.createComponentFiles(embediaFiles); results.files.push('components/generated/embedia-chat/*'); // Create standalone HTML example const htmlPath = await this.createStandaloneHTML(embediaFiles); results.files.push(htmlPath); // Create integration examples for various frameworks const examplesPath = await this.createIntegrationExamples(); results.files.push(examplesPath); // Add manual integration instructions instead of creating wrapper results.instructions.push(...this.getIntegrationInstructions()); // Create public/static files for direct access const publicFiles = await this.createPublicFiles(embediaFiles); results.files.push(...publicFiles); // Create detailed integration guide const guidePath = await this.createIntegrationGuide(); results.files.push(guidePath); results.instructions = [ 'Universal integration files created successfully!', 'See EMBEDIA_INTEGRATION_GUIDE.md for detailed instructions', 'Open embedia-chat-demo.html in a browser to test the chat', 'Copy the integration code for your specific framework' ]; } async createWebComponentExample(embediaFiles, webComponentDir) { const botId = embediaFiles.config?.botId || 'embedia-chatbot'; const exampleHTML = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Embedia Chatbot Example</title> <style> body { font-family: Arial, sans-serif; margin: 40px; line-height: 1.6; } .container { max-width: 800px; margin: 0 auto; } .header { text-align: center; margin-bottom: 40px; } .demo-content { background: #f4f4f4; padding: 20px; border-radius: 8px; margin: 20px 0; } </style> </head> <body> <div class="container"> <div class="header"> <h1>🤖 Embedia Chatbot Demo</h1> <p>This page demonstrates the Embedia web component integration.</p> <p>The chatbot should appear in the bottom-right corner.</p> </div> <div class="demo-content"> <h2>How it works</h2> <p>The chatbot is loaded as a web component using just two lines of code:</p> <pre><code>&lt;script src="embedia-chatbot.js"&gt;&lt;/script&gt; &lt;embedia-chatbot bot-id="${botId}"&gt;&lt;/embedia-chatbot&gt;</code></pre> <h3>Features</h3> <ul> <li>✅ Universal compatibility (works everywhere)</li> <li>✅ No framework dependencies</li> <li>✅ Shadow DOM encapsulation</li> <li>✅ Responsive design</li> <li>✅ Easy customization</li> </ul> </div> </div> <!-- Embedia Chatbot Integration --> <script src="${path.basename(webComponentDir) === 'public' ? '' : './'}embedia-chatbot.js"></script> <embedia-chatbot bot-id="${botId}" theme="default" position="bottom-right"> </embedia-chatbot> </body> </html>`; const examplePath = path.join(webComponentDir, 'embedia-example.html'); await fs.writeFile(examplePath, exampleHTML); return path.basename(webComponentDir) === 'public' ? 'public/embedia-example.html' : 'embedia-example.html'; } async createWebComponentIntegrationExamples(embediaFiles) { const examplesDir = path.join(this.projectPath, 'embedia-examples'); await fs.ensureDir(examplesDir); const botId = embediaFiles.config?.botId || 'embedia-chatbot'; // React example const reactExample = `// React Integration Example import { useEffect } from 'react'; function App() { useEffect(() => { // Load the web component script const script = document.createElement('script'); script.src = '/embedia-chatbot.js'; script.async = true; document.head.appendChild(script); return () => { // Cleanup const existingScript = document.querySelector('script[src="/embedia-chatbot.js"]'); if (existingScript) { document.head.removeChild(existingScript); } }; }, []); return ( <div className="App"> <h1>My React App</h1> {/* Your app content */} {/* Embedia Chatbot */} <embedia-chatbot bot-id="${botId}"></embedia-chatbot> </div> ); } export default App;`; // Vue example const vueExample = `<!-- Vue Integration Example --> <template> <div id="app"> <h1>My Vue App</h1> <!-- Your app content --> <!-- Embedia Chatbot --> <embedia-chatbot bot-id="${botId}"></embedia-chatbot> </div> </template> <script> export default { name: 'App', mounted() { // Load the web component script const script = document.createElement('script'); script.src = '/embedia-chatbot.js'; script.async = true; document.head.appendChild(script); }, beforeUnmount() { // Cleanup const existingScript = document.querySelector('script[src="/embedia-chatbot.js"]'); if (existingScript) { document.head.removeChild(existingScript); } } } </script>`; // WordPress example const wordPressExample = `<?php // WordPress Integration Example // Add this to your theme's functions.php file function enqueue_embedia_chatbot() { wp_enqueue_script( 'embedia-chatbot', get_template_directory_uri() . '/embedia-chatbot.js', array(), '1.0.0', true ); } add_action('wp_enqueue_scripts', 'enqueue_embedia_chatbot'); // Add this to your theme's footer.php before </body> ?> <embedia-chatbot bot-id="${botId}"></embedia-chatbot>`; // Vanilla HTML example const vanillaExample = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vanilla HTML Integration</title> </head> <body> <h1>My Website</h1> <!-- Your website content --> <!-- Embedia Chatbot Integration --> <script src="embedia-chatbot.js"></script> <embedia-chatbot bot-id="${botId}" theme="default" position="bottom-right"> </embedia-chatbot> </body> </html>`; // Write example files await fs.writeFile(path.join(examplesDir, 'react-integration.jsx'), reactExample); await fs.writeFile(path.join(examplesDir, 'vue-integration.vue'), vueExample); await fs.writeFile(path.join(examplesDir, 'wordpress-integration.php'), wordPressExample); await fs.writeFile(path.join(examplesDir, 'vanilla-html.html'), vanillaExample); return 'embedia-examples'; } async createWebComponentGuide(embediaFiles) { const botId = embediaFiles.config?.botId || 'embedia-chatbot'; const guide = `# Embedia Web Component Integration Guide ## Overview Your Embedia chatbot has been generated as a universal web component that works in any web environment - React, Vue, Angular, WordPress, or plain HTML. ## Quick Start ### 1. Basic Integration \`\`\`html <script src="embedia-chatbot.js"></script> <embedia-chatbot bot-id="${botId}"></embedia-chatbot> \`\`\` ### 2. Test the Integration Open \`embedia-example.html\` in your browser to see the chatbot in action. ## Framework-Specific Integration ### React/Next.js See \`embedia-examples/react-integration.jsx\` for complete example. Key points: - Load script in useEffect - Use the custom element directly in JSX - Handle cleanup on unmount ### Vue.js See \`embedia-examples/vue-integration.vue\` for complete example. Key points: - Load script in mounted() hook - Use custom element in template - Handle cleanup in beforeUnmount() ### WordPress See \`embedia-examples/wordpress-integration.php\` for complete example. Key points: - Enqueue script in functions.php - Add custom element to theme template - Use WordPress hooks for proper loading ### Vanilla HTML See \`embedia-examples/vanilla-html.html\` for complete example. Simply include the script and add the custom element anywhere in your HTML. ## Customization ### Attributes - \`bot-id\`: Your unique bot identifier (required) - \`theme\`: Visual theme (\`default\`, \`dark\`, \`light\`) - \`position\`: Position on screen (\`bottom-right\`, \`bottom-left\`, \`top-right\`, \`top-left\`) - \`api-endpoint\`: Custom API endpoint (optional) ### Example with Customization \`\`\`html <embedia-chatbot bot-id="${botId}" theme="dark" position="bottom-left"> </embedia-chatbot> \`\`\` ## Browser Support - Chrome 54+ - Firefox 63+ - Safari 10.1+ - Edge 79+ ## Troubleshooting ### Common Issues 1. **Chatbot doesn't appear** - Check that the script is loaded properly - Ensure the custom element is in the DOM - Check browser console for errors 2. **Styling conflicts** - Web component uses Shadow DOM for style isolation - Custom CSS won't affect the chatbot internals - Use theme attributes for styling 3. **Framework compatibility** - All modern frameworks support custom elements - For older versions, you may need polyfills ## Support For help and documentation, visit [https://docs.embedia.ai](https://docs.embedia.ai) Generated by Embedia CLI v2.3.0 `; const guidePath = path.join(this.projectPath, 'EMBEDIA_WEB_COMPONENT_GUIDE.md'); await fs.writeFile(guidePath, guide); return 'EMBEDIA_WEB_COMPONENT_GUIDE.md'; } async createStandaloneHTML(embediaFiles) { const htmlPath = 'embedia-chat-demo.html'; const htmlContent = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Embedia Chat Demo</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; } .container { max-width: 1200px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } h1 { color: #333; margin-bottom: 10px; } .subtitle { color: #666; margin-bottom: 30px; } .info { background: #f0f9ff; border: 1px solid #e0f2fe; padding: 20px; border-radius: 6px; margin-bottom: 20px; } code { background: #f3f4f6; padding: 2px 6px; border-radius: 3px; font-size: 14px; } </style> </head> <body> <div class="container"> <h1>Embedia Chat Demo</h1> <p class="subtitle">This is a standalone demo of your Embedia Chat widget</p> <div class="info"> <h3>â„šī¸ Integration Test</h3> <p>The chat widget should appear in the bottom-right corner of this page.</p> <p>If you don't see it, check the browser console for errors.</p> </div> <h2>Quick Integration</h2> <p>To add this chat to your website, include these scripts before the closing <code>&lt;/body&gt;</code> tag:</p> <pre><code>&lt;!-- Embedia Chat Integration --&gt; &lt;div id="embedia-chat-root"&gt;&lt;/div&gt; &lt;script src="https://unpkg.com/react@18/umd/react.production.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"&gt;&lt;/script&gt; &lt;script&gt; // Load Embedia Chat Component ${embediaFiles.component} // Initialize Chat // Simplified mounting logic &lt;/script&gt;</code></pre> </div> <!-- Embedia Chat Integration --> <embedia-chatbot></embedia-chatbot> <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script> <script> // Embedia Chat Configuration window.EMBEDIA_CONFIG = ${JSON.stringify(embediaFiles.config, null, 2)}; // Load Component ${embediaFiles.component} // Initialize if (window.EmbediaChat && // Simplified web component logic const container = document.getElementById('embedia-chat-root'); const root = } </script> </body> </html>`; await this.createFile(htmlPath, htmlContent); return htmlPath; } async createIntegrationExamples() { const examplesPath = 'embedia-integration-examples.js'; const examples = `// Embedia Chat Integration Examples for Various Frameworks // ========================================== // Vanilla JavaScript / HTML // ========================================== function integrateVanillaJS() { // Add to your HTML const chatRoot = document.createElement('div'); chatRoot.id = 'embedia-chat-root'; document.body.appendChild(chatRoot); // Load React if not already loaded if (!window.React) { const reactScript = document.createElement('script'); reactScript.src = 'https://unpkg.com/react@18/umd/react.production.min.js'; document.head.appendChild(reactScript); } if (!window.ReactDOM) { const reactDOMScript = document.createElement('script'); reactDOMScript.src = 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js'; document.head.appendChild(reactDOMScript); } // Load Embedia Chat import('/components/generated/embedia-chat/index.js').then((module) => { const EmbediaChat = module.default; // Simplified mounting }); } // ========================================== // React (Create React App, Vite, etc.) // ========================================== import { useEffect } from 'react'; function App() { useEffect(() => { import('/components/generated/embedia-chat/index.js').then((module) => { const EmbediaChat = module.default; const container = document.getElementById('embedia-chat-root'); if (container && !container.hasChildNodes()) { // Simplified mounting } }); }, []); return ( <div> {/* Your app content */} <embedia-chatbot></embedia-chatbot> </div> ); } // ========================================== // Vue.js // ========================================== export default { mounted() { this.loadEmbediaChat(); }, methods: { async loadEmbediaChat() { // Ensure React is available // React checks removed // Load Embedia Chat const module = await import('/components/generated/embedia-chat/index.js'); const EmbediaChat = module.default; const container = document.getElementById('embedia-chat-root'); if (container) { // Simplified mounting } }, async loadReact() { // Load React for Vue integration return new Promise((resolve) => { const script1 = document.createElement('script'); script1.src = 'https://unpkg.com/react@18/umd/react.production.min.js'; script1.onload = () => { const script2 = document.createElement('script'); script2.src = 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js'; script2.onload = resolve; document.head.appendChild(script2); }; document.head.appendChild(script1); }); } }, template: '<div id="app"><embedia-chatbot></embedia-chatbot></div>' } // ========================================== // Angular // ========================================== import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-root', template: '<embedia-chatbot></embedia-chatbot>' }) export class AppComponent implements OnInit { ngOnInit() { this.loadEmbediaChat(); } async loadEmbediaChat() { // Load React if needed // React checks removed // Dynamic import const module = await import('/components/generated/embedia-chat/index.js'); const EmbediaChat = module.default; const container = document.getElementById('embedia-chat-root'); if (container) { const root = (window as any). } } loadReactLibraries(): Promise<void> { // Implementation to load React libraries return new Promise((resolve) => { // Load scripts... resolve(); }); } } // ========================================== // Svelte // ========================================== <script> import { onMount } from 'svelte'; onMount(async () => { // Ensure React is loaded if (!// Simplified web component logic // Load React scripts } // Load Embedia Chat const module = await import('/components/generated/embedia-chat/index.js'); const EmbediaChat = module.default; const container = document.getElementById('embedia-chat-root'); if (container) { const root = window. } }); </script> <embedia-chatbot></embedia-chatbot> // ========================================== // WordPress Plugin // ========================================== function embedia_chat_enqueue_scripts() { // Enqueue React wp_enqueue_script('react', 'https://unpkg.com/react@18/umd/react.production.min.js'); wp_enqueue_script('react-dom', 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js'); // Enqueue Embedia Chat wp_enqueue_script( 'embedia-chat', plugin_dir_url(__FILE__) . 'components/generated/embedia-chat/index.js', array('react', 'react-dom'), '1.0.0', true ); // Initialize wp_add_inline_script('embedia-chat', ' document.addEventListener("DOMContentLoaded", function() { if (window.EmbediaChat && // Simplified web component logic const container = document.createElement("div"); container.id = "embedia-chat-root"; document.body.appendChild(container); const root = } }); '); } add_action('wp_enqueue_scripts', 'embedia_chat_enqueue_scripts'); `; await this.createFile(examplesPath, examples); return examplesPath; } getIntegrationInstructions() { return [ 'Manual integration required. Add Embedia Chat to your application:', '', 'For React applications:', ' import EmbediaChat from "/components/generated/embedia-chat"', ' <EmbediaChat />', '', 'For vanilla JavaScript:', ' <script type="module">', ' import("/components/generated/embedia-chat/index.js").then(module => {', ' const EmbediaChat = module.default;', ' const container = document.getElementById("embedia-chat-root");', ' // Simplified mounting', ' });', ' </script>', ' <embedia-chatbot></embedia-chatbot>', '', 'Note: The component is pre-compiled and works with both JavaScript and TypeScript.' ]; } async createPublicFiles(embediaFiles) { const publicFiles = []; // Try to find public directory const publicDirs = ['public', 'static', 'dist', 'www']; let publicDir = null; for (const dir of publicDirs) { if (await this.fileExists(dir)) { publicDir = dir; break; } } if (publicDir) { const embediaPublicDir = `${publicDir}/embedia-chat`; await fs.ensureDir(path.join(this.projectPath, embediaPublicDir)); // Copy files to public directory await this.createFile(`${embediaPublicDir}/embedia-chat.js`, embediaFiles.component); await this.createFile(`${embediaPublicDir}/config.json`, JSON.stringify(embediaFiles.config, null, 2)); publicFiles.push(`${embediaPublicDir}/*`); } return publicFiles; } async createIntegrationGuide() { const guidePath = 'EMBEDIA_INTEGRATION_GUIDE.md'; const guide = `# Embedia Chat - Universal Integration Guide ## 🚀 Quick Start ### Option 1: Standalone HTML Open \`embedia-chat-demo.html\` in your browser to see a working demo. ### Option 2: Copy Integration Code Check \`embedia-integration-examples.js\` for framework-specific examples. ### Option 3: Use Wrapper Component Import \`components/EmbediaChatWrapper\` in your React/Next.js/Gatsby app. ## đŸ“Ļ File Structure \`\`\` your-project/ ├── components/ │ ├── generated/ │ │ └── embedia-chat/ # Core chat component │ └── EmbediaChatWrapper.* # React wrapper component ├── embedia-chat-demo.html # Standalone demo └── embedia-integration-examples.js # Integration examples \`\`\` ## 🔧 Integration Steps ### 1. Environment Setup Create a \`.env\` file with your AI provider key: \`\`\` GEMINI_API_KEY=your_api_key_here # or OPENAI_API_KEY=your_api_key_here \`\`\` ### 2. Choose Your Integration Method #### Method A: Dynamic Import (Recommended for React/Vue/Angular) \`\`\`javascript import('/components/generated/embedia-chat/index.js').then((module) => { const EmbediaChat = module.default; // Render the component }); \`\`\` #### Method B: Script Tag (For vanilla JS/HTML) \`\`\`html <embedia-chatbot></embedia-chatbot> <script src="/path/to/embedia-chat.js"></script> <script> // Simplified mounting </script> \`\`\` #### Method C: Wrapper Component (For React apps) \`\`\`jsx import EmbediaChatWrapper from './components/EmbediaChatWrapper'; function App() { return ( <div> <YourContent /> <EmbediaChatWrapper /> </div> ); } \`\`\` ### 3. API Endpoint Setup The chat requires an API endpoint to communicate with your AI provider. #### For Express.js: \`\`\`javascript app.post('/api/embedia/chat', async (req, res) => { // API handler code from api/chat/route.js }); \`\`\` #### For serverless/Vercel: Copy \`components/generated/embedia-chat/api/chat/route.js\` to your API directory. ## 🎨 Customization Edit \`components/generated/embedia-chat/config.json\`: \`\`\`json { "chatbotName": "Your Bot Name", "themeColors": { "primary": "#2563EB", "background": "#FFFFFF" }, "position": "bottom-right" } \`\`\` ## 🔍 Troubleshooting ### Chat not appearing? 1. Check browser console for errors 2. Ensure React and ReactDOM are loaded 3. Verify the component path is correct 4. Check that the container element exists ### API errors? 1. Verify your API key is set correctly 2. Check network tab for failed requests 3. Ensure CORS is configured if needed ### Styling issues? 1. Check for CSS conflicts with existing styles 2. Increase z-index if chat is hidden behind elements 3. Use the wrapper component for better isolation ## 📚 Framework-Specific Notes ### React/Next.js/Gatsby - Use the provided wrapper component - Ensure React 18+ for createRoot API ### Vue.js - Load React as external dependency - Mount in mounted() lifecycle hook ### Angular - Add React types: \`npm install @types/react @types/react-dom\` - Use ngAfterViewInit for mounting ### WordPress - Enqueue React before Embedia - Use wp_add_inline_script for initialization ## 🆘 Need Help? 1. Check the demo file for a working example 2. Review framework-specific examples 3. Visit https://docs.embedia.ai 4. Run \`npx embedia doctor\` for diagnostics --- **Embedia Chat v2.0** - Universal Integration `; await this.createFile(guidePath, guide); return guidePath; } } module.exports = UniversalAdapter;