anshharora commited on
Commit
6556191
·
verified ·
1 Parent(s): 777758b

Update static/script.js

Browse files
Files changed (1) hide show
  1. static/script.js +263 -259
static/script.js CHANGED
@@ -1,260 +1,264 @@
1
- class ChatBot {
2
- constructor() {
3
- this.voiceEnabled = false;
4
- this.isListening = false;
5
- this.synthesis = window.speechSynthesis;
6
- this.recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
7
- this.currentUtterance = null;
8
- this.isPaused = false;
9
- this.audioQueue = [];
10
- this.mediaRecorder = null;
11
- this.audioChunks = [];
12
- this.isRecording = false;
13
-
14
- this.setupRecognition();
15
- this.setupEventListeners();
16
- }
17
-
18
- setupRecognition() {
19
- this.recognition.continuous = true;
20
- this.recognition.interimResults = true;
21
- this.recognition.lang = 'en-US';
22
-
23
- this.recognition.onstart = () => {
24
- this.isListening = true;
25
- this.toggleVoiceInputClass(true);
26
- };
27
-
28
- this.recognition.onend = () => {
29
- this.isListening = false;
30
- this.toggleVoiceInputClass(false);
31
- };
32
-
33
- this.recognition.onerror = (event) => {
34
- console.error('Speech recognition error:', event.error);
35
- this.isListening = false;
36
- this.toggleVoiceInputClass(false);
37
- };
38
-
39
- this.recognition.onresult = (event) => {
40
- let finalTranscript = '';
41
- let interimTranscript = '';
42
-
43
- for (let i = event.resultIndex; i < event.results.length; i++) {
44
- const transcript = event.results[i][0].transcript;
45
- if (event.results[i].isFinal) {
46
- finalTranscript += transcript + ' ';
47
- } else {
48
- interimTranscript += transcript;
49
- }
50
- }
51
-
52
- const input = document.getElementById('messageInput');
53
- input.value = finalTranscript + interimTranscript;
54
- };
55
- }
56
-
57
- setupEventListeners() {
58
- // Send button click event
59
- document.getElementById('sendMessage').addEventListener('click', () => this.handleSendMessage());
60
-
61
- // Voice input button
62
- document.getElementById('voiceInput').addEventListener('mousedown', () => {
63
- this.startRecording();
64
- });
65
-
66
- document.getElementById('voiceInput').addEventListener('mouseup', () => {
67
- this.stopRecording();
68
- });
69
-
70
- // Input field key events
71
- document.getElementById('messageInput').addEventListener('keydown', (e) => {
72
- if (e.key === 'Enter' && !e.shiftKey) {
73
- e.preventDefault();
74
- this.handleSendMessage();
75
- }
76
- });
77
-
78
- // Message speaker button click event
79
- document.addEventListener('click', (e) => {
80
- if (e.target.closest('.message-speaker')) {
81
- const messageContent = e.target.closest('.message-content');
82
- const text = messageContent.textContent;
83
- if (this.isPaused) {
84
- this.resumeSpeaking();
85
- } else {
86
- this.stopSpeaking();
87
- this.speak(text);
88
- }
89
- }
90
- });
91
- }
92
-
93
- async startRecording() {
94
- try {
95
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
96
- this.mediaRecorder = new MediaRecorder(stream);
97
- this.audioChunks = [];
98
- this.isRecording = true;
99
-
100
- this.mediaRecorder.ondataavailable = (event) => {
101
- this.audioChunks.push(event.data);
102
- };
103
-
104
- this.mediaRecorder.onstop = async () => {
105
- const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
106
- await this.sendAudioToServer(audioBlob);
107
- stream.getTracks().forEach(track => track.stop());
108
- };
109
-
110
- this.mediaRecorder.start();
111
- this.toggleVoiceInputClass(true);
112
- } catch (error) {
113
- console.error('Error starting recording:', error);
114
- }
115
- }
116
-
117
- stopRecording() {
118
- if (this.mediaRecorder && this.isRecording) {
119
- this.mediaRecorder.stop();
120
- this.isRecording = false;
121
- this.toggleVoiceInputClass(false);
122
- }
123
- }
124
-
125
- async sendAudioToServer(audioBlob) {
126
- const formData = new FormData();
127
- formData.append('audio', audioBlob);
128
-
129
- try {
130
- const response = await fetch('/api/voice', {
131
- method: 'POST',
132
- body: formData
133
- });
134
-
135
- if (!response.ok) throw new Error('Failed to send audio');
136
-
137
- const data = await response.json();
138
- if (data.text) {
139
- document.getElementById('messageInput').value = data.text;
140
- }
141
- if (data.response) {
142
- this.addMessage(data.response, 'bot');
143
- if (this.voiceEnabled) {
144
- this.speak(data.response);
145
- }
146
- }
147
- } catch (error) {
148
- console.error('Error sending audio:', error);
149
- this.addMessage('Sorry, there was an error processing your voice input.', 'bot');
150
- }
151
- }
152
-
153
- handleSendMessage() {
154
- const input = document.getElementById('messageInput');
155
- const message = input.value.trim();
156
- if (message) {
157
- this.stopSpeaking();
158
- this.sendMessage(message);
159
- input.value = '';
160
- }
161
- }
162
-
163
- async sendMessage(message) {
164
- this.addMessage(message, 'user');
165
- this.showTypingIndicator();
166
-
167
- try {
168
- const response = await fetch('/api/chat', {
169
- method: 'POST',
170
- headers: { 'Content-Type': 'application/json' },
171
- body: JSON.stringify({ message })
172
- });
173
-
174
- if (!response.ok) throw new Error('Failed to send message');
175
-
176
- const data = await response.json();
177
- this.removeTypingIndicator();
178
- this.addMessage(data.response, 'bot');
179
-
180
- if (this.voiceEnabled) {
181
- this.speak(data.response);
182
- }
183
- } catch (error) {
184
- console.error('Error:', error);
185
- this.removeTypingIndicator();
186
- this.addMessage('Sorry, there was an error processing your request.', 'bot');
187
- }
188
- }
189
-
190
- speak(text) {
191
- if (this.synthesis.speaking) {
192
- this.synthesis.cancel();
193
- }
194
-
195
- const utterance = new SpeechSynthesisUtterance(text);
196
- this.currentUtterance = utterance;
197
-
198
- utterance.onend = () => {
199
- this.currentUtterance = null;
200
- this.isPaused = false;
201
- if (this.audioQueue.length > 0) {
202
- const nextText = this.audioQueue.shift();
203
- this.speak(nextText);
204
- }
205
- };
206
-
207
- this.synthesis.speak(utterance);
208
- }
209
-
210
- stopSpeaking() {
211
- if (this.synthesis.speaking) {
212
- this.synthesis.cancel();
213
- this.currentUtterance = null;
214
- this.isPaused = false;
215
- this.audioQueue = [];
216
- }
217
- }
218
-
219
- toggleVoiceInputClass(isActive) {
220
- const button = document.getElementById('voiceInput');
221
- button.classList.toggle('active', isActive);
222
- }
223
-
224
- addMessage(message, sender) {
225
- const messagesContainer = document.getElementById('chatMessages');
226
- const messageDiv = document.createElement('div');
227
- messageDiv.className = `message ${sender}`;
228
-
229
- const content = document.createElement('div');
230
- content.className = 'message-content';
231
- content.textContent = message;
232
-
233
- if (sender === 'bot') {
234
- const speakerButton = document.createElement('button');
235
- speakerButton.className = 'message-speaker';
236
- speakerButton.innerHTML = '<i class="fas fa-volume-up"></i>';
237
- content.appendChild(speakerButton);
238
- }
239
-
240
- messageDiv.appendChild(content);
241
- messagesContainer.appendChild(messageDiv);
242
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
243
- }
244
-
245
- showTypingIndicator() {
246
- const indicator = document.createElement('div');
247
- indicator.className = 'message bot typing-indicator';
248
- indicator.innerHTML = '<div class="typing-dot"></div>'.repeat(3);
249
- document.getElementById('chatMessages').appendChild(indicator);
250
- }
251
-
252
- removeTypingIndicator() {
253
- const indicator = document.querySelector('.typing-indicator');
254
- if (indicator) indicator.remove();
255
- }
256
- }
257
-
258
- document.addEventListener('DOMContentLoaded', () => {
259
- window.chatBot = new ChatBot();
 
 
 
 
260
  });
 
