rag-chatbot-widget-alpha 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/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # đŸ€– RAG Chatbot Widget
2
+
3
+ Widget chatbot intelligent alimenté par IA pour vos sites web. Installation en 2 minutes avec React, Vue, Angular ou HTML pur.
4
+
5
+ ## 📩 Installation
6
+
7
+ ```bash
8
+ npm install @webidea/rag-chatbot-widget
9
+ ```
10
+
11
+ ## 🔑 Obtenir une clĂ© API
12
+
13
+ **Ce widget nécessite une clé API.**
14
+ Contactez WebIdea pour obtenir votre clé : contact@webidea.fr
15
+
16
+ ## 🚀 Utilisation rapide
17
+
18
+ ### Avec React
19
+
20
+ ```jsx
21
+ import { useEffect } from 'react';
22
+ import { init, destroy } from '@webidea/rag-chatbot-widget';
23
+ import '@webidea/rag-chatbot-widget/styles.css';
24
+
25
+ function App() {
26
+ useEffect(() => {
27
+ init({
28
+ apiKey: 'sk_your_api_key_here', // ← ClĂ© fournie par WebIdea
29
+ primaryColor: '#2CB3FF',
30
+ title: 'Assistant',
31
+ subtitle: 'Comment puis-je vous aider ?'
32
+ });
33
+
34
+ return () => destroy(); // Cleanup
35
+ }, []);
36
+
37
+ return <div>Mon application</div>;
38
+ }
39
+ ```
40
+
41
+ ### Avec Vue 3
42
+
43
+ ```vue
44
+ <script setup>
45
+ import { onMounted, onUnmounted } from 'vue';
46
+ import { init, destroy } from '@webidea/rag-chatbot-widget';
47
+ import '@webidea/rag-chatbot-widget/styles.css';
48
+
49
+ onMounted(() => {
50
+ init({
51
+ apiKey: 'sk_your_api_key_here', // ← ClĂ© fournie par WebIdea
52
+ primaryColor: '#2CB3FF'
53
+ });
54
+ });
55
+
56
+ onUnmounted(() => destroy());
57
+ </script>
58
+
59
+ <template>
60
+ <div>Mon application</div>
61
+ </template>
62
+ ```
63
+
64
+ ### Avec HTML classique (via unpkg CDN)
65
+
66
+ ```html
67
+ <!DOCTYPE html>
68
+ <html>
69
+ <head>
70
+ <link rel="stylesheet" href="https://unpkg.com/@webidea/rag-chatbot-widget@1.0.0/dist/style.css">
71
+ </head>
72
+ <body>
73
+ <h1>Mon site web</h1>
74
+
75
+ <script src="https://unpkg.com/@webidea/rag-chatbot-widget@1.0.0/dist/index.umd.js"></script>
76
+ <script>
77
+ RAGChatbot.init({
78
+ apiKey: 'sk_your_api_key_here', // ← ClĂ© fournie par WebIdea
79
+ primaryColor: '#2CB3FF',
80
+ title: 'Assistant',
81
+ subtitle: 'Posez vos questions'
82
+ });
83
+ </script>
84
+ </body>
85
+ </html>
86
+ ```
87
+
88
+ ## ⚙ Configuration
89
+
90
+ | Option | Type | Default | Description |
91
+ |--------|------|---------|-------------|
92
+ | `apiKey` | `string` | **Required** | Clé API fournie par WebIdea |
93
+ | `sessionId` | `string` | Auto-généré | ID de session unique du visiteur |
94
+ | `position` | `string` | `'bottom-right'` | Position : `'bottom-right'` ou `'bottom-left'` |
95
+ | `primaryColor` | `string` | `'#2CB3FF'` | Couleur principale du chatbot |
96
+ | `title` | `string` | `'Assistant'` | Titre du chatbot |
97
+ | `subtitle` | `string` | `'Comment puis-je vous aider ?'` | Sous-titre |
98
+ | `logoUrl` | `string` | `null` | URL du logo (optionnel) |
99
+
100
+ ## 🔒 SĂ©curitĂ©
101
+
102
+ - Ne partagez jamais votre clé API publiquement
103
+ - Stockez-la dans vos variables d'environnement :
104
+
105
+ ```env
106
+ # .env.local
107
+ VITE_CHATBOT_API_KEY=sk_your_api_key_here
108
+ ```
109
+
110
+ ```javascript
111
+ // Dans votre code
112
+ init({ apiKey: import.meta.env.VITE_CHATBOT_API_KEY });
113
+ ```
114
+
115
+ ## 🎹 Exemples de personnalisation
116
+
117
+ ### Style professionnel (Bleu)
118
+
119
+ ```javascript
120
+ init({
121
+ apiUrl: 'https://api.example.com',
122
+ primaryColor: '#1e40af',
123
+ title: 'Service Client',
124
+ subtitle: 'En quoi puis-je vous aider ?',
125
+ position: 'bottom-right'
126
+ });
127
+ ```
128
+
129
+ ### Style moderne (Violet)
130
+
131
+ ```javascript
132
+ init({
133
+ apiUrl: 'https://api.example.com',
134
+ primaryColor: '#8b5cf6',
135
+ title: 'Assistant IA',
136
+ subtitle: 'Posez-moi vos questions',
137
+ position: 'bottom-left'
138
+ });
139
+ ```
140
+
141
+ ### Avec logo personnalisé
142
+
143
+ ```javascript
144
+ init({
145
+ apiUrl: 'https://api.example.com',
146
+ primaryColor: '#10b981',
147
+ logoUrl: 'https://example.com/logo.svg'
148
+ });
149
+ ```
150
+
151
+ ## 🔧 API
152
+
153
+ ### `init(config)`
154
+
155
+ Initialise et affiche le widget chatbot.
156
+
157
+ **ParamĂštres :**
158
+ - `config` (Object) : Options de configuration
159
+
160
+ **Exemple :**
161
+ ```javascript
162
+ import { init } from '@webidea/rag-chatbot-widget';
163
+
164
+ init({
165
+ apiUrl: 'https://api.example.com',
166
+ primaryColor: '#2CB3FF'
167
+ });
168
+ ```
169
+
170
+ ### `destroy()`
171
+
172
+ Supprime le widget du DOM (utile pour cleanup dans React/Vue).
173
+
174
+ **Exemple :**
175
+ ```javascript
176
+ import { destroy } from '@webidea/rag-chatbot-widget';
177
+
178
+ destroy();
179
+ ```
180
+
181
+ ## đŸ“± CompatibilitĂ©
182
+
183
+ - ✅ React 16.8+
184
+ - ✅ Vue 3
185
+ - ✅ Angular 12+
186
+ - ✅ Vanilla JavaScript
187
+ - ✅ Next.js
188
+ - ✅ Nuxt.js
189
+ - ✅ Tous les navigateurs modernes
190
+
191
+ ## đŸ› ïž DĂ©veloppement local
192
+
193
+ ### Test avec npm link
194
+
195
+ ```bash
196
+ # Dans le dossier du package
197
+ npm run build
198
+ npm link
199
+
200
+ # Dans votre projet de test
201
+ npm link @webidea/rag-chatbot-widget
202
+ ```
203
+
204
+ ## 📄 Licence
205
+
206
+ MIT
207
+
208
+ ## 📧 Support
209
+
210
+ Pour toute question ou problĂšme, ouvrez une issue sur GitHub.
@@ -0,0 +1,41 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=()=>typeof crypto<"u"&&crypto.randomUUID?"visitor_"+crypto.randomUUID():"visitor_"+Date.now()+"_"+Math.random().toString(36).substr(2,9);let o={apiUrl:"https://backend-production-e9c35.up.railway.app",apiKey:null,sessionId:j(),collectionId:"default",position:"bottom-right",primaryColor:"#2CB3FF",title:"Assistant",subtitle:"Comment puis-je vous aider ?",logoUrl:null,logoSVG:null},m=!1,r=null,p=null,h=null,C=0;const B=2e3;function q(){const e=o.position==="bottom-left"?"rag-chatbot-left":"rag-chatbot-right";return`
2
+ <!-- Bouton flottant -->
3
+ <div id="rag-chatbot-button" class="${e}">
4
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
5
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
6
+ </svg>
7
+ </div>
8
+
9
+ <!-- FenĂȘtre de chat -->
10
+ <div id="rag-chatbot-window" class="rag-chatbot-window ${e}" style="display: none;">
11
+ <!-- Header -->
12
+ <div class="rag-chatbot-header">
13
+ <div style="display: flex; align-items: center; height: 24px;">
14
+ ${o.logoSVG?o.logoSVG:o.logoUrl?`<img src="${o.logoUrl}" alt="Logo" style="height: 24px; width: auto;">`:""}
15
+ </div>
16
+ <button id="rag-chatbot-close">
17
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
18
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
19
+ </svg>
20
+ </button>
21
+ </div>
22
+
23
+ <!-- Messages -->
24
+ <div id="rag-chatbot-messages" class="rag-chatbot-messages">
25
+ <div class="rag-message rag-bot-message">
26
+ <p>Bonjour, je suis Eliott. Comment puis-je vous aider ?</p>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Input -->
31
+ <div class="rag-chatbot-input">
32
+ <input type="text" id="rag-chatbot-input" placeholder="Posez votre question...">
33
+ <button id="rag-chatbot-send">
34
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
35
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
36
+ </svg>
37
+ </button>
38
+ </div>
39
+ </div>
40
+ `}function x(){r=document.createElement("div"),r.id="rag-chatbot-container",r.innerHTML=q(),document.body.appendChild(r),document.documentElement.style.setProperty("--rag-primary-color",o.primaryColor),U()}function U(){document.getElementById("rag-chatbot-button").addEventListener("click",T),document.getElementById("rag-chatbot-close").addEventListener("click",T),document.getElementById("rag-chatbot-send").addEventListener("click",M),document.getElementById("rag-chatbot-input").addEventListener("keypress",e=>{e.key==="Enter"&&M()})}function T(){m=!m;const e=document.getElementById("rag-chatbot-window"),t=document.getElementById("rag-chatbot-button");m?(e.style.display="flex",t.style.display="none"):(e.style.display="none",t.style.display="flex")}async function M(){var f,b;const e=document.getElementById("rag-chatbot-input"),t=e.value.trim();if(!t)return;const s=500;if(t.length>s){const u=v(`⚠ Votre question est trop longue (${t.length} caractĂšres). Limite : ${s} caractĂšres.`,"bot");setTimeout(()=>u.remove(),5e3);return}const i=Date.now();if(i-C<B)return;C=i,v(t,"user"),e.value="";const n=v("","bot",!0),a=n.querySelector("p");try{const u=await $(),l=await fetch(`${o.apiUrl}/ask`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify({question:t,session_id:o.sessionId,collection_id:o.collectionId})});if(!l.ok){if(l.status===400){const d=await l.json();if(((f=d.detail)==null?void 0:f.error)==="inappropriate_content"){a.textContent="⚠ "+d.detail.message;const c=n.querySelector(".rag-typing-indicator");c&&c.remove();return}if(((b=d.detail)==null?void 0:b.error)==="guardrails_violation"){a.textContent="đŸ›Ąïž "+d.detail.message;const c=n.querySelector(".rag-typing-indicator");c&&c.remove();return}}throw new Error("Erreur rĂ©seau")}const S=l.body.getReader(),_=new TextDecoder;let w=!1,k=!1;for(;;){const{value:d,done:c}=await S.read();if(c)break;const L=_.decode(d).split(`
41
+ `).filter(y=>y.trim());for(const y of L)try{const g=JSON.parse(y);if(g.type==="content"){if(!k){const E=n.querySelector(".rag-typing-indicator");E&&E.remove(),k=!0}w=!0,a.textContent+=g.content,I()}else g.type==="error"&&(a.textContent="Une erreur est survenue. Veuillez reformuler votre question ou rĂ©essayer plus tard.")}catch(g){console.error("Parse error:",g)}}!w&&!a.textContent&&(a.textContent="DĂ©solĂ©, je ne peux pas rĂ©pondre pour le moment. Veuillez rĂ©essayer dans quelques instants.")}catch(u){a.textContent="Le service est temporairement indisponible. Veuillez rĂ©essayer ultĂ©rieurement.",console.error("Error:",u);const l=n.querySelector(".rag-typing-indicator");l&&l.remove()}}function v(e,t,s=!1){const i=document.getElementById("rag-chatbot-messages"),n=document.createElement("div");return n.className=`rag-message rag-${t}-message`,s?n.innerHTML='<p></p><span class="rag-typing-indicator"></span>':n.innerHTML=`<p>${D(e)}</p>`,i.appendChild(n),I(),n}function D(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function I(){const e=document.getElementById("rag-chatbot-messages");e.scrollTop=e.scrollHeight}async function $(){const e=Date.now();if(p&&h&&h-e>3e4)return p;console.log("[JWT] RĂ©cupĂ©ration d'un nouveau token...");try{const t=await fetch(`${o.apiUrl}/api/session`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({public_key:o.apiKey})});if(!t.ok){const i=await t.json();throw console.error("[JWT] Erreur:",i),new Error(i.detail||"Impossible d'obtenir un token")}const s=await t.json();return p=s.token,h=e+s.expires_in*1e3,console.log("[JWT] ✅ Token obtenu, expire dans",s.expires_in,"secondes"),p}catch(t){throw console.error("[JWT] Erreur lors de la rĂ©cupĂ©ration du token:",t),t}}function H(e={}){if(o={...o,...e},!o.apiKey){console.error("❌ @webidea/rag-chatbot-widget: apiKey est obligatoire !"),console.error('Usage: init({ apiKey: "pk_your_public_key_here" })'),console.error("Contactez WebIdea pour obtenir votre clĂ© publique.");return}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",x):x()}function N(){r&&r.parentNode&&(r.parentNode.removeChild(r),r=null),m=!1}exports.destroy=N;exports.init=H;
@@ -0,0 +1,201 @@
1
+ const B = () => typeof crypto < "u" && crypto.randomUUID ? "visitor_" + crypto.randomUUID() : "visitor_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
2
+ let o = {
3
+ apiUrl: "https://backend-production-e9c35.up.railway.app",
4
+ // URL backend en dur
5
+ apiKey: null,
6
+ // OBLIGATOIRE - Public Key (pk_xxx) fournie par WebIdea
7
+ sessionId: B(),
8
+ collectionId: "default",
9
+ // Non utilisé (backend gÚre via JWT)
10
+ position: "bottom-right",
11
+ primaryColor: "#2CB3FF",
12
+ title: "Assistant",
13
+ subtitle: "Comment puis-je vous aider ?",
14
+ logoUrl: null,
15
+ logoSVG: null
16
+ // Code SVG inline (prioritaire sur logoUrl si défini)
17
+ }, m = !1, r = null, g = null, y = null, C = 0;
18
+ const j = 2e3;
19
+ function q() {
20
+ const e = o.position === "bottom-left" ? "rag-chatbot-left" : "rag-chatbot-right";
21
+ return `
22
+ <!-- Bouton flottant -->
23
+ <div id="rag-chatbot-button" class="${e}">
24
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
25
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
26
+ </svg>
27
+ </div>
28
+
29
+ <!-- FenĂȘtre de chat -->
30
+ <div id="rag-chatbot-window" class="rag-chatbot-window ${e}" style="display: none;">
31
+ <!-- Header -->
32
+ <div class="rag-chatbot-header">
33
+ <div style="display: flex; align-items: center; height: 24px;">
34
+ ${o.logoSVG ? o.logoSVG : o.logoUrl ? `<img src="${o.logoUrl}" alt="Logo" style="height: 24px; width: auto;">` : ""}
35
+ </div>
36
+ <button id="rag-chatbot-close">
37
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
38
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
39
+ </svg>
40
+ </button>
41
+ </div>
42
+
43
+ <!-- Messages -->
44
+ <div id="rag-chatbot-messages" class="rag-chatbot-messages">
45
+ <div class="rag-message rag-bot-message">
46
+ <p>Bonjour, je suis Eliott. Comment puis-je vous aider ?</p>
47
+ </div>
48
+ </div>
49
+
50
+ <!-- Input -->
51
+ <div class="rag-chatbot-input">
52
+ <input type="text" id="rag-chatbot-input" placeholder="Posez votre question...">
53
+ <button id="rag-chatbot-send">
54
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
55
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
56
+ </svg>
57
+ </button>
58
+ </div>
59
+ </div>
60
+ `;
61
+ }
62
+ function x() {
63
+ r = document.createElement("div"), r.id = "rag-chatbot-container", r.innerHTML = q(), document.body.appendChild(r), document.documentElement.style.setProperty("--rag-primary-color", o.primaryColor), U();
64
+ }
65
+ function U() {
66
+ document.getElementById("rag-chatbot-button").addEventListener("click", T), document.getElementById("rag-chatbot-close").addEventListener("click", T), document.getElementById("rag-chatbot-send").addEventListener("click", M), document.getElementById("rag-chatbot-input").addEventListener("keypress", (e) => {
67
+ e.key === "Enter" && M();
68
+ });
69
+ }
70
+ function T() {
71
+ m = !m;
72
+ const e = document.getElementById("rag-chatbot-window"), t = document.getElementById("rag-chatbot-button");
73
+ m ? (e.style.display = "flex", t.style.display = "none") : (e.style.display = "none", t.style.display = "flex");
74
+ }
75
+ async function M() {
76
+ var f, b;
77
+ const e = document.getElementById("rag-chatbot-input"), t = e.value.trim();
78
+ if (!t) return;
79
+ const s = 500;
80
+ if (t.length > s) {
81
+ const u = v(`⚠ Votre question est trop longue (${t.length} caractĂšres). Limite : ${s} caractĂšres.`, "bot");
82
+ setTimeout(() => u.remove(), 5e3);
83
+ return;
84
+ }
85
+ const i = Date.now();
86
+ if (i - C < j)
87
+ return;
88
+ C = i, v(t, "user"), e.value = "";
89
+ const n = v("", "bot", !0), a = n.querySelector("p");
90
+ try {
91
+ const u = await $(), l = await fetch(`${o.apiUrl}/ask`, {
92
+ method: "POST",
93
+ headers: {
94
+ "Content-Type": "application/json",
95
+ Authorization: `Bearer ${u}`
96
+ // Envoi du JWT token
97
+ },
98
+ body: JSON.stringify({
99
+ question: t,
100
+ session_id: o.sessionId,
101
+ collection_id: o.collectionId
102
+ })
103
+ });
104
+ if (!l.ok) {
105
+ if (l.status === 400) {
106
+ const d = await l.json();
107
+ if (((f = d.detail) == null ? void 0 : f.error) === "inappropriate_content") {
108
+ a.textContent = "⚠ " + d.detail.message;
109
+ const c = n.querySelector(".rag-typing-indicator");
110
+ c && c.remove();
111
+ return;
112
+ }
113
+ if (((b = d.detail) == null ? void 0 : b.error) === "guardrails_violation") {
114
+ a.textContent = "đŸ›Ąïž " + d.detail.message;
115
+ const c = n.querySelector(".rag-typing-indicator");
116
+ c && c.remove();
117
+ return;
118
+ }
119
+ }
120
+ throw new Error("Erreur réseau");
121
+ }
122
+ const S = l.body.getReader(), _ = new TextDecoder();
123
+ let w = !1, k = !1;
124
+ for (; ; ) {
125
+ const { value: d, done: c } = await S.read();
126
+ if (c) break;
127
+ const L = _.decode(d).split(`
128
+ `).filter((h) => h.trim());
129
+ for (const h of L)
130
+ try {
131
+ const p = JSON.parse(h);
132
+ if (p.type === "content") {
133
+ if (!k) {
134
+ const E = n.querySelector(".rag-typing-indicator");
135
+ E && E.remove(), k = !0;
136
+ }
137
+ w = !0, a.textContent += p.content, I();
138
+ } else p.type === "error" && (a.textContent = "Une erreur est survenue. Veuillez reformuler votre question ou réessayer plus tard.");
139
+ } catch (p) {
140
+ console.error("Parse error:", p);
141
+ }
142
+ }
143
+ !w && !a.textContent && (a.textContent = "Désolé, je ne peux pas répondre pour le moment. Veuillez réessayer dans quelques instants.");
144
+ } catch (u) {
145
+ a.textContent = "Le service est temporairement indisponible. Veuillez réessayer ultérieurement.", console.error("Error:", u);
146
+ const l = n.querySelector(".rag-typing-indicator");
147
+ l && l.remove();
148
+ }
149
+ }
150
+ function v(e, t, s = !1) {
151
+ const i = document.getElementById("rag-chatbot-messages"), n = document.createElement("div");
152
+ return n.className = `rag-message rag-${t}-message`, s ? n.innerHTML = '<p></p><span class="rag-typing-indicator"></span>' : n.innerHTML = `<p>${D(e)}</p>`, i.appendChild(n), I(), n;
153
+ }
154
+ function D(e) {
155
+ const t = document.createElement("div");
156
+ return t.textContent = e, t.innerHTML;
157
+ }
158
+ function I() {
159
+ const e = document.getElementById("rag-chatbot-messages");
160
+ e.scrollTop = e.scrollHeight;
161
+ }
162
+ async function $() {
163
+ const e = Date.now();
164
+ if (g && y && y - e > 3e4)
165
+ return g;
166
+ console.log("[JWT] Récupération d'un nouveau token...");
167
+ try {
168
+ const t = await fetch(`${o.apiUrl}/api/session`, {
169
+ method: "POST",
170
+ headers: {
171
+ "Content-Type": "application/json"
172
+ },
173
+ body: JSON.stringify({
174
+ public_key: o.apiKey
175
+ // Envoie la public key (pk_xxx)
176
+ })
177
+ });
178
+ if (!t.ok) {
179
+ const i = await t.json();
180
+ throw console.error("[JWT] Erreur:", i), new Error(i.detail || "Impossible d'obtenir un token");
181
+ }
182
+ const s = await t.json();
183
+ return g = s.token, y = e + s.expires_in * 1e3, console.log("[JWT] ✅ Token obtenu, expire dans", s.expires_in, "secondes"), g;
184
+ } catch (t) {
185
+ throw console.error("[JWT] Erreur lors de la récupération du token:", t), t;
186
+ }
187
+ }
188
+ function N(e = {}) {
189
+ if (o = { ...o, ...e }, !o.apiKey) {
190
+ console.error("❌ @webidea/rag-chatbot-widget: apiKey est obligatoire !"), console.error('Usage: init({ apiKey: "pk_your_public_key_here" })'), console.error("Contactez WebIdea pour obtenir votre clĂ© publique.");
191
+ return;
192
+ }
193
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", x) : x();
194
+ }
195
+ function V() {
196
+ r && r.parentNode && (r.parentNode.removeChild(r), r = null), m = !1;
197
+ }
198
+ export {
199
+ V as destroy,
200
+ N as init
201
+ };
@@ -0,0 +1,41 @@
1
+ (function(s,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(s=typeof globalThis<"u"?globalThis:s||self,m(s.RAGChatbot={}))})(this,function(s){"use strict";let o={apiUrl:"https://backend-production-e9c35.up.railway.app",apiKey:null,sessionId:typeof crypto<"u"&&crypto.randomUUID?"visitor_"+crypto.randomUUID():"visitor_"+Date.now()+"_"+Math.random().toString(36).substr(2,9),collectionId:"default",position:"bottom-right",primaryColor:"#2CB3FF",title:"Assistant",subtitle:"Comment puis-je vous aider ?",logoUrl:null,logoSVG:null},h=!1,r=null,y=null,f=null,w=0;const j=2e3;function L(){const e=o.position==="bottom-left"?"rag-chatbot-left":"rag-chatbot-right";return`
2
+ <!-- Bouton flottant -->
3
+ <div id="rag-chatbot-button" class="${e}">
4
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
5
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
6
+ </svg>
7
+ </div>
8
+
9
+ <!-- FenĂȘtre de chat -->
10
+ <div id="rag-chatbot-window" class="rag-chatbot-window ${e}" style="display: none;">
11
+ <!-- Header -->
12
+ <div class="rag-chatbot-header">
13
+ <div style="display: flex; align-items: center; height: 24px;">
14
+ ${o.logoSVG?o.logoSVG:o.logoUrl?`<img src="${o.logoUrl}" alt="Logo" style="height: 24px; width: auto;">`:""}
15
+ </div>
16
+ <button id="rag-chatbot-close">
17
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
18
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
19
+ </svg>
20
+ </button>
21
+ </div>
22
+
23
+ <!-- Messages -->
24
+ <div id="rag-chatbot-messages" class="rag-chatbot-messages">
25
+ <div class="rag-message rag-bot-message">
26
+ <p>Bonjour, je suis Eliott. Comment puis-je vous aider ?</p>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Input -->
31
+ <div class="rag-chatbot-input">
32
+ <input type="text" id="rag-chatbot-input" placeholder="Posez votre question...">
33
+ <button id="rag-chatbot-send">
34
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
35
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
36
+ </svg>
37
+ </button>
38
+ </div>
39
+ </div>
40
+ `}function k(){r=document.createElement("div"),r.id="rag-chatbot-container",r.innerHTML=L(),document.body.appendChild(r),document.documentElement.style.setProperty("--rag-primary-color",o.primaryColor),B()}function B(){document.getElementById("rag-chatbot-button").addEventListener("click",E),document.getElementById("rag-chatbot-close").addEventListener("click",E),document.getElementById("rag-chatbot-send").addEventListener("click",C),document.getElementById("rag-chatbot-input").addEventListener("keypress",e=>{e.key==="Enter"&&C()})}function E(){h=!h;const e=document.getElementById("rag-chatbot-window"),t=document.getElementById("rag-chatbot-button");h?(e.style.display="flex",t.style.display="none"):(e.style.display="none",t.style.display="flex")}async function C(){var T,M;const e=document.getElementById("rag-chatbot-input"),t=e.value.trim();if(!t)return;const i=500;if(t.length>i){const p=v(`⚠ Votre question est trop longue (${t.length} caractĂšres). Limite : ${i} caractĂšres.`,"bot");setTimeout(()=>p.remove(),5e3);return}const a=Date.now();if(a-w<j)return;w=a,v(t,"user"),e.value="";const n=v("","bot",!0),l=n.querySelector("p");try{const p=await U(),c=await fetch(`${o.apiUrl}/ask`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${p}`},body:JSON.stringify({question:t,session_id:o.sessionId,collection_id:o.collectionId})});if(!c.ok){if(c.status===400){const u=await c.json();if(((T=u.detail)==null?void 0:T.error)==="inappropriate_content"){l.textContent="⚠ "+u.detail.message;const d=n.querySelector(".rag-typing-indicator");d&&d.remove();return}if(((M=u.detail)==null?void 0:M.error)==="guardrails_violation"){l.textContent="đŸ›Ąïž "+u.detail.message;const d=n.querySelector(".rag-typing-indicator");d&&d.remove();return}}throw new Error("Erreur rĂ©seau")}const H=c.body.getReader(),N=new TextDecoder;let I=!1,S=!1;for(;;){const{value:u,done:d}=await H.read();if(d)break;const O=N.decode(u).split(`
41
+ `).filter(b=>b.trim());for(const b of O)try{const g=JSON.parse(b);if(g.type==="content"){if(!S){const _=n.querySelector(".rag-typing-indicator");_&&_.remove(),S=!0}I=!0,l.textContent+=g.content,x()}else g.type==="error"&&(l.textContent="Une erreur est survenue. Veuillez reformuler votre question ou rĂ©essayer plus tard.")}catch(g){console.error("Parse error:",g)}}!I&&!l.textContent&&(l.textContent="DĂ©solĂ©, je ne peux pas rĂ©pondre pour le moment. Veuillez rĂ©essayer dans quelques instants.")}catch(p){l.textContent="Le service est temporairement indisponible. Veuillez rĂ©essayer ultĂ©rieurement.",console.error("Error:",p);const c=n.querySelector(".rag-typing-indicator");c&&c.remove()}}function v(e,t,i=!1){const a=document.getElementById("rag-chatbot-messages"),n=document.createElement("div");return n.className=`rag-message rag-${t}-message`,i?n.innerHTML='<p></p><span class="rag-typing-indicator"></span>':n.innerHTML=`<p>${q(e)}</p>`,a.appendChild(n),x(),n}function q(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function x(){const e=document.getElementById("rag-chatbot-messages");e.scrollTop=e.scrollHeight}async function U(){const e=Date.now();if(y&&f&&f-e>3e4)return y;console.log("[JWT] RĂ©cupĂ©ration d'un nouveau token...");try{const t=await fetch(`${o.apiUrl}/api/session`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({public_key:o.apiKey})});if(!t.ok){const a=await t.json();throw console.error("[JWT] Erreur:",a),new Error(a.detail||"Impossible d'obtenir un token")}const i=await t.json();return y=i.token,f=e+i.expires_in*1e3,console.log("[JWT] ✅ Token obtenu, expire dans",i.expires_in,"secondes"),y}catch(t){throw console.error("[JWT] Erreur lors de la rĂ©cupĂ©ration du token:",t),t}}function D(e={}){if(o={...o,...e},!o.apiKey){console.error("❌ @webidea/rag-chatbot-widget: apiKey est obligatoire !"),console.error('Usage: init({ apiKey: "pk_your_public_key_here" })'),console.error("Contactez WebIdea pour obtenir votre clĂ© publique.");return}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",k):k()}function $(){r&&r.parentNode&&(r.parentNode.removeChild(r),r=null),h=!1}s.destroy=$,s.init=D,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ :root{--rag-primary-color: #2CB3FF;--rag-secondary-color: #2CB3FF;--rag-text-color: #FFF;--rag-bg-color: #212A2F;--rag-border-color: #3a4550;--rag-shadow: 0 10px 40px rgba(0, 0, 0, .4)}#rag-chatbot-button{position:fixed;bottom:20px;width:60px;height:60px;background:var(--rag-primary-color);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:var(--rag-shadow);z-index:9999;transition:all .3s ease}#rag-chatbot-button:hover{transform:scale(1.1);background:var(--rag-secondary-color)}#rag-chatbot-button svg{width:30px;height:30px;color:#fff}.rag-chatbot-right{right:20px}.rag-chatbot-left{left:20px}.rag-chatbot-window{position:fixed;bottom:20px;width:400px;height:600px;background:var(--rag-bg-color);border-radius:16px;box-shadow:var(--rag-shadow);z-index:9999;display:flex;flex-direction:column;overflow:hidden;animation:slideUp .3s ease}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.rag-chatbot-window.rag-chatbot-right{right:20px}.rag-chatbot-window.rag-chatbot-left{left:20px}.rag-chatbot-header{background:#212a2f;color:#fff;padding:20px;display:flex;justify-content:space-between;align-items:center}.rag-chatbot-header h3{margin:0;font-size:18px;font-weight:600}.rag-chatbot-header p{margin:5px 0 0;font-size:13px;opacity:.9}#rag-chatbot-close{background:none;border:none;color:#fff;cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background .2s}#rag-chatbot-close:hover{background:#fff3}#rag-chatbot-close svg{width:24px;height:24px}.rag-chatbot-messages{flex:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:15px;background:#1a2227}.rag-message{max-width:80%;padding:12px 16px;border-radius:12px;font-size:14px;line-height:1.5;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.rag-message p{margin:0;word-wrap:break-word;white-space:pre-wrap}.rag-bot-message{align-self:flex-start;background:#2d3740;border:1px solid var(--rag-border-color);color:var(--rag-text-color)}.rag-user-message{align-self:flex-end;background:var(--rag-primary-color);color:#fff}.rag-typing-indicator{color:var(--rag-primary-color);font-size:2.5px;position:relative;text-indent:-9999em;transform:translateZ(0);animation-delay:-.16s;display:inline-block;border-radius:50%;width:2.5em;height:2.5em;animation-fill-mode:both;animation:bblFadInOut 1.8s infinite ease-in-out}.rag-typing-indicator:before,.rag-typing-indicator:after{content:"";position:absolute;top:0;border-radius:50%;width:2.5em;height:2.5em;animation-fill-mode:both;animation:bblFadInOut 1.8s infinite ease-in-out}.rag-typing-indicator:before{left:-3.5em;animation-delay:-.32s}.rag-typing-indicator:after{left:3.5em}@keyframes bblFadInOut{0%,80%,to{box-shadow:0 2.5em 0 -1.3em}40%{box-shadow:0 2.5em}}.rag-chatbot-input{padding:15px;border-top:1px solid var(--rag-border-color);background:#2d3740;display:flex;gap:10px}#rag-chatbot-input{flex:1;padding:12px 15px;border:2px solid var(--rag-border-color);border-radius:24px;font-size:14px;transition:border-color .2s;background:#212a2f;color:#fff}#rag-chatbot-input:focus{outline:none;border-color:var(--rag-primary-color)}#rag-chatbot-send{width:45px;height:45px;background:var(--rag-primary-color);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}#rag-chatbot-send:hover{background:var(--rag-secondary-color);transform:scale(1.05)}#rag-chatbot-send svg{width:20px;height:20px}@media (max-width: 480px){.rag-chatbot-window{width:calc(100% - 20px);height:calc(100% - 20px);bottom:10px;left:10px;right:10px}.rag-chatbot-window.rag-chatbot-right,.rag-chatbot-window.rag-chatbot-left{left:10px;right:10px}}.rag-chatbot-messages::-webkit-scrollbar{width:6px}.rag-chatbot-messages::-webkit-scrollbar-track{background:transparent}.rag-chatbot-messages::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}.rag-chatbot-messages::-webkit-scrollbar-thumb:hover{background:#94a3b8}.rag-chatbot-window,.rag-chatbot-window *{font-family:Inter,sans-serif!important}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "rag-chatbot-widget-alpha",
3
+ "version": "1.0.0",
4
+ "description": "Widget chatbot RAG intelligent avec IA - Intégration facile pour React, Vue, Angular et sites web",
5
+ "main": "./dist/index.cjs.js",
6
+ "module": "./dist/index.es.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.es.js",
10
+ "require": "./dist/index.cjs.js"
11
+ },
12
+ "./styles.css": "./dist/style.css"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "vite build",
20
+ "dev": "vite build --watch"
21
+ },
22
+ "keywords": [
23
+ "chatbot",
24
+ "rag",
25
+ "widget",
26
+ "ai",
27
+ "assistant",
28
+ "react",
29
+ "vue",
30
+ "angular",
31
+ "openai",
32
+ "langchain"
33
+ ],
34
+ "author": "WebIdea",
35
+ "license": "MIT",
36
+ "devDependencies": {
37
+ "vite": "^5.0.0"
38
+ }
39
+ }