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 +210 -0
- package/dist/index.cjs.js +41 -0
- package/dist/index.es.js +201 -0
- package/dist/index.umd.js +41 -0
- package/dist/style.css +1 -0
- package/package.json +39 -0
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;
|
package/dist/index.es.js
ADDED
|
@@ -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
|
+
}
|