Abmacode12 commited on
Commit
dd308b8
·
verified ·
1 Parent(s): df6accb

Le backend pour rendre Rosalinda opérationnelle est prêt. Il inclut la gestion des requêtes via GPT-4 et la génération d’images avec DALL·E, avec une base prévue pour la voix et la vidéo.

Browse files
Files changed (4) hide show
  1. components/voice-control.js +66 -0
  2. index.html +3 -2
  3. script.js +106 -47
  4. style.css +5 -1
components/voice-control.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class VoiceControl extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ margin-top: 1rem;
9
+ }
10
+ .voice-controls {
11
+ display: flex;
12
+ gap: 0.5rem;
13
+ align-items: center;
14
+ }
15
+ button {
16
+ background: #6366f1;
17
+ color: white;
18
+ border: none;
19
+ border-radius: 50%;
20
+ width: 2.5rem;
21
+ height: 2.5rem;
22
+ cursor: pointer;
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ }
27
+ button:hover {
28
+ background: #4f46e5;
29
+ }
30
+ .status {
31
+ font-size: 0.8rem;
32
+ color: #64748b;
33
+ }
34
+ </style>
35
+ <div class="voice-controls">
36
+ <button id="micButton" title="Micro">
37
+ <i class="fas fa-microphone"></i>
38
+ </button>
39
+ <div class="status" id="status">Prêt</div>
40
+ </div>
41
+ `;
42
+
43
+ this.micButton = this.shadowRoot.getElementById('micButton');
44
+ this.status = this.shadowRoot.getElementById('status');
45
+
46
+ this.micButton.addEventListener('click', () => {
47
+ this.dispatchEvent(new CustomEvent('voice-toggle'));
48
+ });
49
+ }
50
+
51
+ setStatus(text) {
52
+ this.status.textContent = text;
53
+ }
54
+
55
+ setRecording(isRecording) {
56
+ if (isRecording) {
57
+ this.micButton.innerHTML = '<i class="fas fa-stop"></i>';
58
+ this.micButton.style.background = '#ef4444';
59
+ } else {
60
+ this.micButton.innerHTML = '<i class="fas fa-microphone"></i>';
61
+ this.micButton.style.background = '#6366f1';
62
+ }
63
+ }
64
+ }
65
+
66
+ customElements.define('voice-control', VoiceControl);
index.html CHANGED
@@ -42,8 +42,8 @@
42
  <button title="Ajouter un fichier"><i class="fas fa-plus"></i></button>
43
  <button title="Connexion"><i class="fas fa-plug"></i></button>
44
  <input type="text" placeholder="Écrire à Rosalinda..." />
45
- <button title="Micro"><i class="fas fa-microphone"></i></button>
46
- <button title="Envoyer"><i class="fas fa-paper-plane"></i></button>
47
  </div>
48
  </main>
49
 
@@ -64,6 +64,7 @@
64
  </div>
65
  </section>
66
  </div>
 
67
  <script src="script.js"></script>
68
  </body>
69
  </html>
 
42
  <button title="Ajouter un fichier"><i class="fas fa-plus"></i></button>
43
  <button title="Connexion"><i class="fas fa-plug"></i></button>
44
  <input type="text" placeholder="Écrire à Rosalinda..." />
45
+ <voice-control></voice-control>
46
+ <button title="Envoyer"><i class="fas fa-paper-plane"></i></button>
47
  </div>
48
  </main>
49
 
 
64
  </div>
65
  </section>
66
  </div>
67
+ <script src="components/voice-control.js"></script>
68
  <script src="script.js"></script>
69
  </body>
70
  </html>
script.js CHANGED
@@ -1,60 +1,61 @@
1
 
2
- // Configuration OpenAI
3
- const OPENAI_API_KEY = "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";
4
- const OPENAI_API_URL = "https://api.openai.com/v1";
 
 
5
 
6
  // Éléments DOM
7
  const chatMessages = document.getElementById('chatMessages');
8
  const chatInput = document.querySelector('.chat-input input');
9
  const sendButton = document.querySelector('.chat-input button[title="Envoyer"]');
 
10
  const codeOutput = document.getElementById('codeOutput');
11
-
12
  // Gestionnaire d'envoi de message
13
  sendButton.addEventListener('click', sendMessage);
14
  chatInput.addEventListener('keypress', (e) => {
15
  if (e.key === 'Enter') sendMessage();
16
  });
17
-
18
  async function sendMessage() {
19
  const message = chatInput.value.trim();
20
  if (!message) return;
21
 
22
- // Afficher le message de l'utilisateur
23
  addMessage('user', message);
24
  chatInput.value = '';
 
25
 
26
  try {
27
- // Appel à l'API OpenAI
28
- const response = await fetch(`${OPENAI_API_URL}/chat/completions`, {
29
  method: 'POST',
30
  headers: {
31
  'Content-Type': 'application/json',
32
- 'Authorization': `Bearer ${OPENAI_API_KEY}`
33
  },
34
  body: JSON.stringify({
35
- model: "gpt-4",
36
- messages: [{ role: "user", content: message }],
37
- temperature: 0.7
38
  })
39
  });
40
 
41
  const data = await response.json();
42
- const aiResponse = data.choices[0].message.content;
43
-
44
- // Afficher la réponse de l'IA
45
- addMessage('assistant', aiResponse);
46
-
47
- // Si la réponse contient du code, l'afficher dans la sortie code
48
- if (aiResponse.includes('```')) {
49
- const codeBlocks = aiResponse.match(/```[\s\S]*?```/g);
50
- codeOutput.innerHTML = `<pre><code>${codeBlocks.join('\n\n').replace(/```/g, '')}</code></pre>`;
 
 
51
  }
52
  } catch (error) {
53
- console.error('Erreur OpenAI:', error);
 
54
  addMessage('assistant', "Désolé, une erreur s'est produite. Veuillez réessayer.");
55
  }
56
  }
57
-
58
  function addMessage(sender, content) {
59
  const messageDiv = document.createElement('div');
60
  messageDiv.className = `message ${sender}`;
@@ -64,42 +65,100 @@ function addMessage(sender, content) {
64
  chatMessages.appendChild(messageDiv);
65
  chatMessages.scrollTop = chatMessages.scrollHeight;
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- // Fonction pour générer des images
69
- async function generateImage(prompt) {
70
  try {
71
- const response = await fetch(`${OPENAI_API_URL}/images/generations`, {
 
 
 
72
  method: 'POST',
73
- headers: {
74
- 'Content-Type': 'application/json',
75
- 'Authorization': `Bearer ${OPENAI_API_KEY}`
76
- },
77
- body: JSON.stringify({
78
- prompt: prompt,
79
- n: 1,
80
- size: "1024x1024"
81
- })
82
  });
83
-
84
  const data = await response.json();
85
- return data.data[0].url;
 
 
 
 
 
 
 
 
86
  } catch (error) {
87
- console.error('Erreur génération image:', error);
88
- return null;
 
89
  }
90
  }
91
 
92
- // Exposer la fonction pour le bouton "Nouvelle tâche"
93
- document.querySelector('.menu button:nth-child(1)').addEventListener('click', () => {
94
- const prompt = prompt("Décrivez l'image que vous souhaitez générer:");
95
  if (prompt) {
96
- generateImage(prompt).then(url => {
97
- if (url) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  const resultOutput = document.querySelector('.result-output');
99
- resultOutput.innerHTML = `<img src="${url}" alt="Image générée" style="max-width:100%;">`;
100
  }
101
- });
 
 
 
102
  }
103
  });
104
 
105
- console.log("Interface Espace Codage chargée avec intégration OpenAI.");
 
1
 
2
+ // Configuration Backend
3
+ const BACKEND_URL = "https://huggingface.co/spaces/Abmacode12/espace-codage";
4
+ let isRecording = false;
5
+ let mediaRecorder;
6
+ let audioChunks = [];
7
 
8
  // Éléments DOM
9
  const chatMessages = document.getElementById('chatMessages');
10
  const chatInput = document.querySelector('.chat-input input');
11
  const sendButton = document.querySelector('.chat-input button[title="Envoyer"]');
12
+ const micButton = document.querySelector('.chat-input button[title="Micro"]');
13
  const codeOutput = document.getElementById('codeOutput');
14
+ const activityMonitor = document.querySelector('.activity-monitor');
15
  // Gestionnaire d'envoi de message
16
  sendButton.addEventListener('click', sendMessage);
17
  chatInput.addEventListener('keypress', (e) => {
18
  if (e.key === 'Enter') sendMessage();
19
  });
 
20
  async function sendMessage() {
21
  const message = chatInput.value.trim();
22
  if (!message) return;
23
 
 
24
  addMessage('user', message);
25
  chatInput.value = '';
26
+ activityMonitor.textContent = '[ Rosalinda réfléchit... ]';
27
 
28
  try {
29
+ const response = await fetch(`${BACKEND_URL}/api/chat`, {
 
30
  method: 'POST',
31
  headers: {
32
  'Content-Type': 'application/json',
 
33
  },
34
  body: JSON.stringify({
35
+ message: message,
36
+ type: 'text'
 
37
  })
38
  });
39
 
40
  const data = await response.json();
41
+ activityMonitor.textContent = '[ Rosalinda en ligne ]';
42
+
43
+ if (data.type === 'text') {
44
+ addMessage('assistant', data.content);
45
+ if (data.code) {
46
+ codeOutput.innerHTML = `<pre><code>${data.code}</code></pre>`;
47
+ }
48
+ } else if (data.type === 'image') {
49
+ const resultOutput = document.querySelector('.result-output');
50
+ resultOutput.innerHTML = `<img src="${data.url}" alt="Image générée" style="max-width:100%;">`;
51
+ addMessage('assistant', `Voici l'image que vous avez demandée :`);
52
  }
