victor HF Staff commited on
Commit
e1c3a1a
·
1 Parent(s): bd6c0c0

feat: implement pure web demo with audio recording and chat functionality

Browse files
Files changed (1) hide show
  1. webui/index.html +125 -24
webui/index.html CHANGED
@@ -3,13 +3,36 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>My Web Page</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  </head>
8
- <body style="background-color: black; color: white;">
9
  <div id="svg-container"></div>
10
- <button id="play-button">play</button>
 
 
 
11
  <main>
12
- <p>Current status: listening</p>
13
  </main>
14
  </body>
15
  <script>
@@ -31,17 +54,17 @@ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
31
  const analyser = audioContext.createAnalyser();
32
  analyser.fftSize = 256;
33
 
34
- // Load audio file
35
- const audio = new Audio('/heath_ledger.mp3');
36
- const source = audioContext.createMediaElementSource(audio);
37
- source.connect(analyser);
38
- analyser.connect(audioContext.destination);
39
-
40
  // Animation variables
41
  let isAudioPlaying = false;
42
  let lastBlinkTime = 0;
43
  let eyeMovementOffset = { x: 0, y: 0 };
44
 
 
 
 
 
 
 
45
  // Idle eye animation function
46
  function animateIdleEyes(timestamp) {
47
  const leftEye = document.getElementById('left-eye');
@@ -135,23 +158,101 @@ function animate(timestamp) {
135
  // Start animation
136
  animate();
137
 
138
- // Handle audio play/pause
139
- audio.addEventListener('play', () => {
140
- isAudioPlaying = true;
141
- audioContext.resume();
142
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
- audio.addEventListener('pause', () => {
145
- isAudioPlaying = false;
146
- });
 
 
 
 
 
 
147
 
148
- audio.addEventListener('ended', () => {
149
- isAudioPlaying = false;
150
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- // Play audio (you might want to trigger this with a user interaction)
153
- document.getElementById('play-button').addEventListener('click', () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  audio.play();
155
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  </script>
157
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Mini-Omni Chat Demo</title>
7
+ <style>
8
+ body {
9
+ background-color: black;
10
+ color: white;
11
+ font-family: Arial, sans-serif;
12
+ }
13
+ #chat-container {
14
+ height: 300px;
15
+ overflow-y: auto;
16
+ border: 1px solid #444;
17
+ padding: 10px;
18
+ margin-bottom: 10px;
19
+ }
20
+ #status-message {
21
+ margin-bottom: 10px;
22
+ }
23
+ button {
24
+ margin-right: 10px;
25
+ }
26
+ </style>
27
  </head>
28
+ <body>
29
  <div id="svg-container"></div>
30
+ <div id="chat-container"></div>
31
+ <div id="status-message">Current status: idle</div>
32
+ <button id="start-button">Start</button>
33
+ <button id="stop-button" disabled>Stop</button>
34
  <main>
35
+ <p id="current-status">Current status: idle</p>
36
  </main>
37
  </body>
38
  <script>
 
54
  const analyser = audioContext.createAnalyser();
55
  analyser.fftSize = 256;
56
 
 
 
 
 
 
 
57
  // Animation variables
58
  let isAudioPlaying = false;
59
  let lastBlinkTime = 0;
60
  let eyeMovementOffset = { x: 0, y: 0 };
61
 
62
+ // Chat variables
63
+ let mediaRecorder;
64
+ let audioChunks = [];
65
+ let isRecording = false;
66
+ const API_URL = 'http://127.0.0.1:60808/chat';
67
+
68
  // Idle eye animation function
69
  function animateIdleEyes(timestamp) {
70
  const leftEye = document.getElementById('left-eye');
 
158
  // Start animation
159
  animate();
160
 
161
+ // Chat functions
162
+ function startRecording() {
163
+ navigator.mediaDevices.getUserMedia({ audio: true })
164
+ .then(stream => {
165
+ mediaRecorder = new MediaRecorder(stream);
166
+ mediaRecorder.ondataavailable = event => {
167
+ audioChunks.push(event.data);
168
+ };
169
+ mediaRecorder.onstop = sendAudioToServer;
170
+ mediaRecorder.start();
171
+ isRecording = true;
172
+ updateStatus('Recording...');
173
+ document.getElementById('start-button').disabled = true;
174
+ document.getElementById('stop-button').disabled = false;
175
+ })
176
+ .catch(error => {
177
+ console.error('Error accessing microphone:', error);
178
+ updateStatus('Error: ' + error.message);
179
+ });
180
+ }
181
 
182
+ function stopRecording() {
183
+ if (mediaRecorder && isRecording) {
184
+ mediaRecorder.stop();
185
+ isRecording = false;
186
+ updateStatus('Processing...');
187
+ document.getElementById('start-button').disabled = false;
188
+ document.getElementById('stop-button').disabled = true;
189
+ }
190
+ }
191
 
192
+ function sendAudioToServer() {
193
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
194
+ const reader = new FileReader();
195
+ reader.readAsDataURL(audioBlob);
196
+ reader.onloadend = function() {
197
+ const base64Audio = reader.result.split(',')[1];
198
+ fetch(API_URL, {
199
+ method: 'POST',
200
+ headers: {
201
+ 'Content-Type': 'application/json',
202
+ },
203
+ body: JSON.stringify({ audio: base64Audio }),
204
+ })
205
+ .then(response => response.blob())
206
+ .then(blob => {
207
+ const audioUrl = URL.createObjectURL(blob);
208
+ playResponseAudio(audioUrl);
209
+ updateChatHistory('User', 'Audio message sent');
210
+ updateChatHistory('Assistant', 'Audio response received');
211
+ })
212
+ .catch(error => {
213
+ console.error('Error:', error);
214
+ updateStatus('Error: ' + error.message);
215
+ });
216
+ };
217
+ audioChunks = [];
218
+ }
219
 
220
+ function playResponseAudio(audioUrl) {
221
+ const audio = new Audio(audioUrl);
222
+ audio.onloadedmetadata = () => {
223
+ const source = audioContext.createMediaElementSource(audio);
224
+ source.connect(analyser);
225
+ analyser.connect(audioContext.destination);
226
+ };
227
+ audio.onplay = () => {
228
+ isAudioPlaying = true;
229
+ updateStatus('Playing response...');
230
+ };
231
+ audio.onended = () => {
232
+ isAudioPlaying = false;
233
+ updateStatus('Idle');
234
+ };
235
  audio.play();
236
+ }
237
+
238
+ function updateChatHistory(role, message) {
239
+ const chatContainer = document.getElementById('chat-container');
240
+ const messageElement = document.createElement('p');
241
+ messageElement.textContent = `${role}: ${message}`;
242
+ chatContainer.appendChild(messageElement);
243
+ chatContainer.scrollTop = chatContainer.scrollHeight;
244
+ }
245
+
246
+ function updateStatus(status) {
247
+ document.getElementById('status-message').textContent = status;
248
+ document.getElementById('current-status').textContent = 'Current status: ' + status;
249
+ }
250
+
251
+ // Event listeners
252
+ document.getElementById('start-button').addEventListener('click', startRecording);
253
+ document.getElementById('stop-button').addEventListener('click', stopRecording);
254
+
255
+ // Initialize
256
+ updateStatus('Idle');
257
  </script>
258
  </html>