File size: 20,057 Bytes
a41ca00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0f1b9e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a41ca00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
let mapEnabled = false; // Flag to track if mapping is enabled
let spotifyEnabled = false; // Flag to track if spotify is enabled
startNewChat();

function sendMessage() {
    // Hide sample questions buttons
    hideAdditionalButtons();

    // Determine route based on Map and Spotify flags
    if (mapEnabled) {
        // If mapping is enabled, handle mapping functionality
        handleMapping()
    } else if (spotifyEnabled) {
        // If spotify is enabled, handle spotify functionality
        var userInput = document.getElementById("user-input").value.trim();
        if (userInput !== "") {
            // Pass user input to Python Flask for processing
            sendSpotifyRequest(userInput);
        } else {
            updateAndDisplayMessage("Please enter a song title or artist.", false);
        }
    } else {
        var userInput = document.getElementById("user-input").value.trim();
        sendRegularMessage(userInput)
    }
    // Clear input field
    document.getElementById("user-input").value = "";
}


// ============================== Spotify ==============================
function toggleSpotify(){
    hideAdditionalButtons();
    spotifyEnabled = !spotifyEnabled
    mapEnabled = false;
    // Update the appearance of the buttons
    updateButtons(spotifyEnabled,mapEnabled)

    if (spotifyEnabled) {
        updateAndDisplayMessage("Please enter a song title or artist.", false);
    } else {
        updateAndDisplayMessage("Spotify turned off.", false);
    }

}
function sendSpotifyRequest(musicRequest) {
    // Display user's message immediately
    displayMessage(musicRequest, true);

    // Send user's message and selected language to server
    fetch('/handle_spotify', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        body: JSON.stringify({ song: musicRequest })
    })
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error('Network response was not ok.');
        }
    })
    .then(responseData => {
        // Display Spotify results
        displaySpotifyResults(responseData)
        console.log("Attempting to display Spotify results");
    })
    .catch(error => {
        console.error('Error:', error);
    });
}
function displaySpotifyResults(results) {
    updateAndDisplayMessage("Here are the top 5 results for this query:");
    var chatList = document.querySelector(".chat");
    results.forEach(track => {
        var messageElement = document.createElement("li");
        messageElement.className = "message-music";

        // Create and append image element
        var imageElement = document.createElement("img");
        imageElement.src = track.image;
        imageElement.className = "play-btn";
        imageElement.dataset.id = track.preview_url; // Use preview URL as track ID
        imageElement.addEventListener("click", play);
        messageElement.appendChild(imageElement);

        // Create and append text content (track name and artist)
        var textElement = document.createElement("span");
        textElement.textContent = track.name + ' - ' + track.artist;
        messageElement.appendChild(textElement);

        chatList.appendChild(messageElement);
    });
}

function play() {
    const previewUrl = this.getAttribute('data-id');
    const player = document.getElementById('player');
    player.innerHTML = '';
    
    if (previewUrl && previewUrl !== '') {
        const audio = document.createElement('audio');
        audio.controls = true;
        audio.src = previewUrl;
        player.appendChild(audio);
        audio.play();
        audio.addEventListener('ended', function() {
            audio.currentTime = 0; // Reset audio to the beginning
            audio.play(); // Restart playback
        });
    } else {
        player.innerHTML = 'No preview available';
    }
}