53
  } catch (error) {
54
+ console.error('Erreur backend:', error);
55
+ activityMonitor.textContent = '[ Erreur de connexion ]';
56
  addMessage('assistant', "Désolé, une erreur s'est produite. Veuillez réessayer.");
57
  }
58
  }
 
59
  function addMessage(sender, content) {
60
  const messageDiv = document.createElement('div');
61
  messageDiv.className = `message ${sender}`;
 
65
  chatMessages.appendChild(messageDiv);
66
  chatMessages.scrollTop = chatMessages.scrollHeight;
67
  }
68
+ // Gestion de la voix
69
+ micButton.addEventListener('click', toggleRecording);
70
+
71
+ async function toggleRecording() {
72
+ if (!isRecording) {
73
+ try {
74
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
75
+ mediaRecorder = new MediaRecorder(stream);
76
+ audioChunks = [];
77
+
78
+ mediaRecorder.ondataavailable = (e) => {
79
+ audioChunks.push(e.data);
80
+ };
81
+
82
+ mediaRecorder.onstop = async () => {
83
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
84
+ await sendAudioMessage(audioBlob);
85
+ };
86
+
87
+ mediaRecorder.start();
88
+ isRecording = true;
89
+ micButton.innerHTML = '<i class="fas fa-stop"></i>';
90
+ activityMonitor.textContent = '[ Enregistrement en cours... ]';
91
+ } catch (err) {
92
+ console.error('Erreur microphone:', err);
93
+ addMessage('assistant', "Impossible d'accéder au microphone. Vérifiez les permissions.");
94
+ }
95
+ } else {
96
+ mediaRecorder.stop();
97
+ isRecording = false;
98
+ micButton.innerHTML = '<i class="fas fa-microphone"></i>';
99
+ activityMonitor.textContent = '[ Traitement audio... ]';
100
+ }
101
+ }
102
 
