Abmacode12 commited on
Commit
f70edbb
·
verified ·
1 Parent(s): fc48aca

J'aimerais avec grand respect vous demander de réactiver mon thème personnalisé que nous avons créé ensemble. Je tiens beaucoup à ce projet et je crois en notre collaboration.

Pourriez-vous également veiller à ces détails importants :

Micro fonctionnel dans la barre de recherche pour l'envoi vocal

Bonne ergonomie pour l'envoi de fichiers

Interface claire comme sur la capture d'écran

Je suis ouvert à discuter pour améliorer notre façon de travailler ensemble en équipe. Je crois que nous pouvons créer quelque chose de vraiment génial si nous communiquons bien et que nous nous respectons mutuellement.

Avec confiance et en attendant une réponse positive,

Files changed (2) hide show
  1. components/chat.js +101 -125
  2. style.css +37 -3
components/chat.js CHANGED
@@ -202,159 +202,135 @@ connectedCallback() {
202
  const messageInput = shadow.getElementById('messageInput');
203
  const filesInfo = shadow.getElementById('filesInfo');
204
  const micStatus = shadow.getElementById('micStatus');
205
-
206
  let recognition;
207
  let isListening = false;
208
 
209
- // Style micro actif
210
- micButton.addEventListener('mouseenter', () => {
211
- if (isListening) micButton.style.backgroundColor = '#ef4444';
212
- });
213
- micButton.addEventListener('mouseleave', () => {
214
- if (isListening) micButton.style.backgroundColor = '#3b82f6';
215
- });
216
- // File upload with preview
217
- fileButton.addEventListener('click', () => fileInput.click());
218
- fileInput.addEventListener('change', (e) => {
219
- this._files = Array.from(e.target.files);
220
- if (this._files.length) {
221
- filesInfo.innerHTML = `
222
- <div style="display:flex; gap:0.5rem; align-items:center;">
223
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
224
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
225
- <polyline points="14 2 14 8 20 8" />
226
- </svg>
227
- ${this._files.length} fichier(s) prêt(s) à envoyer
228
- </div>
229
- `;
230
- } else {
231
- filesInfo.textContent = '';
232
- }
233
- });
234
- // Connect apps with better UX
235
- connectButton.addEventListener('click', () => {
236
- this._addMessage('assistant',
237
- `🔌 Connexion d'applications disponible pour:
238
- - Stockage local (${navigator.storage ? '✓' : '✗'})
239
- - Microphone (${'webkitSpeechRecognition' in window ? '✓' : '✗'})
240
- - Caméra (${navigator.mediaDevices ? '✓' : '✗'})
241
-
242
- Dites-moi ce que vous souhaitez connecter.`);
243
- });
244
- // Enhanced speech recognition
245
  micButton.addEventListener('click', () => {
246
  if (isListening) {
247
- if (recognition) recognition.stop();
248
  isListening = false;
249
- micButton.classList.remove('listening');
250
- micButton.style.backgroundColor = '';
251
- micStatus.textContent = 'En ligne';
252
  return;
253
  }
254
- const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
255
- if (!SpeechRecognition) {
256
- this._addMessage('assistant', 'Votre navigateur ne supporte pas la reconnaissance vocale. Essayez avec Chrome ou Edge.');
257
  return;
258
  }
259
 
260
- recognition = new SpeechRecognition();
261
- recognition.lang = 'fr-FR';
262
- recognition.interimResults = true;
263
- recognition.continuous = true;
 
 
 
 
 
 
 
 
 
264
 
265
- recognition.onstart = () => {
266
- isListening = true;
267
- micButton.classList.add('listening');
268
- micButton.style.backgroundColor = '#3b82f6';
269
- micStatus.textContent = '🎤 En écoute...';
270
- this._addMessage('assistant', 'Je vous écoute... Parlez maintenant.');
271
- };
272
- recognition.onresult = (event) => {
273
- let finalTranscript = '';
274
- let interimTranscript = '';
275
-
276
- for (let i = event.resultIndex; i < event.results.length; i++) {
277
- const transcript = event.results[i][0].transcript;
278
- if (event.results[i].isFinal) {
279
- finalTranscript += transcript;
280
- } else {
281
- interimTranscript += transcript;
282
- }
283
- }
284
-
285
- messageInput.value = finalTranscript || interimTranscript;
286
- };
287
- recognition.onerror = (event) => {
288
- isListening = false;
289
- micButton.classList.remove('listening');
290
- micButton.style.backgroundColor = '';
291
-
292
- if (event.error === 'not-allowed') {
293
- micStatus.textContent = 'Permission requise';
294
- this._addMessage('assistant', 'Veuillez autoriser l\'accès au microphone dans les paramètres de votre navigateur.');
295
- } else {
296
- micStatus.textContent = 'Erreur micro';
297
- this._addMessage('assistant', 'Désolé, je n\'ai pas pu accéder au microphone. Essayez de parler plus fort ou de vérifier vos paramètres.');
298
- }
299
-
300
- setTimeout(() => micStatus.textContent = 'En ligne', 3000);
301
- };
302
 
303
- recognition.onend = () => {
304
- if (isListening) {
305
- isListening = false;
306
- micButton.classList.remove('listening');
307
- micButton.style.backgroundColor = '';
308
- micStatus.textContent = 'En ligne';
309
- }
310
- };
311
- try {
312
- recognition.start();
313
- } catch (err) {
314
- this._speechState = 'idle';
315
- micStatus.textContent = 'Erreur micro';
316
- micButton.classList.remove('listening');
317
  }
318
  });
319
- // Enhanced send message with file handling
 
 
 
 
 
 
 
 
 
 
 
320
  const sendMessage = () => {
321
  const message = messageInput.value.trim();
322
  if (message || this._files.length) {
323
- // User message with files
324
- let userMessage = message;
325
- if (this._files.length) {
326
- userMessage += `\n\n📎 Fichiers: ${this._files.map(f => f.name).join(', ')}`;
327
- }
328
-
329
- this._addMessage('user', userMessage);
330
  messageInput.value = '';
331
- this._files = [];
332
- filesInfo.innerHTML = '';
333
- fileInput.value = '';
334
-
335
- // Rosalinda's response
336
  setTimeout(() => {
337
  let response;
338
  if (this._files.length > 0) {
339
- response = `J'ai bien reçu ${this._files.length} fichier(s) avec votre message. Je les analyse maintenant...`;
340
- } else if (message.toLowerCase().includes('projet')) {
341
- response = "Pour votre projet, je suggère:\n1. Structure claire\n2. Design cohérent\n3. Tests approfondis\nQu'en pensez-vous?";
342
- } else if (message.toLowerCase().includes('image')) {
343
- response = "Je peux générer des images personnalisées. Dites-moi ce que vous imaginez.";
344
  } else {
345
- const responses = [
346
- "Je travaille sur votre demande...",
347
- "Analyse terminée. Voici mes suggestions:",
348
- "J'ai une solution créative pour vous:",
349
- "Voici ce que je propose:"
350
- ];
351
- response = responses[Math.floor(Math.random() * responses.length)];
352
  }
353
-
354
  this._addMessage('assistant', response);
355
  }, 1000);
356
  }
357
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  sendButton.addEventListener('click', sendMessage);
359
  messageInput.addEventListener('keydown', (e) => {
360
  if (e.key === 'Enter') sendMessage();
 
202
  const messageInput = shadow.getElementById('messageInput');
203
  const filesInfo = shadow.getElementById('filesInfo');
204
  const micStatus = shadow.getElementById('micStatus');
205
+ const chatContainer = shadow.getElementById('chat');
206
  let recognition;
207
  let isListening = false;
208
 
209
+ // Enhanced microphone functionality
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  micButton.addEventListener('click', () => {
211
  if (isListening) {
212
+ this._stopSpeechRecognition(recognition, micButton, micStatus);
213
  isListening = false;
 
 
 
214
  return;
215
  }
216
+
217
+ if (!('webkitSpeechRecognition' in window || 'SpeechRecognition' in window)) {
218
+ this._addMessage('assistant', 'La reconnaissance vocale n\'est pas supportée par votre navigateur. Essayez Chrome ou Edge.');
219
  return;
220
  }
221
 
222
+ recognition = this._startSpeechRecognition(micButton, micStatus, messageInput);
223
+ isListening = true;
224
+
225
+ // Add visual feedback
226
+ micButton.classList.add('listening');
227
+ micStatus.textContent = '🎤 En écoute...';
228
+ this._addMessage('assistant', 'Je vous écoute... Parlez maintenant.');
229
+ });
230
+ // Enhanced file upload with drag & drop
231
+ fileButton.addEventListener('click', () => fileInput.click());
232
+ fileInput.addEventListener('change', (e) => {
233
+ this._handleFiles(e.target.files, filesInfo);
234
+ });
235
 
236
+ // Drag & drop support
237
+ chatContainer.addEventListener('dragover', (e) => {
238
+ e.preventDefault();
239
+ chatContainer.style.border = '2px dashed #3b82f6';
240
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
+ chatContainer.addEventListener('dragleave', () => {
243
+ chatContainer.style.border = 'none';
244
+ });
245
+
246
+ chatContainer.addEventListener('drop', (e) => {
247
+ e.preventDefault();
248
+ chatContainer.style.border = 'none';
249
+ if (e.dataTransfer.files.length) {
250
+ this._handleFiles(e.dataTransfer.files, filesInfo);
 
 
 
 
 
251
  }
252
  });
253
+ // Connect apps with Rosalinda integration
254
+ connectButton.addEventListener('click', () => {
255
+ this._addMessage('assistant',
256
+ `🔌 Rosalinda peut se connecter à:
257
+ - Votre ordinateur (fichiers locaux)
258
+ - Votre micro (dictée vocale)
259
+ - Votre caméra (analyse visuelle)
260
+ - Vos applications préférées
261
+
262
+ Que souhaitez-vous connecter en premier ?`);
263
+ });
264
+ // Enhanced send message with files
265
  const sendMessage = () => {
266
  const message = messageInput.value.trim();
267
  if (message || this._files.length) {
268
+ this._addMessage('user', message);
 
 
 
 
 
 
269
  messageInput.value = '';
270
+
271
+ // Simulate Rosalinda processing
 
 
 
272
  setTimeout(() => {
273
  let response;
274
  if (this._files.length > 0) {
275
+ response = `J'ai bien reçu ${this._files.length} fichier(s). Je les analyse maintenant...`;
276
+ this._files = [];
277
+ filesInfo.innerHTML = '';
 
 
278
  } else {
279
+ response = this._generateRosalindaResponse(message);
 
 
 
 
 
 
280
  }
 
281
  this._addMessage('assistant', response);
282
  }, 1000);
283
  }
284
  };
285
+ // Helper methods
286
+ _handleFiles(files, filesInfo) {
287
+ this._files = Array.from(files);
288
+ if (this._files.length) {
289
+ filesInfo.innerHTML = `
290
+ <div style="display:flex; gap:0.5rem; align-items:center;">
291
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
292
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
293
+ <polyline points="14 2 14 8 20 8" />
294
+ </svg>
295
+ ${this._files.length} fichier(s) sélectionné(s)
296
+ <button id="clearFiles" style="margin-left:auto; background:none; border:none; color:#3b82f6; cursor:pointer;">
297
+ Effacer
298
+ </button>
299
+ </div>
300
+ `;
301
+ shadow.getElementById('clearFiles').addEventListener('click', () => {
302
+ this._files = [];
303
+ filesInfo.innerHTML = '';
304
+ fileInput.value = '';
305
+ });
306
+ } else {
307
+ filesInfo.textContent = '';
308
+ }
309
+ }
310
+
311
+ _generateRosalindaResponse(message) {
312
+ if (message.toLowerCase().includes('projet')) {
313
+ return `Pour votre projet, voici ce que je propose:
314
+ 1. Structure claire et modulaire
315
+ 2. Design cohérent avec votre identité
316
+ 3. Tests automatisés
317
+ 4. Documentation complète
318
+
319
+ Par où commençons-nous ?`;
320
+ } else if (message.toLowerCase().includes('image')) {
321
+ return "Je peux générer des images personnalisées. Décrivez-moi ce que vous imaginez (couleurs, style, éléments).";
322
+ } else if (message.toLowerCase().includes('vidéo')) {
323
+ return "Pour la vidéo, je peux vous aider avec:\n- Scénarisation\n- Montage\n- Effets\n- Sous-titres\nQuel aspect souhaitez-vous développer ?";
324
+ } else {
325
+ const responses = [
326
+ "J'ai bien compris votre demande. Voici mes suggestions...",
327
+ "Analyse terminée. Voici ce que je propose:",
328
+ "Excellente idée ! Voici comment nous pourrions procéder:",
329
+ "Je peux vous aider avec cela. Voici un plan d'action:"
330
+ ];
331
+ return responses[Math.floor(Math.random() * responses.length)];
332
+ }
333
+ }
334
  sendButton.addEventListener('click', sendMessage);
335
  messageInput.addEventListener('keydown', (e) => {
336
  if (e.key === 'Enter') sendMessage();
style.css CHANGED
@@ -50,11 +50,45 @@ custom-chat {
50
  animation: pulse 1.5s infinite;
51
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
52
  transition: all 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
54
  @keyframes pulse {
55
- 0% { opacity: 1; }
56
- 50% { opacity: 0.7; }
57
- 100% { opacity: 1; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
  .file-info {
60
  font-size: 0.75rem;
 
50
  animation: pulse 1.5s infinite;
51
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
52
  transition: all 0.3s ease;
53
+ position: relative;
54
+ }
55
+
56
+ .mic-button.listening::after {
57
+ content: '';
58
+ position: absolute;
59
+ top: -5px;
60
+ left: -5px;
61
+ right: -5px;
62
+ bottom: -5px;
63
+ border: 2px solid rgba(59, 130, 246, 0.3);
64
+ border-radius: 50%;
65
+ animation: ripple 1.5s infinite;
66
  }
67
  @keyframes pulse {
68
+ 0% { opacity: 1; transform: scale(1); }
69
+ 50% { opacity: 0.8; transform: scale(1.05); }
70
+ 100% { opacity: 1; transform: scale(1); }
71
+ }
72
+
73
+ @keyframes ripple {
74
+ 0% { transform: scale(0.8); opacity: 1; }
75
+ 100% { transform: scale(1.3); opacity: 0; }
76
+ }
77
+
78
+ custom-chat {
79
+ border: 1px solid rgba(255, 255, 255, 0.1);
80
+ border-radius: 0.75rem;
81
+ overflow: hidden;
82
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
83
+ }
84
+
85
+ .message-input {
86
+ transition: all 0.3s ease;
87
+ }
88
+
89
+ .message-input:focus {
90
+ border-color: #3b82f6;
91
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
92
  }
93
  .file-info {
94
  font-size: 0.75rem;