yasserrmd commited on
Commit
5398c25
·
verified ·
1 Parent(s): cac37fa

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +203 -42
static/index.html CHANGED
@@ -4,65 +4,226 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Voice Chat Interface</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  </head>
8
  <body>
9
- <h1>Voice Chat</h1>
10
- <button id="recordButton">Start Listening</button>
11
- <button id="generateButton">Generate Speech</button>
12
- <audio id="audioPlayer" controls></audio>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
 
 
14
  <script>
15
  let mediaRecorder;
16
  let audioChunks = [];
 
 
 
 
17
 
18
- document.getElementById("recordButton").addEventListener("click", async () => {
19
  if (!mediaRecorder || mediaRecorder.state === "inactive") {
20
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
21
- mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
22
- mediaRecorder.ondataavailable = event => audioChunks.push(event.data);
23
- mediaRecorder.onstop = async () => {
24
- const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
25
- const wavBlob = await convertWebMToWav(audioBlob);
26
- const formData = new FormData();
27
- formData.append("file", wavBlob, "recording.wav");
28
 
29
- const response = await fetch("/chat/", {
30
- method: "POST",
31
- body: formData
32
- });
33
- const audioData = await response.blob();
34
- document.getElementById("audioPlayer").src = URL.createObjectURL(audioData);
35
- };
36
- audioChunks = [];
37
- mediaRecorder.start();
38
- setTimeout(() => mediaRecorder.stop(), 5000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
  });
41
 
42
- document.getElementById("generateButton").addEventListener("click", async () => {
43
  const text = prompt("Enter text to convert to speech:");
44
  if (text) {
45
- const response = await fetch("/tts/", {
46
- method: "POST",
47
- headers: { "Content-Type": "application/json" },
48
- body: JSON.stringify({ text })
49
- });
50
- const audioData = await response.blob();
51
- document.getElementById("audioPlayer").src = URL.createObjectURL(audioData);
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
  });
54
 
55
  async function convertWebMToWav(blob) {
56
- return new Promise(resolve => {
57
- const reader = new FileReader();
58
- reader.onload = function () {
59
- const audioContext = new AudioContext();
60
- audioContext.decodeAudioData(reader.result, buffer => {
61
- const wavBuffer = audioBufferToWav(buffer);
62
- resolve(new Blob([wavBuffer], { type: "audio/wav" }));
63
- });
64
- };
65
- reader.readAsArrayBuffer(blob);
 
 
 
 
 
 
 
 
 
 
66
  });
67
  }
68
 
@@ -116,4 +277,4 @@
116
  }
117
  </script>
118
  </body>
119
- </html>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Voice Chat Interface</title>
7
+ <!-- Bootstrap CSS -->
8
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <!-- Bootstrap Icons -->
10
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
11
+ <style>
12
+ body {
13
+ background-color: #f8f9fa;
14
+ padding-top: 30px;
15
+ }
16
+ .chat-container {
17
+ max-width: 600px;
18
+ margin: 0 auto;
19
+ background-color: white;
20
+ border-radius: 12px;
21
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
22
+ padding: 25px;
23
+ }
24
+ .btn-record {
25
+ background-color: #ff4b4b;
26
+ border-color: #ff4b4b;
27
+ }
28
+ .btn-record:hover {
29
+ background-color: #e43c3c;
30
+ border-color: #e43c3c;
31
+ }
32
+ .btn-record.recording {
33
+ animation: pulse 1.5s infinite;
34
+ }
35
+ .btn-generate {
36
+ background-color: #4c6ef5;
37
+ border-color: #4c6ef5;
38
+ }
39
+ .btn-generate:hover {
40
+ background-color: #3b5bdb;
41
+ border-color: #3b5bdb;
42
+ }
43
+ .icon-spacing {
44
+ margin-right: 8px;
45
+ }
46
+ .control-label {
47
+ font-size: 0.9rem;
48
+ color: #6c757d;
49
+ margin-bottom: 8px;
50
+ }
51
+ .audio-container {
52
+ background-color: #f1f3f5;
53
+ border-radius: 8px;
54
+ padding: 15px;
55
+ margin-top: 20px;
56
+ }
57
+ audio {
58
+ width: 100%;
59
+ }
60
+ .status-indicator {
61
+ font-size: 0.9rem;
62
+ margin-top: 10px;
63
+ height: 24px;
64
+ }
65
+ @keyframes pulse {
66
+ 0% { transform: scale(1); }
67
+ 50% { transform: scale(1.05); }
68
+ 100% { transform: scale(1); }
69
+ }
70
+ </style>
71
  </head>
72
  <body>
73
+ <div class="container">
74
+ <div class="chat-container">
75
+ <h1 class="text-center mb-4">
76
+ <i class="bi bi-mic-fill text-primary"></i> Voice Chat
77
+ </h1>
78
+
79
+ <div class="row g-4">
80
+ <div class="col-md-6">
81
+ <div class="d-grid">
82
+ <p class="control-label text-center">Voice Recognition</p>
83
+ <button id="recordButton" class="btn btn-record btn-lg text-white">
84
+ <i class="bi bi-mic-fill icon-spacing"></i> Start Listening
85
+ </button>
86
+ </div>
87
+ </div>
88
+ <div class="col-md-6">
89
+ <div class="d-grid">
90
+ <p class="control-label text-center">Text to Speech</p>
91
+ <button id="generateButton" class="btn btn-generate btn-lg text-white">
92
+ <i class="bi bi-soundwave icon-spacing"></i> Generate Speech
93
+ </button>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="audio-container">
99
+ <p class="control-label mb-2">Audio Playback</p>
100
+ <audio id="audioPlayer" controls></audio>
101
+ <div id="statusMessage" class="status-indicator text-center text-secondary"></div>
102
+ </div>
103
+ </div>
104
+ </div>
105
 
106
+ <!-- Bootstrap JS Bundle -->
107
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
108
  <script>
109
  let mediaRecorder;
110
  let audioChunks = [];
111
+ const recordButton = document.getElementById("recordButton");
112
+ const generateButton = document.getElementById("generateButton");
113
+ const statusMessage = document.getElementById("statusMessage");
114
+ let recordingTimeout;
115
 
116
+ recordButton.addEventListener("click", async () => {
117
  if (!mediaRecorder || mediaRecorder.state === "inactive") {
118
+ try {
119
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
120
+ mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
 
 
 
 
 
121
 
122
+ mediaRecorder.ondataavailable = event => audioChunks.push(event.data);
123
+
124
+ mediaRecorder.onstop = async () => {
125
+ statusMessage.textContent = "Processing audio...";
126
+ recordButton.innerHTML = '<i class="bi bi-mic-fill icon-spacing"></i> Start Listening';
127
+ recordButton.classList.remove("recording");
128
+ recordButton.classList.remove("btn-danger");
129
+ recordButton.classList.add("btn-record");
130
+
131
+ try {
132
+ const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
133
+ const wavBlob = await convertWebMToWav(audioBlob);
134
+ const formData = new FormData();
135
+ formData.append("file", wavBlob, "recording.wav");
136
+
137
+ const response = await fetch("/chat/", {
138
+ method: "POST",
139
+ body: formData
140
+ });
141
+
142
+ if (response.ok) {
143
+ const audioData = await response.blob();
144
+ document.getElementById("audioPlayer").src = URL.createObjectURL(audioData);
145
+ statusMessage.textContent = "Response ready!";
146
+ } else {
147
+ statusMessage.textContent = "Error processing audio. Please try again.";
148
+ }
149
+ } catch (error) {
150
+ console.error("Error:", error);
151
+ statusMessage.textContent = "Error processing audio. Please try again.";
152
+ }
153
+ };
154
+
155
+ audioChunks = [];
156
+ mediaRecorder.start();
157
+
158
+ recordButton.innerHTML = '<i class="bi bi-stop-fill icon-spacing"></i> Listening...';
159
+ recordButton.classList.add("recording");
160
+ recordButton.classList.remove("btn-record");
161
+ recordButton.classList.add("btn-danger");
162
+ statusMessage.textContent = "Listening (5 seconds)...";
163
+
164
+ // Auto-stop after 5 seconds
165
+ recordingTimeout = setTimeout(() => {
166
+ if (mediaRecorder && mediaRecorder.state === "recording") {
167
+ mediaRecorder.stop();
168
+ }
169
+ }, 5000);
170
+ } catch (error) {
171
+ console.error("Error accessing microphone:", error);
172
+ statusMessage.textContent = "Could not access microphone. Please check permissions.";
173
+ }
174
+ } else if (mediaRecorder.state === "recording") {
175
+ // Stop recording if already recording
176
+ clearTimeout(recordingTimeout);
177
+ mediaRecorder.stop();
178
  }
179
  });
180
 
181
+ generateButton.addEventListener("click", async () => {
182
  const text = prompt("Enter text to convert to speech:");
183
  if (text) {
184
+ statusMessage.textContent = "Generating speech...";
185
+ try {
186
+ const response = await fetch("/tts/", {
187
+ method: "POST",
188
+ headers: { "Content-Type": "application/json" },
189
+ body: JSON.stringify({ text })
190
+ });
191
+
192
+ if (response.ok) {
193
+ const audioData = await response.blob();
194
+ document.getElementById("audioPlayer").src = URL.createObjectURL(audioData);
195
+ statusMessage.textContent = "Speech generated successfully!";
196
+ } else {
197
+ statusMessage.textContent = "Error generating speech. Please try again.";
198
+ }
199
+ } catch (error) {
200
+ console.error("Error:", error);
201
+ statusMessage.textContent = "Error generating speech. Please try again.";
202
+ }
203
  }
204
  });
205
 
206
  async function convertWebMToWav(blob) {
207
+ return new Promise((resolve, reject) => {
208
+ try {
209
+ const reader = new FileReader();
210
+ reader.onload = function () {
211
+ const audioContext = new AudioContext();
212
+ audioContext.decodeAudioData(reader.result)
213
+ .then(buffer => {
214
+ const wavBuffer = audioBufferToWav(buffer);
215
+ resolve(new Blob([wavBuffer], { type: "audio/wav" }));
216
+ })
217
+ .catch(error => {
218
+ console.error("Error decoding audio data:", error);
219
+ reject(error);
220
+ });
221
+ };
222
+ reader.readAsArrayBuffer(blob);
223
+ } catch (error) {
224
+ console.error("Error in convertWebMToWav:", error);
225
+ reject(error);
226
+ }
227
  });
228
  }
229
 
 
277
  }
278
  </script>
279
  </body>
280
+ </html>