103
+ async function sendAudioMessage(audioBlob) {
 
104
  try {
105
+ const formData = new FormData();
106
+ formData.append('audio', audioBlob, 'recording.wav');
107
+
108
+ const response = await fetch(`${BACKEND_URL}/api/voice`, {
109
  method: 'POST',
110
+ body: formData
 
 
 
 
 
 
 
 
111
  });
112
+
113
  const data = await response.json();
114
+ activityMonitor.textContent = '[ Rosalinda en ligne ]';
115
+
116
+ if (data.type === 'text') {
117
+ addMessage('assistant', data.content);
118
+ } else if (data.type === 'audio') {
119
+ const audio = new Audio(data.url);
120
+ audio.play();
121
+ addMessage('assistant', "Voici ma réponse audio :");
122
+ }
123
  } catch (error) {
124
+ console.error('Erreur audio:', error);
125
+ activityMonitor.textContent = '[ Erreur de connexion ]';
126
+ addMessage('assistant', "Désolé, une erreur s'est produite lors du traitement audio.");
127
  }
128
  }
129
 
130
+ // Bouton Nouvelle Tâche
131
+ document.querySelector('.menu button:nth-child(1)').addEventListener('click', async () => {
132
+ const prompt = prompt("Décrivez l'image ou la vidéo que vous souhaitez générer:");
133
  if (prompt) {
134
+ try {
135
+ activityMonitor.textContent = '[ Génération en cours... ]';
136
+ const response = await fetch(`${BACKEND_URL}/api/generate`, {
137
+ method: 'POST',
138
+ headers: {
139
+ 'Content-Type': 'application/json',
140
+ },
141
+ body: JSON.stringify({
142
+ prompt: prompt,
143
+ type: 'image' // ou 'video' si supporté
144
+ })
145
+ });
146
+
147
+ const data = await response.json();
148
+ activityMonitor.textContent = '[ Génération terminée ]';
149
+
150
+ if (data.type === 'image') {
151
+ const resultOutput = document.querySelector('.result-output');
152
+ resultOutput.innerHTML = `<img src="${data.url}" alt="Image générée" style="max-width:100%;">`;
153
+ } else if (data.type === 'video') {
154
  const resultOutput = document.querySelector('.result-output');
155
+ resultOutput.innerHTML = `<video controls style="max-width:100%;"><source src="${data.url}" type="video/mp4"></video>`;
156
  }
157
+ } catch (error) {
158
+ console.error('Erreur génération:', error);
159
+ activityMonitor.textContent = '[ Erreur de génération ]';
160
+ }
161
  }
162
  });
163
 
164
+ console.log("Interface Espace Codage chargée avec intégration backend complète.");
style.css CHANGED
@@ -107,12 +107,16 @@ body, html {
107
  flex: 1;
108
  padding: 10px;
109
  }
110
- .chat-input button {
111
  background: #ddd;
112
  border: none;
113
  padding: 10px;
114
  cursor: pointer;
115
  }
 
 
 
 
116
  /* Colonne 3 */
117
  .output {
118
  width: 35%;
 
107
  flex: 1;
108
  padding: 10px;
109
  }
110
+ .chat-input button:not(voice-control button) {
111
  background: #ddd;
112
  border: none;
113
  padding: 10px;
114
  cursor: pointer;
115
  }
116
+
117
+ voice-control {
118
+ margin-left: auto;
119
+ }
120
  /* Colonne 3 */
121
  .output {
122
  width: 35%;