1
+ class ChatBot {
2
+ constructor() {
3
+ this.voiceEnabled = false;
4
+ this.isListening = false;
5
+ this.synthesis = window.speechSynthesis;
6
+ this.recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
7
+ this.currentUtterance = null;
8
+ this.isPaused = false;
9
+ this.audioQueue = [];
10
+ this.mediaRecorder = null;
11
+ this.audioChunks = [];
12
+ this.isRecording = false;
13
+
14
+ this.setupRecognition();
15
+ this.setupEventListeners();
16
+ }
17
+
18
+ setupRecognition() {
19
+ this.recognition.continuous = true;
20
+ this.recognition.interimResults = true;
21
+ this.recognition.lang = 'en-US';
22
+
23
+ this.recognition.onstart = () => {
24
+ this.isListening = true;
25
+ this.toggleVoiceInputClass(true);
26
+ };
27
+
28
+ this.recognition.onend = () => {
29
+ this.isListening = false;
30
+ this.toggleVoiceInputClass(false);
31
+ };
32
+
33
+ this.recognition.onerror = (event) => {
34
+ console.error('Speech recognition error:', event.error);
35
+ this.isListening = false;
36
+ this.toggleVoiceInputClass(false);
37
+ };
38
+
39
+ this.recognition.onresult = (event) => {
40
+ let finalTranscript = '';
41
+ let interimTranscript = '';
42
+
43
+ for (let i = event.resultIndex; i < event.results.length; i++) {
44
+ const transcript = event.results[i][0].transcript;
45
+ if (event.results[i].isFinal) {
46
+ finalTranscript += transcript + ' ';
47
+ } else {
48
+ interimTranscript += transcript;
49
+ }
50
+ }
51
+
52
+ const input = document.getElementById('messageInput');
53
+ input.value = finalTranscript + interimTranscript;
54
+ };
55
+ }
56
+
57
+ setupEventListeners() {
58
+ // Send button click event
59
+ document.getElementById('sendMessage').addEventListener('click', () => this.handleSendMessage());
60
+
61
+ // Voice input button
62
+ document.getElementById('voiceInput').addEventListener('mousedown', () => {
63
+ this.startRecording();
64
+ });
65
+
66
+ document.getElementById('voiceInput').addEventListener('mouseup', () => {
67
+ this.stopRecording();
68
+ });
69
+
70
+ // Input field key events
71
+ document.getElementById('messageInput').addEventListener('keydown', (e) => {
72
+ if (e.key === 'Enter' && !e.shiftKey) {
73
+ e.preventDefault();
74
+ this.handleSendMessage();
75
+ }
76
+ });
77
+
78
+ // Message speaker button click event
79
+ document.addEventListener('click', (e) => {
80
+ if (e.target.closest('.message-speaker')) {
81
+ const messageContent = e.target.closest('.message-content');
82
+ const text = messageContent.textContent;
83
+ if (this.isPaused) {
84
+ this.resumeSpeaking();
85
+ } else {
86
+ this.stopSpeaking();
87
+ this.speak(text);
88
+ }
89
+ }
90
+ });
91
+ }
92
+
93
+ async startRecording() {
94
+ try {
95
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
96
+ this.mediaRecorder = new MediaRecorder(stream, {
97
+ mimeType: 'audio/webm' // Use webm format for better compatibility
98
+ });
99
+ this.audioChunks = [];
100
+ this.isRecording = true;
101
+
102
+ this.mediaRecorder.ondataavailable = (event) => {
103
+ if (event.data.size > 0) {
104
+ this.audioChunks.push(event.data);
105
+ }
106
+ };
107
+
108
+ this.mediaRecorder.onstop = async () => {
109
+ const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });
110
+ await this.sendAudioToServer(audioBlob);
111
+ stream.getTracks().forEach(track => track.stop());
112
+ };
113
+
114
+ this.mediaRecorder.start();
115
+ this.toggleVoiceInputClass(true);
116
+ } catch (error) {
117
+ console.error('Error starting recording:', error);
118
+ }
119
+ }
120
+
121
+ stopRecording() {
122
+ if (this.mediaRecorder && this.isRecording) {
123
+ this.mediaRecorder.stop();
124
+ this.isRecording = false;
125
+ this.toggleVoiceInputClass(false);
126
+ }
127
+ }
128
+
129
+ async sendAudioToServer(audioBlob) {
130
+ const formData = new FormData();
131
+ formData.append('audio', audioBlob, 'recording.webm'); // Specify filename with extension
132
+
133
+ try {
134
+ const response = await fetch('/api/voice', {
135
+ method: 'POST',
136
+ body: formData
137
+ });
138
+
139
+ if (!response.ok) throw new Error('Failed to send audio');
140
+
141
+ const data = await response.json();
142
+ if (data.text) {
143
+ document.getElementById('messageInput').value = data.text;
144
+ }
145
+ if (data.response) {
146
+ this.addMessage(data.response, 'bot');
147
+ if (this.voiceEnabled) {
148
+ this.speak(data.response);
149
+ }
150
+ }
151
+ } catch (error) {
152
+ console.error('Error sending audio:', error);
153
+ this.addMessage('Sorry, there was an error processing your voice input.', 'bot');
154
+ }
155
+ }
156
+
157
+ handleSendMessage() {
158
+ const input = document.getElementById('messageInput');
159
+ const message = input.value.trim();
160
+ if (message) {
161
+ this.stopSpeaking();
162
+ this.sendMessage(message);
163
+ input.value = '';
164
+ }
165
+ }
166
+
167
+ async sendMessage(message) {
168
+ this.addMessage(message, 'user');
169
+ this.showTypingIndicator();
170
+
171
+ try {
172
+ const response = await fetch('/api/chat', {
173
+ method: 'POST',
174
+ headers: { 'Content-Type': 'application/json' },
175
+ body: JSON.stringify({ message })
176
+ });
177
+
178
+ if (!response.ok) throw new Error('Failed to send message');
179
+
180
+ const data = await response.json();
181
+ this.removeTypingIndicator();
182
+ this.addMessage(data.response, 'bot');
183
+
184
+ if (this.voiceEnabled) {
185
+ this.speak(data.response);
186
+ }
187
+ } catch (error) {
188
+ console.error('Error:', error);
189
+ this.removeTypingIndicator();
190
+ this.addMessage('Sorry, there was an error processing your request.', 'bot');
191
+ }
192
+ }
193
+
194
+ speak(text) {
195
+ if (this.synthesis.speaking) {
196
+ this.synthesis.cancel();
197
+ }
198
+
199
+ const utterance = new SpeechSynthesisUtterance(text);
200
+ this.currentUtterance = utterance;
201
+
202
+ utterance.onend = () => {
203
+ this.currentUtterance = null;
204
+ this.isPaused = false;
205
+ if (this.audioQueue.length > 0) {
206
+ const nextText = this.audioQueue.shift();
207
+ this.speak(nextText);
208
+ }
209
+ };
210
+
211
+ this.synthesis.speak(utterance);
212
+ }
213
+
214
+ stopSpeaking() {
215
+ if (this.synthesis.speaking) {
216
+ this.synthesis.cancel();
217
+ this.currentUtterance = null;
218
+ this.isPaused = false;
219
+ this.audioQueue = [];
220
+ }
221
+ }
222
+
223
+ toggleVoiceInputClass(isActive) {
224
+ const button = document.getElementById('voiceInput');
225
+ button.classList.toggle('active', isActive);
226
+ }
227
+
228
+ addMessage(message, sender) {
229
+ const messagesContainer = document.getElementById('chatMessages');
230
+ const messageDiv = document.createElement('div');
231
+ messageDiv.className = `message ${sender}`;
232
+
233
+ const content = document.createElement('div');
234
+ content.className = 'message-content';
235
+ content.textContent = message;
236
+
237
+ if (sender === 'bot') {
238
+ const speakerButton = document.createElement('button');
239
+ speakerButton.className = 'message-speaker';
240
+ speakerButton.innerHTML = '<i class="fas fa-volume-up"></i>';
241
+ content.appendChild(speakerButton);
242
+ }
243
+
244
+ messageDiv.appendChild(content);
245
+ messagesContainer.appendChild(messageDiv);
246
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
247
+ }
248
+
249
+ showTypingIndicator() {
250
+ const indicator = document.createElement('div');
251
+ indicator.className = 'message bot typing-indicator';
252
+ indicator.innerHTML = '<div class="typing-dot"></div>'.repeat(3);
253
+ document.getElementById('chatMessages').appendChild(indicator);
254
+ }
255
+
256
+ removeTypingIndicator() {
257
+ const indicator = document.querySelector('.typing-indicator');
258
+ if (indicator) indicator.remove();
259
+ }
260
+ }
261
+
262
+ document.addEventListener('DOMContentLoaded', () => {
263
+ window.chatBot = new ChatBot();
264
  });