// ============================== Mapping ==============================
function toggleMap() {
    hideAdditionalButtons();
    mapEnabled = !mapEnabled; // Toggle the flag
    spotifyEnabled = false;
    updateButtons(spotifyEnabled,mapEnabled)
    // Display message in the chat area based on the state
    if (mapEnabled) {
        addLocationDropDown("start_location", false, "Select Starting Location: ");
        addLocationDropDown("end_location", false, "Select Ending Location: ");
    } else {
        updateAndDisplayMessage("Mapping turned off.", false);
    }
}
function addLocationDropDown(idAndName, isUserMessage, location_string) {
    var chatList = document.querySelector(".chat");

    // Create message element
    var messageElement = document.createElement("li");
    messageElement.className = "message";

    // Create label for the drop down menu
    var dropdownLabel = document.createElement("label");
    dropdownLabel.setAttribute("for", idAndName);
    dropdownLabel.textContent = location_string;

    // Add elements to the html
    messageElement.appendChild(dropdownLabel);
    chatList.appendChild(messageElement);

    var dropdown = document.createElement("select");
    dropdown.setAttribute("id", idAndName);
    dropdown.setAttribute("name", idAndName);
    dropdown.className = "location-dropdown";

    var locations = {
        "42 Langguth Road":"42 Langguth Road, West Langguth Road, 06824 Fairfield, Connecticut, United States",
        "Kelley Center":"Aloysius P. Kelley Center, Loyola Drive, 06824 Fairfield, United States",
        "Alumni Hall Sports Arena":"Alumni Hall Sports Arena, Leeber Road, 06824 Fairfield, Connecticut, United States",
        "Alumni House":"Alumni House, Stonkas Road, 06824 Fairfield, United States",
        "Alumni Softball Field":"Alumni Softball Field, McCormick Road, 06824 Fairfield, United States",
        "Barlow Field":"Barlow Field, Barlow Road, 06824 Fairfield, United States",
        "Barone Campus Center":"Barone Campus Center, Loyola Drive, 06824 Fairfield, United States",
        "Bellarmine Hall":"Bellarmine Hall, Fitzgerald Way, 06824 Fairfield, United States",
        "Campion Hall":"Campion Hall, McCormick Road, 06824 Fairfield, United States",
        "Canisius Hall":"Canisius Hall, East Langguth Road, 06824 Fairfield, Connecticut, United States",
        "Center for Nursing and Health Studies":"Center for Nursing and Health Studies, McInnes Road, 06824 Fairfield, United States",
        "Charles F Dolan School of Business":"Charles F Dolan School of Business, Bellarmine Road, 06824 Fairfield, CT, United States",
        "Claver Hall":"Claver Hall, Mahan Road, 06824 Fairfield, United States",
        "Conference Center at Fairfield U":"Conference Center at Fairfield University, Walters Way, 06824 Fairfield, United States",
        "David J Dolan House":"David J Dolan House, Mooney Road, 06824 Fairfield, CT, United States",
        "DiMenna-Nyselius Library":"DiMenna-Nyselius Library, McInnes Road, 06824 Fairfield, United States",
        "Donnarumma Hall":"Donnarumma Hall, East Langguth Road, 06824 Fairfield, Connecticut, United States",
        "Egan Chapel of Saint Ignatius Lo":"Egan Chapel of Saint Ignatius Loyola, Bellarmine Road, 06824 Fairfield, United States",
        "Faber Hall":"Faber Hall, Bellarmine Road, 06824 Fairfield, United States",
        "Gonzaga Hall":"Gonzaga Hall, East Langguth Road, 06824 Fairfield, Connecticut, United States",
        "Jesuit Community Center":"Jesuit Community Center, Bellarmine Road, 06824 Fairfield, United States",
        "Jogues Hall":"Jogues Hall, McCormick Road, 06824 Fairfield, United States",
        "John C. Dolan Hall":"John C. Dolan Hall, Mooney Road, 06824 Fairfield, CT, United States",
        "Kelley Center Parking Garage":"Kelley Center Parking Garage, Leeber Road, 06824 Fairfield, Connecticut, United States",
        "Kostka Hall":"Kostka Hall, Mahan Road, 06824 Fairfield, United States",
        "Lessing Field":"Lessing Field, Leeber Road, 06824 Fairfield, Connecticut, United States",
        "Loyola Hall":"Loyola Hall, McCormick Road, 06824 Fairfield, United States",
        "Mahan Road":"Mahan Road, 06824 Fairfield, United States",
        "McAuliffe Hall":"McAuliffe Hall, Ross Road, 06824 Fairfield, United States",
        "McCormick Road":"McCormick Road, 06824 Fairfield, United States",
        "Meditz Hall":"Meditz Hall, McInnes Road, 06824 Fairfield, United States",
        "Rafferty Stadium":"Rafferty Stadium, Lynch Road, 06824 Fairfield, United States",
        "Regina A Quick Center for the Arts":"Regina A Quick Center for the Arts, McInnes Road, 06824 Fairfield, CT, United States",
        "Regis Hall":"Regis Hall, East Langguth Road, 06824 Fairfield, Connecticut, United States",
        "Rudolph F. Bannow Science Center":"Rudolph F. Bannow Science Center, McInnes Road, 06824 Fairfield, United States",
        "Student Townhouse Complex":"Student Townhouse Complex, Lynch Road, 06824 Fairfield, CT, United States",
        "The Levee":"The Levee, Lynch Road, 06824 Fairfield, CT, United States",
        "University Field":"University Field, Leeber Road, 06824 Fairfield, Connecticut, United States",
        "Walsh Athletic Center":"Walsh Athletic Center, Lynch Road, 06824 Fairfield, United States"
    };

    Object.keys(locations).forEach(function(key) {
        var option = document.createElement("option");
        option.setAttribute("value", locations[key]);
        option.textContent = key;
        dropdown.appendChild(option);
    });
    messageElement.appendChild(dropdown);
}

