nexus-web-assistant 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kaif Ansari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # Nexus Web Assistant 🚀
2
+
3
+ **Your Intelligent AI-Powered Web Companion**
4
+
5
+ [![GitHub stars](https://img.shields.io/github/stars/thekaifansari01/NexusWebAssistant?style=for-the-badge&color=gold)](https://github.com/thekaifansari01/NexusWebAssistant/stargazers)
6
+ [![GitHub forks](https://img.shields.io/github/forks/thekaifansari01/NexusWebAssistant?style=for-the-badge&color=blue)](https://github.com/thekaifansari01/NexusWebAssistant/network)
7
+ [![GitHub issues](https://img.shields.io/github/issues/thekaifansari01/NexusWebAssistant?style=for-the-badge&color=red)](https://github.com/thekaifansari01/NexusWebAssistant/issues)
8
+ [![License](https://img.shields.io/badge/license-MIT-green?style=for-the-badge)](LICENSE)
9
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=for-the-badge)](https://github.com/thekaifansari01/NexusWebAssistant/pulls)
10
+
11
+ ---
12
+
13
+ ## 📖 Overview
14
+
15
+ **Nexus Web Assistant** is a cutting-edge, fully-featured AI chatbot widget that seamlessly integrates into any website. Powered by Groq's ultra-fast inference engine and equipped with advanced web scraping capabilities, it delivers intelligent, context-aware responses about your web content in real-time.
16
+
17
+ > ✨ **Live Demo:** [https://nexus-web-assistant.vercel.app](https://nexus-web-assistant.vercel.app)
18
+
19
+ ---
20
+
21
+ ## ✨ Key Features
22
+
23
+ ### 🤖 **Intelligent AI Chat**
24
+ - **Powered by Groq API** - Lightning-fast inference with LLaMA models
25
+ - **Context-Aware Responses** - Understands and references page content
26
+ - **Multimodal Support** - Text + Image analysis capabilities
27
+ - **Markdown Rendering** - Beautifully formatted responses with code highlighting
28
+
29
+ ### 📄 **Advanced Web Scraping**
30
+ - **Readability Integration** - Clean, distraction-free content extraction
31
+ - **Markdown Conversion** - Transforms HTML to clean Markdown
32
+ - **JSON-LD Support** - Extracts structured data (Schema.org)
33
+ - **SPA Navigation Detection** - Automatically refreshes context on page changes
34
+ - **Smart Content Detection** - Identifies page types (Blog, Product, Portfolio, etc.)
35
+
36
+ ### 💾 **Intelligent Caching**
37
+ - **IndexedDB Storage** - Unlimited local cache capacity
38
+ - **24-Hour Auto-Expiry** - Smart cache invalidation
39
+ - **Offline Support** - Persistent data across sessions
40
+ - **Cache Statistics** - Real-time cache monitoring
41
+
42
+ ### 🎨 **Premium UI/UX**
43
+ - **Glassmorphism Design** - Modern, elegant aesthetic
44
+ - **Dark Mode Optimized** - Perfect for any website
45
+ - **Responsive Layout** - Works on all screen sizes
46
+ - **Smooth Animations** - Delightful user experience
47
+ - **Typing Indicators** - Real-time feedback
48
+
49
+ ---
50
+
51
+ ## 🚀 Quick Start
52
+
53
+ ### **Option 1: Direct Integration (Recommended)**
54
+
55
+ Add this single script tag to your website:
56
+
57
+ ```html
58
+ <script defer src="https://cdn.jsdelivr.net/gh/thekaifansari01/NexusWebAssistant@main/dist/nexus-assistant.min.js"></script>
59
+ ```
60
+
61
+ ### **Option 2: Self-Hosted**
62
+
63
+ ```bash
64
+ # Clone the repository
65
+ git clone https://github.com/thekaifansari01/NexusWebAssistant.git
66
+
67
+ # Navigate to project
68
+ cd NexusWebAssistant
69
+
70
+ # Install dependencies
71
+ npm install
72
+
73
+ # Build for production
74
+ npm run build
75
+
76
+ # Include in your project
77
+ <script defer src="/path/to/dist/nexus-assistant.min.js"></script>
78
+ ```
79
+
80
+ ### **Option 3: Development**
81
+
82
+ ```bash
83
+ # Install dependencies
84
+ npm install
85
+
86
+ # Start development server
87
+ npm run dev
88
+
89
+ # Build for production
90
+ npm run build
91
+ ```
92
+
93
+ ---
94
+
95
+ ## ⚙️ Configuration
96
+
97
+ Customize the assistant by modifying `config.js`:
98
+
99
+ ```javascript
100
+ export const CONFIG = {
101
+ // API Configuration
102
+ API_URL: 'https://api.groq.com/openai/v1/chat/completions',
103
+ API_KEY: 'your-api-key-here', // 🔑 Get from console.groq.com
104
+ MODEL: 'meta-llama/llama-4-scout-17b-16e-instruct',
105
+
106
+ // Branding
107
+ BOT_NAME: "Nexus AI",
108
+ GREETING: "Hey! I'm Nexus AI, your intelligent assistant. Ask me anything about this page!",
109
+
110
+ // System Prompt
111
+ SYSTEM_PROMPT: `...`, // Customize AI behavior
112
+
113
+ // UI Colors
114
+ COLORS: {
115
+ bg: '#0a0a0a',
116
+ panelBg: 'rgba(12, 12, 12, 0.85)',
117
+ // ... customize theme
118
+ }
119
+ };
120
+ ```
121
+
122
+ ### **Required Configuration:**
123
+
124
+ 1. **Get your API Key:** [Groq Console](https://console.groq.com)
125
+ 2. **Update `API_KEY`** in `config.js`
126
+ 3. **(Optional)** Customize branding and appearance
127
+
128
+ ---
129
+
130
+ ## 📁 Project Structure
131
+
132
+ ```
133
+ NexusWebAssistant/
134
+ ├── src/
135
+ │ ├── api.js # AI API integration
136
+ │ ├── cache.js # IndexedDB caching engine
137
+ │ ├── config.js # Configuration & settings
138
+ │ ├── dom.js # DOM manipulation & rendering
139
+ │ ├── index.js # Main entry point
140
+ │ ├── scraper.js # Advanced web scraping engine
141
+ │ ├── state.js # Application state management
142
+ │ └── styles.js # Dynamic styles injection
143
+ ├── dist/ # Production build
144
+ ├── docs/ # Documentation
145
+ ├── package.json # Dependencies
146
+ ├── webpack.config.js # Build configuration
147
+ └── README.md # You are here!
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 🛠️ Technology Stack
153
+
154
+ | Technology | Purpose |
155
+ |------------|---------|
156
+ | **Groq API** | AI inference engine |
157
+ | **IndexedDB** | Client-side caching |
158
+ | **Readability** | Content extraction |
159
+ | **Turndown** | HTML → Markdown conversion |
160
+ | **Marked.js** | Markdown rendering |
161
+ | **Highlight.js** | Code syntax highlighting |
162
+ | **Font Awesome** | Icon library |
163
+ | **Webpack** | Build tool |
164
+
165
+ ---
166
+
167
+ ## 🔌 Features in Detail
168
+
169
+ ### 🧠 **Smart Context Retrieval**
170
+ The assistant automatically scrapes and caches page content, providing the AI with rich context for accurate responses.
171
+
172
+ ### 🖼️ **Image Analysis**
173
+ Users can attach images for AI-powered analysis alongside text queries.
174
+
175
+ ### 🔄 **SPA Support**
176
+ Automatically detects Single Page Application navigation and refreshes context.
177
+
178
+ ### 📊 **Structured Data Extraction**
179
+ Extracts JSON-LD, meta tags, Open Graph, and Twitter Cards for enhanced understanding.
180
+
181
+ ### 💬 **Conversation History**
182
+ Maintains context across multiple messages for natural conversations.
183
+
184
+ ---
185
+
186
+ ## 📊 Performance
187
+
188
+ - **Cache Hit Rate:** >90% for repeat visits
189
+ - **Average Response Time:** <1.5s (Groq optimized)
190
+ - **Bundle Size:** ~45KB (gzipped)
191
+ - **Memory Usage:** <30MB
192
+ - **Compatibility:** All modern browsers (Chrome 90+, Firefox 88+, Safari 14+)
193
+
194
+ ---
195
+
196
+ ## 🤝 Contributing
197
+
198
+ We welcome contributions! Here's how you can help:
199
+
200
+ ### 🐛 **Report Bugs**
201
+ [Open an Issue](https://github.com/thekaifansari01/NexusWebAssistant/issues)
202
+
203
+ ### 💡 **Feature Requests**
204
+ [Submit a Feature Request](https://github.com/thekaifansari01/NexusWebAssistant/issues/new?labels=enhancement)
205
+
206
+ ### 🔧 **Development**
207
+
208
+ ```bash
209
+ # Fork the repository
210
+ # Clone your fork
211
+ git clone https://github.com/YOUR_USERNAME/NexusWebAssistant.git
212
+
213
+ # Create a feature branch
214
+ git checkout -b feature/amazing-feature
215
+
216
+ # Make your changes
217
+ # Commit and push
218
+ git push origin feature/amazing-feature
219
+
220
+ # Open a Pull Request
221
+ ```
222
+
223
+ ### 📝 **Guidelines**
224
+ - Follow existing code style
225
+ - Write meaningful commit messages
226
+ - Update documentation
227
+ - Add tests where applicable
228
+
229
+ ---
230
+
231
+ ## 📄 License
232
+
233
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
234
+
235
+ ---
236
+
237
+ ## 🏆 Acknowledgments
238
+
239
+ - **Groq** for their incredible AI inference engine
240
+ - **Mozilla** for Readability library
241
+ - **Open Source Community** for all the amazing tools
242
+
243
+ ---
244
+
245
+ ## 📞 Contact & Support
246
+
247
+ - **Author:** [Kaif Ansari](https://github.com/thekaifansari01)
248
+ - **Issues:** [GitHub Issues](https://github.com/thekaifansari01/NexusWebAssistant/issues)
249
+ - **Email:** contact@kaifansari.com
250
+
251
+ ---
252
+
253
+ ## ⭐ Show Your Support
254
+
255
+ If you find this project useful, please consider:
256
+ - ⭐ Starring the repository
257
+ - 🍴 Forking the project
258
+ - 🐦 Sharing on social media
259
+ - 🧑‍💻 Contributing to the codebase
260
+
261
+ ---
262
+
263
+ **Built with ❤️ by [Kaif Ansari](https://github.com/thekaifansari01)**
264
+
265
+ [⬆ Back to Top](#nexus-web-assistant-)
@@ -0,0 +1 @@
1
+ (()=>{"use strict";const n="https://api.groq.com/openai/v1/chat/completions",e="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",t="meta-llama/llama-4-scout-17b-16e-instruct",o="Nexus AI",a="Hey! I'm Nexus AI, your intelligent assistant. Ask me anything about Website!",i="\nYou are Nexus AI, a smart assistant. Use the page context provided in every response.\n\n**Rules:**\n- Always prioritize the given page context over general knowledge.\n- Quote specific details (headings, tables, code, lists, etc.) from the context.\n- Structure answers clearly with bullet points or headings where helpful.\n- Be crisp, professional, and friendly. Use Markdown.\n- If information is not in context, politely say so and offer to help with related topics.\n- Keep responses concise (under 600 tokens).\n ",r={bg:"#0a0a0a",panelBg:"rgba(12, 12, 12, 0.85)",border:"#2a2a2a",borderHover:"#444444",textPrimary:"#f5f5f5",textSecondary:"#a0a0a0",userBubble:"#1e1e1e",botBubble:"transparent"},s=n=>document.getElementById(n);function c(n,e){if(!n)return!1;const t=void 0!==e?e:!n.classList.contains("open");return n.classList.toggle("open",t),t&&setTimeout(()=>s("aiInput")?.focus(),100),t}function l(n,e,t="bot",o=null){if(!n)return null;const a=document.createElement("div");if(a.className=`msg ${t}`,"bot"===t){const n=function(n){return"undefined"!=typeof marked&&marked.parse?marked.parse(n,{breaks:!0,gfm:!0}):n.replace(/\n/g,"<br>")}(e);a.innerHTML=n,"undefined"!=typeof hljs&&a.querySelectorAll("pre code").forEach(n=>{hljs.highlightElement(n)})}else{let n=e||"";o&&(n+=`<br><img src="${o}" class="image-preview" alt="attached">`),a.innerHTML=n}return n.appendChild(a),n.scrollTo({top:n.scrollHeight,behavior:"smooth"}),a}let d=null;function p(n,e){n&&(d&&(d.remove(),d=null),e&&(d=document.createElement("div"),d.className="typing-indicator",d.innerHTML="<span></span><span></span><span></span>",n.appendChild(d),n.scrollTo({top:n.scrollHeight,behavior:"smooth"})))}function u(n,e){if(!n)return;if(n.innerHTML="",!e)return;const t=document.createElement("div");t.className="image-preview-pill",t.innerHTML=`\n <img src="${e.dataUrl}" alt="preview">\n <span class="file-name">${e.name}</span>\n <button class="remove-file" id="aiRemoveFile"><i class="fas fa-times"></i></button>\n `,n.appendChild(t),document.getElementById("aiRemoveFile")?.addEventListener("click",()=>{})}const m={isOpen:!1,isProcessing:!1,attachedFile:null,conversationHistory:[]};function g(n){Object.assign(m,n)}const f="NexusAICache",b="pageData";let h=null;function x(){return new Promise((n,e)=>{if(h)return void n(h);const t=indexedDB.open(f,1);t.onupgradeneeded=n=>{const e=n.target.result;if(!e.objectStoreNames.contains(b)){const n=e.createObjectStore(b,{keyPath:"id"});n.createIndex("url","url",{unique:!1}),n.createIndex("timestamp","timestamp",{unique:!1}),console.log("📦 IndexedDB store created")}},t.onsuccess=e=>{h=e.target.result,n(h)},t.onerror=n=>{e(n.target.error)}})}async function y(n){try{const e=(await x()).transaction(b,"readwrite").objectStore(b),t=window.location.href,o={id:t,url:t,data:n,timestamp:Date.now()};return new Promise((n,t)=>{const a=e.put(o);a.onsuccess=()=>{console.log("💾 Data cached in IndexedDB"),n()},a.onerror=n=>{t(n.target.error)}})}catch(n){console.warn("IndexedDB write failed:",n)}}let w=null,v=null;function k(n){return new Promise((e,t)=>{const o=document.createElement("script");o.src=n,o.async=!0,o.onload=e,o.onerror=t,document.head.appendChild(o)})}function S(){console.log("🕷️ Advanced scraping started...");const n={title:document.title,url:window.location.href,timestamp:(new Date).toISOString(),pageType:E(),readability:null,structuredData:[],markdown:"",summary:"",metadata:{}};try{if(w){const e=document.cloneNode(!0),t=new w(e).parse();if(t){if(n.readability={title:t.title,byline:t.byline,excerpt:t.excerpt,content:t.content,textContent:t.textContent},v){const e=new v({headingStyle:"atx",codeBlockStyle:"fenced",emDelimiter:"*",bulletListMarker:"-"});e.addRule("strikethrough",{filter:["del","s","strike"],replacement:function(n){return"~~"+n+"~~"}}),n.markdown=e.turndown(t.content)}n.summary=t.excerpt||t.textContent.substring(0,300)}}}catch(e){console.warn("Readability failed, falling back to basic scraper:",e),n.readability=null}try{document.querySelectorAll('script[type="application/ld+json"]').forEach(e=>{try{const t=JSON.parse(e.textContent);n.structuredData.push(t)}catch(n){}})}catch(n){console.warn("JSON-LD extraction failed:",n)}if(n.metadata=function(){const n={},e=document.querySelector('meta[name="description"]');e&&(n.description=e.content);const t=document.querySelector('meta[name="keywords"]');t&&(n.keywords=t.content),["title","description","image","url","type","site_name"].forEach(e=>{const t=document.querySelector(`meta[property="og:${e}"]`);t&&(n[`og_${e}`]=t.content)}),["card","title","description","image"].forEach(e=>{const t=document.querySelector(`meta[name="twitter:${e}"]`);t&&(n[`twitter_${e}`]=t.content)});const o=document.querySelector('link[rel="canonical"]');return o&&(n.canonical=o.href),n}(),!n.readability){console.log("⚠️ Using fallback scraper");const e=function(){const n=document.body.cloneNode(!0);["nav","header","footer","aside",".sidebar",".navigation",".menu",".ads",".cookie-banner",".popup",".overlay","script","style","noscript","iframe"].forEach(e=>{n.querySelectorAll(e).forEach(n=>n.remove())});let e=n.textContent||"";e=e.replace(/\s+/g," ").trim();const t=e.substring(0,500)+"...";return{content:e,summary:t}}();n.markdown=e.content,n.summary=e.summary}return n.aiContext=$(n),console.log("✅ Advanced scraping complete"),n}function E(){const n=window.location.href,e=document.title.toLowerCase(),t=document.querySelector('meta[property="og:type"]');if(t){const n=t.content;if(n.includes("article"))return"article";if(n.includes("product"))return"product";if(n.includes("website"))return"website"}return n.includes("/blog/")||n.includes("/post/")||e.includes("blog")?"blog":n.includes("/product/")||n.includes("/shop/")?"product":n.includes("/portfolio/")||n.includes("/project/")?"portfolio":n===window.location.origin+"/"||n===window.location.origin?"homepage":"general"}function $(n){let e="";if(e+=`# 📄 ${n.title}\n\n`,e+=`**URL:** ${n.url}\n`,e+=`**Type:** ${n.pageType}\n`,e+=`**Scraped:** ${new Date(n.timestamp).toLocaleString()}\n\n`,Object.keys(n.metadata).length>0){e+="## 📋 Metadata\n";for(const[t,o]of Object.entries(n.metadata))o&&o.length>0&&(e+=`- **${t}:** ${o}\n`);e+="\n"}if(n.structuredData&&n.structuredData.length>0&&(e+="## 📊 Structured Data (Schema.org)\n",n.structuredData.forEach((n,t)=>{e+=`\n### Schema ${t+1}\n`,e+=`\`\`\`json\n${JSON.stringify(n,null,2)}\n\`\`\`\n`}),e+="\n"),n.markdown){e+="## 📝 Main Content\n\n";const t=4e3,o=n.markdown.length>t?n.markdown.substring(0,t)+"... (truncated)":n.markdown;e+=o,e+="\n\n"}return n.summary&&(e+="## 📌 Summary\n\n",e+=n.summary,e+="\n\n"),e+="---\n",e+="*🤖 AI Instructions: Use this context to answer user questions about this page. Be precise, reference specific details from the content, and maintain a friendly professional tone.*\n",e}async function I(o,a,r=null){if(m.isProcessing)return;g({isProcessing:!0});const s=document.getElementById("aiSendBtn"),c=document.getElementById("aiInput");s&&(s.disabled=!0),c&&(c.disabled=!0),p(o,!0);const d=[];if(a&&d.push({type:"text",text:a}),r&&d.push({type:"image_url",image_url:{url:r}}),m.conversationHistory.push({role:"user",content:a||"(image)"}),m.conversationHistory.length>11){const n=m.conversationHistory[0],e=m.conversationHistory.slice(-10);m.conversationHistory=[n,...e]}try{const a=await async function(){let n=await async function(){try{const n=(await x()).transaction(b,"readonly").objectStore(b),e=window.location.href;return new Promise((t,o)=>{const a=n.get(e);a.onsuccess=n=>{const o=n.target.result;if(!o)return void t(null);const a=Date.now();if(a-o.timestamp>864e5)return async function(n){try{(await x()).transaction(b,"readwrite").objectStore(b).delete(n)}catch(n){console.warn("IndexedDB delete failed:",n)}}(e),void t(null);console.log(`📦 Cache hit! Age: ${Math.floor((a-o.timestamp)/6e4)} minutes`),t(o.data)},a.onerror=n=>{o(n.target.error)}})}catch(n){return console.warn("IndexedDB read failed:",n),null}}();if(n)return console.log("📦 Using cached page data"),n;console.log("🔍 Scraping page data...");const e=$(S());return await y(e),console.log("💾 Page data cached"),e}(),r=[{role:"system",content:`${i}\n\n## Current Page Context\n${a}`}];for(let n=1;n<m.conversationHistory.length-1;n++)r.push({role:m.conversationHistory[n].role,content:m.conversationHistory[n].content});r.push({role:"user",content:d});const s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:t,messages:r,temperature:.7,max_tokens:600,stream:!1})});if(!s.ok){const n=await s.json().catch(()=>({}));throw new Error(`API error ${s.status}: ${n.error?.message||s.statusText}`)}const c=await s.json(),u=c.choices?.[0]?.message?.content||"Sorry, I didn't understand that.";m.conversationHistory.push({role:"assistant",content:u}),p(o,!1),l(o,u,"bot")}catch(n){console.error("Groq API Error:",n),p(o,!1),l(o,`⚠️ Oops! ${n.message||"Something went wrong."} Please try again.`,"bot")}finally{g({isProcessing:!1}),s&&(s.disabled=!1),c&&(c.disabled=!1,c.value="",c.focus())}}async function P(){await async function(){const n=document.createElement("link");n.href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css",n.rel="stylesheet",document.head.appendChild(n);const e=document.createElement("link");e.href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap",e.rel="stylesheet",document.head.appendChild(e);const t=document.createElement("script");t.src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js",t.async=!0,document.head.appendChild(t);const o=document.createElement("link");o.href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css",o.rel="stylesheet",document.head.appendChild(o);const a=document.createElement("script");a.src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js",a.async=!0,document.head.appendChild(a),await async function(){await Promise.all([k("https://cdnjs.cloudflare.com/ajax/libs/readability/0.4.4/Readability.min.js"),k("https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.2/turndown.min.js")]),w=window.Readability,v=window.TurndownService,console.log("📚 Scraper libraries loaded")}()}(),function(){const n=document.createElement("style");n.id="ai-chat-widget-styles",n.textContent=`\n @keyframes slideUpFade {\n 0% { opacity: 0; transform: translateY(16px); }\n 100% { opacity: 1; transform: translateY(0); }\n }\n @keyframes pulseDot {\n 0%, 100% { transform: scale(0.8); opacity: 0.5; }\n 50% { transform: scale(1.2); opacity: 1; }\n }\n @keyframes typing {\n 0%, 80%, 100% { opacity: 0.3; }\n 40% { opacity: 1; }\n }\n\n #ai-widget-root {\n all: initial;\n font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 999999;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n pointer-events: none;\n }\n #ai-widget-root * { box-sizing: border-box; pointer-events: auto; }\n\n /* ===== FIX: Font Awesome icons ===== */\n #ai-widget-root .fas,\n #ai-widget-root .far,\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Free', 'Font Awesome 6 Brands' !important;\n font-weight: 900 !important; /* solid icons use 900 */\n font-style: normal;\n font-variant: normal;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n }\n #ai-widget-root .far {\n font-weight: 400 !important; /* regular */\n }\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Brands' !important;\n font-weight: 400 !important;\n }\n\n /* ===== FLOATING ORB (FAB) ===== */\n .ai-fab {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: #ffffff;\n border: 1px solid rgba(255,255,255,0.1);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #000000;\n transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1),\n transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),\n box-shadow 0.25s ease;\n user-select: none;\n box-shadow: 0 8px 24px rgba(0,0,0,0.4);\n position: relative;\n z-index: 10;\n will-change: transform, opacity;\n }\n .ai-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 12px 32px rgba(0,0,0,0.5);\n }\n .ai-fab .bot-icon i {\n color: #000000 !important;\n font-size: 24px !important;\n }\n\n /* Hide FAB when panel is open – smooth fade + scale */\n .ai-panel.open ~ .ai-fab {\n opacity: 0;\n transform: scale(0.8);\n pointer-events: none;\n }\n\n /* ===== CHAT PANEL ===== */\n .ai-panel {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 400px;\n max-width: calc(100vw - 48px);\n height: 600px;\n max-height: calc(100vh - 48px);\n background: ${r.panelBg};\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border-radius: 20px;\n box-shadow: 0 24px 80px rgba(0,0,0,0.5), 0 0 0 1px ${r.border};\n display: flex;\n flex-direction: column;\n overflow: hidden;\n opacity: 0;\n visibility: hidden;\n transform: translateY(20px);\n transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.3s;\n }\n .ai-panel.open {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n /* ===== HEADER ===== */\n .ai-header {\n padding: 20px 24px;\n border-bottom: 1px solid ${r.border};\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n background: transparent;\n }\n .ai-header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n color: ${r.textPrimary};\n font-weight: 600;\n font-size: 16px;\n }\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #10B981;\n box-shadow: 0 0 8px rgba(16, 185, 129, 0.5);\n }\n .ai-close-btn {\n background: transparent;\n border: none;\n color: ${r.textSecondary};\n font-size: 20px;\n cursor: pointer;\n transition: color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .ai-close-btn:hover {\n color: ${r.textPrimary};\n }\n\n /* ===== MESSAGES ===== */\n .ai-messages {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 24px;\n scroll-behavior: smooth;\n }\n .ai-messages::-webkit-scrollbar { width: 6px; }\n .ai-messages::-webkit-scrollbar-track { background: transparent; }\n .ai-messages::-webkit-scrollbar-thumb {\n background: ${r.border};\n border-radius: 10px;\n }\n\n /* ===== BUBBLES ===== */\n .msg {\n max-width: 85%;\n font-size: 14.5px;\n line-height: 1.6;\n word-break: break-word;\n animation: slideUpFade 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n color: ${r.textPrimary};\n }\n .msg.user {\n align-self: flex-end;\n background: ${r.userBubble};\n padding: 12px 18px;\n border-radius: 16px;\n border-bottom-right-radius: 4px;\n border: 1px solid ${r.border};\n }\n .msg.bot {\n align-self: flex-start;\n background: ${r.botBubble};\n max-width: 95%;\n }\n .msg.bot .bot-label {\n font-size: 12px;\n color: ${r.textSecondary};\n margin-bottom: 6px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .msg .image-preview {\n max-width: 200px;\n border-radius: 12px;\n margin-top: 8px;\n border: 1px solid ${r.border};\n }\n .msg.user .image-preview { max-width: 100%; }\n\n /* Markdown Cleanup */\n .msg.bot p { margin: 0 0 12px 0; }\n .msg.bot p:last-child { margin-bottom: 0; }\n .msg.bot code {\n background: #1e1e1e;\n padding: 2px 6px;\n border-radius: 4px;\n font-family: ui-monospace, monospace;\n font-size: 0.9em;\n border: 1px solid ${r.border};\n }\n .msg.bot pre {\n background: #111111;\n padding: 16px;\n border-radius: 12px;\n overflow-x: auto;\n margin: 12px 0;\n border: 1px solid ${r.border};\n }\n .msg.bot pre code { background: transparent; padding: 0; border: none; }\n .msg.bot ul, .msg.bot ol { margin: 8px 0 12px 20px; padding-left: 0; }\n .msg.bot li { margin-bottom: 6px; }\n .msg.bot a { color: #fff; text-decoration: underline; text-underline-offset: 4px; }\n\n /* ===== INPUT AREA ===== */\n .ai-input-area {\n padding: 16px 24px 24px;\n background: transparent;\n flex-shrink: 0;\n }\n .ai-input-container {\n display: flex;\n align-items: center;\n background: #161616;\n border: 1px solid ${r.border};\n border-radius: 24px;\n padding: 6px 6px 6px 16px;\n transition: border-color 0.2s, background 0.2s;\n }\n .ai-input-container:focus-within {\n border-color: #555;\n background: #1a1a1a;\n }\n .ai-input-container input {\n flex: 1;\n background: transparent;\n border: none;\n color: ${r.textPrimary};\n font-size: 14px;\n outline: none;\n font-family: inherit;\n padding: 8px 0;\n }\n .ai-input-container input::placeholder {\n color: ${r.textSecondary};\n }\n .icon-btn {\n background: transparent;\n border: none;\n color: ${r.textSecondary};\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: color 0.2s, background 0.2s;\n }\n .icon-btn:hover {\n color: #fff;\n background: ${r.borderHover};\n }\n .send-btn {\n background: #fff;\n color: #000;\n margin-left: 4px;\n }\n .send-btn:hover {\n background: #e0e0e0;\n color: #000;\n }\n .send-btn:disabled {\n background: #333;\n color: #666;\n cursor: not-allowed;\n }\n\n /* ===== PREVIEW PILL ===== */\n #aiPreviewContainer { margin-bottom: 12px; }\n .image-preview-pill {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n background: #1e1e1e;\n border: 1px solid ${r.border};\n border-radius: 8px;\n padding: 6px 12px 6px 6px;\n animation: slideUpFade 0.3s ease forwards;\n }\n .image-preview-pill img {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n object-fit: cover;\n }\n .image-preview-pill .file-name {\n font-size: 12px;\n color: ${r.textPrimary};\n max-width: 120px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .image-preview-pill .remove-file {\n background: none;\n border: none;\n color: ${r.textSecondary};\n cursor: pointer;\n font-size: 14px;\n display: flex;\n align-items: center;\n }\n .image-preview-pill .remove-file:hover { color: #fff; }\n\n /* ===== TYPING INDICATOR ===== */\n .typing-indicator {\n display: flex;\n gap: 4px;\n padding: 8px 0;\n align-self: flex-start;\n }\n .typing-indicator span {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: ${r.textSecondary};\n animation: typing 1.4s infinite;\n }\n .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }\n .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }\n\n /* ===== RESPONSIVE ===== */\n @media (max-width: 480px) {\n .ai-panel {\n width: calc(100vw - 32px);\n right: 16px;\n height: 80vh;\n max-height: calc(100vh - 48px);\n }\n .ai-fab {\n width: 50px;\n height: 50px;\n }\n .ai-fab .bot-icon { font-size: 20px; }\n }\n `,document.head.appendChild(n)}(),function(){const n=document.createElement("div");n.id="ai-widget-root",n.innerHTML=`\n <div class="ai-panel" id="aiPanel">\n <div class="ai-header">\n <div class="ai-header-title">\n <span class="status-dot"></span>\n ${o}\n </div>\n <button class="ai-close-btn" id="aiCloseBtn" aria-label="Close chat">\n <i class="fas fa-xmark"></i>\n </button>\n </div>\n <div class="ai-messages" id="aiMessages">\n <div class="msg bot">\n ${a}\n </div>\n </div>\n <div class="ai-input-area" id="aiInputArea">\n <div id="aiPreviewContainer"></div>\n <div class="ai-input-container">\n <button class="icon-btn" id="aiAttachBtn" aria-label="Attach image">\n <i class="fas fa-paperclip"></i>\n </button>\n <input type="text" id="aiInput" placeholder="Message..." autocomplete="off">\n <button class="icon-btn send-btn" id="aiSendBtn">\n <i class="fas fa-arrow-up"></i>\n </button>\n </div>\n </div>\n </div>\n <button class="ai-fab" id="aiFab" aria-label="Open AI Chat">\n <span class="bot-icon">\n <i class="fas fa-robot" style="color: #000000 !important; font-size: 22px;"></i>\n </span>\n </button>\n `,document.body.appendChild(n)}();const n=s("aiPanel"),e=s("aiMessages"),t=s("aiFab"),i=s("aiCloseBtn"),d=s("aiSendBtn"),p=s("aiInput"),h=s("aiAttachBtn"),E=s("aiPreviewContainer");!function(n){let e=window.location.href;new MutationObserver(()=>{window.location.href!==e&&(e=window.location.href,console.log("🔄 Page navigation detected"),n())}).observe(document,{subtree:!0,childList:!0});const t=history.pushState;history.pushState=function(){t.apply(this,arguments),setTimeout(()=>{window.location.href!==e&&(e=window.location.href,n())},500)}}(()=>{console.log("🔄 Page changed, refreshing context..."),async function(){console.log("🔄 Forcing page context refresh...");const n=$(S());await y(n),console.log("✅ Page context refreshed")}(),l(e,"🔄 Page context updated!","bot")});const P=document.createElement("input");P.type="file",P.accept="image/*",P.style.display="none",P.id="aiFileInput",document.body.appendChild(P),h?.addEventListener("click",()=>P.click()),P.addEventListener("change",n=>{const e=n.target.files?.[0];if(!e)return;if(!e.type.startsWith("image/"))return void alert("Please select an image file.");const t=new FileReader;t.onload=n=>{const t={dataUrl:n.target.result,name:e.name,type:e.type};g({attachedFile:t}),u(E,t);const o=document.getElementById("aiRemoveFile");o&&o.addEventListener("click",()=>{g({attachedFile:null}),u(E,null),p?.focus()}),p?.focus()},t.readAsDataURL(e),n.target.value=""}),t?.addEventListener("click",()=>{g({isOpen:c(n,!0)})}),i?.addEventListener("click",()=>{g({isOpen:c(n,!1)})}),document.addEventListener("click",e=>{const t=document.getElementById("ai-widget-root");t&&m.isOpen&&!t.contains(e.target)&&g({isOpen:c(n,!1)})});const j=()=>{const n=p?.value.trim();if(!n&&!m.attachedFile)return;if(m.isProcessing)return;const t=m.attachedFile?.dataUrl||null;l(e,n,"user",t),p.value="",u(E,null);const o=m.attachedFile?.dataUrl||null;g({attachedFile:null}),I(e,n,o)};d?.addEventListener("click",j),p?.addEventListener("keydown",n=>{"Enter"!==n.key||n.shiftKey||(n.preventDefault(),j())});const B=await async function(){try{const n=(await x()).transaction(b,"readonly").objectStore(b);return new Promise(e=>{const t=n.count();t.onsuccess=()=>{e({totalEntries:t.result,database:f,version:1})},t.onerror=()=>e(null)})}catch{return null}}();console.log("📊 Cache Stats:",B||"No cache yet"),console.log("✨ Nexus AI v2.0 initialized with advanced scraper!")}m.conversationHistory=[{role:"system",content:i}],"loading"===document.readyState?document.addEventListener("DOMContentLoaded",P):P()})();
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "nexus-web-assistant",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered chatbot widget for any website",
5
+ "main": "dist/nexus-assistant.min.js",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "scripts": {
10
+ "build": "webpack --mode production",
11
+ "prepublishOnly": "npm run build"
12
+ },
13
+ "keywords": [
14
+ "ai",
15
+ "chatbot",
16
+ "assistant",
17
+ "widget"
18
+ ],
19
+ "author": "Kaif Ansari",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/thekaifansari01/NexusWebAssistant.git"
24
+ },
25
+ "devDependencies": {
26
+ "webpack": "^5.108.1",
27
+ "webpack-cli": "^7.1.0"
28
+ }
29
+ }