function handleMapping() {
    var start_location = document.getElementById("start_location").value
    var end_location = document.getElementById("end_location").value
    // Create an object with the data
    var data = {
        start_location: start_location,
        end_location: end_location
    };
    fetch('/handle_mapping', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        body: JSON.stringify(data) // Pass the data object
    })
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error('Network response was not ok.');
        }
    })
    .then(responseData => {
        // Clear display, and display map rsults
        console.log("Attempting to display mapping results");
        toggleMap();
        clearChat();
        displayMessage(responseData.message, false);
        displayMap(responseData);
    })
    .catch(error => {
        console.error('Error:', error);
    });
}
function displayMap(responseData){
    // Select the chat area
    var chatList = document.querySelector(".chat");

    // Create new message element in the chat
    var messageElement = document.createElement("li");
    messageElement.className = "message";
    chatList.appendChild(messageElement);

    // Create new map element in the message element
    var mapContainer = document.createElement("iframe");
    mapContainer.srcdoc = responseData.map_html
    messageElement.appendChild(mapContainer);
}


// ============================== Chatbot ==============================
function sendRegularMessage(userInput) {
    var languageSelect = document.getElementById("language-select");
    var selectedLanguage = languageSelect.value;

    if (userInput.trim() !== "") {
        // Display user's message immediately
        displayMessage(userInput, true);

        // Display loading message for bot response
        displayMessage("...", false);

        // Send user's message and selected language to server using fetch
        fetch('/process_message', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json;charset=UTF-8'
            },
            body: JSON.stringify({ message: userInput, language: selectedLanguage })
        })
        .then(response => {
            if (response.ok) {
                return response.json();
            } else {
                throw new Error('Network response was not ok.');
            }
        })
        .then(responseData => {
            // Update bot's response
            updateBotResponse(responseData.response);
        })
        .catch(error => {
            console.error('Error:', error);
        });

        // Clear user input field
        document.getElementById("user-input").value = "";
    }
}

// Function to check if a message contains 'code block'
function hasCodeSnippet(message) {
    return /\```(?:[^```]+)\```/g.test(message);
}

// Function to convert message to HTML with code blocks
function convertMessageToHTML(message) {
    // Handle code blocks first (before other replacements)
    const codeBlocks = [];
    message = message.replace(/```(.*?)```/gs, (match) => {
        codeBlocks.push(match);
        return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
    });
    
    
    // Convert markdown to HTML
    // Headers
    message = message.replace(/^### (.+)$/gm, '<h3>$1</h3>');
    message = message.replace(/^## (.+)$/gm, '<h2>$1</h2>');
    message = message.replace(/^# (.+)$/gm, '<h1>$1</h1>');
    
    // Bold and italic
    message = message.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
    message = message.replace(/\*(.+?)\*/g, '<em>$1</em>');
    
    // Lists
    message = message.replace(/^- (.+)$/gm, '<li>$1</li>');
    message = message.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
    
    // Line breaks
    message = message.replace(/\n/g, '<br>');
    
    // Restore code blocks
    codeBlocks.forEach((block, i) => {
        const code = block.replace(/```(.*?)```/s, '<div class="code-wrapper"><pre><code>$1</code></pre></div>');
        message = message.replace(`__CODE_BLOCK_${i}__`, code);
    });
    
    return message;
}

function updateBotResponse(botMessage) {
    // Find the loading message and replace it with the bot's response
    var loadingMessage = document.querySelector(".loading-message");
    if (loadingMessage) {
        loadingMessage.innerHTML = convertMessageToHTML(botMessage.trim());
        loadingMessage.classList.remove("loading-message");
    } else {
        // If loading message is not found, add the bot's response
        displayMessage(botMessage, false);
    }
}

function displayMessage(message, isUserMessage) {
    var chatList = document.querySelector(".chat");

    // Display user's message or bot's response
    var messageElement = document.createElement("li");
    if (hasCodeSnippet(message)){
        messageElement.innerHTML = convertMessageToHTML(message);
        messageElement.className = "message" + (isUserMessage ? " user-message" : " loading-message");
        chatList.appendChild(messageElement);
    } else {
        messageElement.innerHTML = message;
        messageElement.className = "message" + (isUserMessage ? " user-message" : " loading-message");
        chatList.appendChild(messageElement);
    }
}

// Helper function to display and update message
function updateAndDisplayMessage(message, isUserMessage){
    displayMessage(message, isUserMessage);
    updateBotResponse(message);
}


// ============================== New Chat ==============================
// Function to start new chat
function startNewChat() {
    mapEnabled = false; // Reset map flag to false
    spotifyEnabled = false; // Reset spotify flag to false
    updateButtons(spotifyEnabled,mapEnabled); // Update button highlighting
    showAdditionalButtons(); // Show the sample prompts
    clearChat();
    updateAndDisplayMessage("Hello, how can I assist you?", false);

    // Send a POST request to clear the conversation history on the server side
    fetch('/clear_history', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        }
    })
    .then(response => {
        if (response.ok) {
            console.log('Conversation history cleared.');
        } else {
            throw new Error('Failed to clear conversation history.');
        }
    })
    .catch(error => {
        console.error('Error:', error);
    });
    // Clear the audio player
    const player = document.getElementById('player');
    player.innerHTML = '';
}

// Helper function to clear chat container messages
function clearChat(){
    var chatList = document.querySelector(".chat");
    chatList.innerHTML = '';
}

// ============================== Speech Recognition ==============================
function startSpeechRecognition() {
    var recognition = new window.webkitSpeechRecognition(); // Create a new SpeechRecognition object

    recognition.lang = "en-US"; // Set language to English (United States)

    recognition.onresult = function(event) { // When speech recognition is successful
        var transcript = event.results[0][0].transcript; // Get the recognized transcript
        document.getElementById("user-input").value = transcript; // Set the transcript as user input
        sendMessage(); // Call sendMessage function to process the input
    };

    recognition.onerror = function(event) { // If there's an error in speech recognition
        console.error("Speech recognition error:", event.error);
        alert("Error occurred in speech recognition. Please try again."); // Show an error message
    };

    recognition.onstart = function() { // When speech recognition starts
        document.getElementById("record-button").classList.add("active"); // Add "active" class to record button
    };

    recognition.onend = function() { // When speech recognition ends
        document.getElementById("record-button").classList.remove("active"); // Remove "active" class from record button
    };

    recognition.start(); // Start speech recognition
}

// ============================== Instructions ==============================
const instructions = `Start Conversation: Type your message in the text box and press 'Send' to start a conversation with the chatbot.\n
Voice Input: Click 'Record Speech' to speak instead of typing. The chatbot will transcribe and respond to your voice message. \n
Language Selection: Use the dropdown menu to select your preferred language for communication with the chatbot. \n
New Chat: Click 'New Chat' to start a new conversation and clear the chat history. \n
Spotify: Click the spotify button to toggle functionality \n
Map: Click the map button to toggle mapping functionality\n`
// Function to display the instructions
function addInstructions() {
    startNewChat();
    updateAndDisplayMessage(instructions,false);
    hideAdditionalButtons();
}


// ============================== Buttons ==============================
// Function to update the spotify and map buttons
function updateButtons(spotifyEnabled,mapEnabled) {
    // Update spotify button
    const spotifyButton = document.getElementById("spotify-button");
    spotifyButton.classList.toggle("active", spotifyEnabled); // Add or remove "active" class

    // Update map button
    const mapButton = document.getElementById("map-button");
    mapButton.classList.toggle("active", mapEnabled); // Add or remove "active" class
}
// Function to hide additional buttons
function hideAdditionalButtons() {
    var additionalButtons = document.getElementById("additional-buttons");
    additionalButtons.style.display = "none";
}
// Function to show additional buttons
function showAdditionalButtons() {
    var additionalButtons = document.getElementById("additional-buttons");
    additionalButtons.style.display = "block";
}
// Function to handle sample buttons
function handleSample(button){
    const question = button.innerText.trim(); // Get the inner text of the button
    hideAdditionalButtons();
    sendRegularMessage(question);
}
// Function to allow user to press enter to submit
function handleKeyDown(event) {
    if (event.key === "Enter") {
        event.preventDefault(); // Prevents the default Enter key behavior (like adding a new line)
        sendMessage(); // Calls the sendMessage function when Enter is pressed
    }
}