You can do this by opening your virtualization software (such as VMware or VirtualBox), selecting each VM, and clicking the "Start" button.
Show more…
Please give Ace some feedback
Your feedback will help us improve your experience
Thanks for your feedback!
Start your Kali and OWASP BWA VMs.
Confirm the IP address of the OWASP BWA VM.
All future steps are to be performed from your Kali VM.
Open http://<OWASP BWA IP>/ in Firefox and select OWASP WebGoat.
If you are asked to authenticate, use the account webgoat/webgoat.
Browse to Cross-Site Scripting -> Reflected XSS Attacks.
Identify which fields are vulnerable to XSS.
Craft a script input that sets the price of each item in your Shopping Cart to $0 and the Quantity of each item to 999.
`, and observe if the script executes (i.e., if an alert box appears).', 'Step 10: Once you identify the vulnerable fields, craft a script to manipulate the shopping cart. The script should aim to set the price of each item to $0 and the quantity to 999. An example of such a script could be:\n```javascript\n\n```', 'Step 11: Input this script into the vulnerable field(s) identified in Step 9 and submit or refresh the page to see if the script executes correctly, altering the values in the shopping cart as intended.', 'Step 12: Verify the changes in the shopping cart to ensure that the script worked as expected, with all items priced at $0 and their quantities set to 999.\n\nBy following these steps, you should be able to successfully exploit a reflected XSS vulnerability in the OWASP WebGoat application to manipulate shopping cart values.']},
"textbook_answer": ``,
"transcription": `In this question, here first we have to start what? Start KALI or we can say KALI and O W A S P B W A VMS. Now we have to do what? We have to confirm the IP address. What? Confirm the IP address. Confirm IP address of the O W A S P B W A VMS. Then open what? Then open HTTP double slash O W A S P B W A V M S IP okay slash in what? In Firefox and select what? And select web got. Now we have to do what? If asked to authentication use what? Use the account that is what? That is web got slash web got. Then what we have to do? Then we have to browse to cross site scripting. Browse to what? Cross site scripting that is what? That is reflect XSS attacks. Then what we have to do? Then we have to identify what? Identify field are vulnerable to XSS. Now what we have to do? Now here for the seventh part craft a script into the set the price of each in your shopping that is what? That is craft to dollar zero and quantity of each item is what? And quantity of each item is what? Each item two nine nine nine. Now identify which field is what? Which field is vulnerable to XSS okay? And we need to inspect the source code of the page and look for the output field are not properly set as what? Look for the look for the input field that are not properly sanitized okay? So from here what we get? Once we have identified the vulnerable…`,
"curriculum_id": 44,
"source": "pdp",
"instruct_mode": false,
};
const sentencesToRenderLaTex = [];
let wasChatbotClosedPopupShown = false;
const isUserAuthenticated = false;
$('[data-toggle="tooltip"]').tooltip();
const userEvent = new UserEvent({
'apiUrl': '/ace-api/v1/userevents/',
'questionId': 99417414,
'questionType': 'ask',
'csrfToken': 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO',
});
const feedbackManager = new FeedbackManager({
thumbImage: 'https://cdn-www.numerade.com/static/icons/thumb-up-icon.f95df33b33e0.svg',
thumbFillImage: 'https://cdn-www.numerade.com/static/icons/thumb-up-filled-icon.ed8121955a51.svg',
feedbackUrl: '/ace-api/v1/feedbacks/',
csrfToken: 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO',
pdpVersion: '',
});
const speakManager = new SpeakManager({
apiUrl: '/ace-api/v1/audios/',
csrfToken: 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO',
});
const chatSettings = {
/* */
welcomeMessage: `
Hi ! Need help with
this question?
I know these concepts can sometimes be confusing, but I’ll make it simple.
Just tell me what’s on your mind!`,
welcomeMessageAiVideo: `
Hi ! Need help with
this question?
I know these concepts can sometimes be confusing, but I’ll make it simple.
Just tell me what’s on your mind!`,
chatProfileImage: `https://cdn-www.numerade.com/static/ace/ace-pointing.3010e9e58287.svg`,
userProfileImage: `https://cdn-www.numerade.com/static/ace/ace-profile.aa65e387d7d7.svg`,
typingImage: `https://cdn-www.numerade.com/static/gifs/typing.3210a534764e.png`,
excludedRegex: [
{
regex: /prompts.*:/i, // Regular expression to match "prompts" followed by ":"
excludeNextLines: true, // Exclude next lines after the match. If this is false, exclude only the current line
},
],
millisecondsBetweenWords: 100,
floatingButtonImageOpen: `https://cdn-www.numerade.com/static/ace/ace-pointing.3010e9e58287.svg`,
floatingButtonImageClose: `https://cdn-www.numerade.com/static/icons/close-x.0ceebab0a1bd.svg`,
playAudioImage: 'https://cdn-www.numerade.com/static/icons/play-audio-icon-gray.6397199f5155.svg',
stopAudioImage: 'https://cdn-www.numerade.com/static/icons/mute-audio-icon-gray.10091237464c.svg',
audioEndpointURL: '/ace-api/v1/audios/',
linksPrefix: {
'Concept Definition': 'Give me more information about',
'Common Mistakes': 'Common examples of mistake of',
'default': 'Tell me more about',
},
questionOverrides: {},
feedbackManager,
excludedMessagesFromHistory: ['exampleQuestion'],
onChatEventCallback,
removeFeedbackOnMessage: false,
sleepBetweenWords: true,
subscriptionIsActive: false,
};
chatManager = new ChatManager(chatSettings);
chatManager.showWelcomeMessage();
chatManager._renderedMessages = window.localStorage.getItem('ace_rendered_messages') || 0;
// Check API status every x minutes and update the global variable
const getAPIStatus = async () => {
const apiUrl = '/ace-api/v1/status/';
try {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`There was an error getting the API status.: ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
};
let APIStatus;
const statusCheckInterval = 2 * 60 * 1000; // x minutes
setInterval(async () => {
APIStatus = await getAPIStatus();
}, statusCheckInterval);
// Start - Upload File Implementation
const FileType = {
NO_SET: 'NO_SET',
PDF: 'PDF',
IMAGE: 'IMAGE',
};
const _uploadBtnId = "#chatbot-upload-btn";
const _dropzoneId = '#chatbot-dropzone';
let _fileType = FileType.NO_SET;
let _uniqueFileId = null;
let _imageUrl = null;
let _questionText = null;
let _questionTitle = null;
let _questionTextError = null;
let _dropzoneInput = null;
const _OCREndpoint = '/ace-api/v1/files/';
const _CSRFToken = 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO';
function setFileType() {
const uploadedFile = _dropzoneInput.files ? _dropzoneInput.files[0] : null;
if (uploadedFile.type === 'application/pdf') {
this._fileType = FileType.PDF;
} else {
this._fileType = FileType.IMAGE;
}
}
function getThumbnailBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});
};
function toBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
});
}
function OCRBase64Image(base64Data) {
_uniqueFileId = null;
return new Promise(async (resolve, reject) => {
try {
const formData = new FormData();
const cropData = {
x: 0,
y: 0,
width: 0,
height: 0
};
let naturalHeight, naturalWidth = 0;
formData.append('saveImage', 1);
formData.append('base64Data', base64Data);
formData.append('conversationId', getConversationId());
formData.append('croppedData', JSON.stringify({
left: 0,
top: 0,
width: 0,
height: 0,
}));
const response = await fetch(_OCREndpoint, {
method: 'POST',
headers: {
"X-CSRFToken": _CSRFToken,
},
body: formData,
});
if (!response.ok) {
throw new Error(`There was an error sending image data.: ${response.statusText}`);
}
let data = await response.json();
const chatbotLoadingElement = $("#chatbot-loading");
if (chatbotLoadingElement) chatbotLoadingElement.remove();
chatManager.enableMessageInput();
if (getConversationId() === 0) {
setConversationId(data.conversationId);
}
_uniqueFileId = data.uniqueFileId;
resolve(data);
} catch (error) {
reject(error);
}
});
}
async function sendFileToBackend() {
const uploadedFile = _dropzoneInput.files ? _dropzoneInput.files[0] : null;
if (!uploadedFile)
return;
const formData = new FormData();
formData.append('file', uploadedFile);
formData.append('conversationId', getConversationId())
formData.append('uniqueFileId', _uniqueFileId);
formData.append('fileUploadOrigin', 'PDP');
try {
const response = await fetch(_OCREndpoint, {
headers: {
"X-CSRFToken": _CSRFToken,
},
method: 'POST',
body: formData
});
if (!response.ok) {
console.error('Failed to upload file');
}
} catch (error) {
console.error('Failed to upload file:', error);
}
}
async function convertImageToText(file) {
const base64Data = await toBase64(file);
let imageUrl = null;
try {
const questionText = await OCRBase64Image(base64Data);
imageUrl = questionText.imageUrl;
if (questionText && questionText.hasOwnProperty('data') && questionText.data.trim() !== '') {
_questionText = questionText.data;
_questionTitle = questionText.title;
} else if (questionText && questionText.hasOwnProperty('error') && questionText.error.trim() !== '') {
_questionTextError = questionText.error;
}
sendFileToBackend(); // Send full file to backend in background
} catch (error) {
const chatbotLoadingElement = $("#chatbot-loading");
if (chatbotLoadingElement) chatbotLoadingElement.remove();
chatManager.enableMessageInput();
console.error(error);
}
return imageUrl;
}
async function _onThumbnailCallback(thumbnail) {
if (thumbnail)
chatManager.addImage(thumbnail, "", false);
chatManager.showTyping();
}
function _onSuccessCallback(title, text, isSampleQuestion) {
const messageSource = (isSampleQuestion) ? MessageSource.SAMPLE_QUESTION : MessageSource.IMAGE_OCR;
sendMessage(text, messageSource);
userEvent.send('CBT_ENT');
userEvent.send('CBT_IMAGE_PROCESSED');
}
function _onErrorCallback(error) {
sendMessage('NOT_TEXT_FOUND', MessageSource.IMAGE_OCR);
}
function resetFileInput() {
_dropzoneInput.value = '';
_fileType = FileType.NO_SET;
_uniqueFileId = null;
_imageUrl = null;
_questionText = null;
_questionTitle = null;
_questionTextError = null;
}
function showUpload() {
$(_dropzoneId).show();
}
async function sendMessageFromImage (file) {
const thumbnail = await getThumbnailBase64(file);
await _onThumbnailCallback(thumbnail);
return new Promise(async (resolve, reject) => {
const timer = setInterval(() => {
if (_questionText || _questionTextError) {
clearInterval(timer);
if (_questionText) {
_onSuccessCallback(_questionTitle, _questionText, false);
resetFileInput();
_questionTitle = null;
_questionText = null;
_questionTextError = null;
resolve();
} else if (_questionTextError) {
_onErrorCallback(_questionTextError);
resetFileInput();
_questionTitle = null;
_questionText = null;
_questionTextError = null;
reject();
}
}
}, 100);
});
}
_dropzoneInput = document.querySelector(`${_dropzoneId} input[type=file]`);
$(_uploadBtnId).on('click', () => {
_dropzoneInput.click();
});
$(_dropzoneInput).on('change', async (event) => {
const file = event.target.files[0];
const allowedImageTypes = ['image/jpeg', 'image/png', 'image/webp'];
if (file.size > MAX_FILE_UPLOADSIZE) {
chatManager.addError('Sorry, Ace can only process images less than 5 MBs, please try again with a different image.');
}
else if (!allowedImageTypes.includes(file.type)) {
chatManager.addError('This file type is not supported. Please upload a jpg, png or webp file.')
}
else {
setFileType(); // analog to chatbot-landing-v2 showPreview()
userEvent.send('CBT_BTN_GALLERY');
chatManager.showTyping();
chatManager.disableMessageInput();
_imageUrl = await convertImageToText(file); // Convert image to text
sendMessageFromImage(file);
userEvent.send('CBT_IMAGE_UPLOADED');
}
});
// End - Upload File Implementation
/* Functions */
let trustpilotModalCalled = false;
function trustpilotModal() {
// Shows Trustpilot feedback modal after five messages
const userMessageCount = $('.chatbot__question__text').length;
if (!trustpilotModalCalled && userMessageCount === 5) {
// Ensures we have the Trustpilot modal and its functions loaded
if (typeof showTrustpilotModal !== 'undefined' && typeof showTrustpilotModal === 'function') {
trustpilotModalCalled = true;
setTimeout(showTrustpilotModal, 300, "ACE");
}
}
}
function onChatEventCallback(event, {sentence, messageId, sentenceId, type}) {
if (event === ChatEvent.OPEN_POPUP) {
renderLaTex('chatbot-pinned-text');
userEvent.send('CBT_CLK');
hideWelcomePopup();
hideClosePopup();
} else if (event === ChatEvent.CLOSE_POPUP) {
userEvent.send('CBT_XOUT');
showClosePopup();
} else if (event === ChatEvent.DISPLAY_SENTENCE) {
if (type === MessageType.ANSWER || type === MessageType.QUESTION) {
renderLaTex(messageId);
}
} else if (event === ChatEvent.DISPLAY_MESSAGE) {
renderLaTex(messageId);
window.localStorage.setItem('ace_rendered_messages', chatManager._renderedMessages);
trustpilotModal();
} else if (event === ChatEvent.UPDATE_PINNED_QUESTION) {
renderLaTex('chatbot-pinned-text');
} else if (event === ChatEvent.BUTTON_CLICK || event === ChatEvent.LINK_CLICK) {
if (!this.stoppedRendering()) {
const source = getSourceFromEventType(event);
sendMessage(sentence, source);
userEvent.send(sentence);
} else {
showSubRegModal();
}
} else if (event === ChatEvent.PLAY_AUDIO) {
speakManager.enableAudio();
userEvent.send('CBT_SON');
} else if (event === ChatEvent.STOP_AUDIO) {
speakManager.disableAudio();
userEvent.send('CBT_SOFF');
} else if (event === ChatEvent.SEND_MESSAGE) {
sendMessage(sentence, MessageSource.USER);
userEvent.send('CBT_ENT');
}
}
function removeHtmlAndEmojis(text) {
const emojiRegex = /[\uD800-\uDFFF]|\uD83C[\uDDE0-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEFF]|\uD83E[\uDD00-\uDDFF]/g;
const htmlRegex = /(<([^>]+)>)/ig;
return text.replace(emojiRegex, '').replace(htmlRegex, '');
}
function getSourceFromEventType(event) {
let source;
if (event === ChatEvent.BUTTON_CLICK) {
source = MessageSource.BUTTON;
} else if (event === ChatEvent.LINK_CLICK) {
source = MessageSource.LINK;
} else {
source = MessageSource.USER;
}
return source;
}
function showClosePopup() {
if (!wasChatbotClosedPopupShown) {
const popup = document.querySelector('#chatbot-onclose-popup');
if (popup) popup.style.display = 'flex';
wasChatbotClosedPopupShown = true;
}
}
function hideClosePopup() {
const popup = document.querySelector('#chatbot-onclose-popup');
if (popup) popup.style.display = 'none';
}
function waitForMathJaxHub(callback) {
if (typeof MathJax !== 'undefined') {
callback();
} else {
document.addEventListener('readystatechange', function() {
if (typeof MathJax !== 'undefined') {
callback();
}
});
}
}
function renderLaTex(id) {
const element = document.getElementById(id);
const elementHTML = (typeof element !== 'undefined' && element !== null) ? element.innerHTML : '';
if (!hasLatexExpression(elementHTML) || sentencesToRenderLaTex.includes(element))
return;
sentencesToRenderLaTex.push(element);
if (sentencesToRenderLaTex.length == 1)
renderLaTexList();
}
function renderLaTexList() {
waitForMathJaxHub(function() {
if (sentencesToRenderLaTex.length == 0)
return;
const firstElement = sentencesToRenderLaTex[0];
MathJax.typesetPromise([firstElement]).then(() => {
// Check if the element was updated in the DOM
if ($(`#${firstElement.id}`).html() != $(firstElement).html()) {
$(`#${firstElement.id}`).html($(firstElement).html())
}
// Check the LaTex notation width, and fix the issue if the width is 0
const mathElement = document.querySelector(`#${firstElement.id} .MathJax .math`);
const mathContentElement = document.querySelector(`#${firstElement.id} .MathJax .math span span`);
if (mathElement && mathContentElement && parseInt(mathElement.style.width) == 0) {
const mathContentWidth = mathContentElement.getClientRects()[0].width;
mathElement.style.width = `${mathContentWidth}px`;
}
const mathJaxSpans = document.querySelectorAll('.chatbot .MathJax span');
mathJaxSpans.forEach(span => {
if (parseFloat(span.style.verticalAlign) < -1) {
span.style.verticalAlign = 'middle';
}
});
})
.catch((error) => {
setTimeout(() => {
const errorId = `#${message[1].MathJax.error?.inputID}-Frame`;
const errorElement = document.querySelector(errorId);
if (!errorElement)
return;
const sentenceId = errorElement.parentElement.id;
renderLaTex(sentenceId);
}, 300);
});
sentencesToRenderLaTex.shift();
renderLaTexList();
});
}
function hasLatexExpression(html) {
if (!html)
return false;
html = html.trim();
const regex = /\\\(.*?\\\)|\\\[(.|\n)*?\\\]|\\begin\{([^}]*)\}((.|\n)*?)\\end\{\1\}|\$([^$]+)\$|MathJax/igm;
return regex.test(html);
}
function getRandomId() {
return (Math.floor(Math.random() * 1000)).toString();
}
async function getQuestionData(questionId, type) {
const apiUrl = '/ace-api/v1/questions/';
return new Promise((resolve, reject) => {
$.ajax({
url: apiUrl,
type: 'POST',
data: {
'question_id': questionId,
'type': type,
'csrfmiddlewaretoken': 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO',
},
success: data => {
resolve(data);
},
error: error => {
reject(error);
}
});
});
}
function saveMessages(assistantMessage = '', responseTime = 0, source=MessageSource.USER, metadata={}) {
const lastQuestion = chatManager.getLastQuestion();
const apiUrl = '/ace-api/v1/messages/';
$.ajax({
url: apiUrl,
type: 'POST',
data: {
'user_message': lastQuestion.sentence,
'assistant_message': assistantMessage,
'response_time': responseTime,
'conversation_id': getConversationId(),
'metadata': JSON.stringify(metadata),
'question_url': '/ask/question/start-your-kali-and-owasp-bwa-vms-confirm-the-ip-address-of-the-owasp-bwa-vm-all-future-steps-are-to-be-performed-from-your-kali-vm-open-http-owasp-bwa-ip-in-firefox-and-select-owasp-webgoat-58232/',
'csrfmiddlewaretoken': 'tlyEOJpmAm7VsulAQkv8yTtnuYEjPQPOCy50VdQvLDYCEt6Woqtb3s1mJAcl03SO',
'source': source,
'message_ace_version': '',
'ask_question_id': 99417414,
'title': `Start your Kali and OWASP BWA VMs.
Confirm the IP address of the OWASP BWA VM.
All future steps are to be performed from your Kali VM.
Open http://<OWASP BWA IP>/ in Firefox and select OWASP WebGoat.
If you are asked to authenticate, use the account webgoat/webgoat.
Browse to Cross-Site Scripting -> Reflected XSS Attacks.
Identify which fields are vulnerable to XSS.
Craft a script input that sets the price of each item in your Shopping Cart to $0 and the Quantity of each item to 999.`,
},
success: data => {
chatManager.setConversationId(data.conversation_id);
const nextAnswer = chatManager.getNextAnswer(lastQuestion.messageId);
if (nextAnswer) {
$(`#${nextAnswer.messageId}[class^="chatbot__message"]`).first().data('dbId', data.message_id); // Used for feedback
}
},
error: error => {
console.error(error);
}
});
}
async function sendMessage(userMessage, source=MessageSource.USER) {
chatManager.setIsAnswering(true);
const questionId = getRandomId();
let answerId = getRandomId();
let messageImage = null;
chatManager.addQuestion(userMessage, `question-${questionId}`, source);
const start = Date.now();
const posterUrl = "https://cdn.numerade.com/project-universal/previews/9700d582-4f0c-4c89-8665-ddf41a5a9b78.jpg";
const duration = '01:53';
const animationUrl = posterUrl;
const videoUrl = 'https://cdn.numerade.com/project-universal/encoded/afbb184e-e950-4c5b-b26c-7f2ba082c28f.mp4?Expires=1782422996&Signature=f-iuo3F7pKI11~Dz0iSSJgRScTKlKxPFaEleAORFBkuM7odZCVORZDZuI6MHzbcIYWKx2yq3XxL5nqeWMicpnRy5sa7Lw1ozC1zIVKhxQMbvPQ3hbjihnZOjb1rTZ0jDgkrtt2LYQA-2BYLPzL0og0ZmHR6kPqJ2le6cFx59dPjPIsdVoGKQ4VlGDIMQvg0fDF3769Fa1y64cpZ106AOju8Qb-QtJXpbuK3910jNCP2wr2yc~avluaSRjZE2t3LG9Tj4kDQKLi~oQTce0GdX2KG~dvj36Mp-4s-MoXcqAEo-iM~5oyFmPA5ahk3cHJCXelpfdIxM53iiGnDxnPdHZA__&Key-Pair-Id=K212LANSMWDVO6';
setTimeout(() => {
if (!chatManager.messageExists(`answer-${answerId}`)) {
chatManager.showTyping();
}
}, 300);
// If the API is down, show an error message
if ((typeof APIStatus !== 'undefined') && (await APIStatus.status !== 200)) {
chatManager.addError("You have reached the limit of messages per day. Please try again in few hours.");
setTimeout(() => {
chatManager.setIsAnswering(false);
chatManager.hideTyping();
}, 300);
return;
}
// If the message is comming from Image OCR update the request parameters
let extraParamsOCRRequest = {}
if (source === MessageSource.IMAGE_OCR || source === MessageSource.SAMPLE_QUESTION) {
messageImage = _imageUrl;
requestBodyData['source'] = 'landing_ocr';
requestBodyData['image_url'] = _imageUrl;
requestBodyData['step_by_step_json'] = [];
requestBodyData['question_texts'] = userMessage;
extraParamsOCRRequest = {'messageSource': 'OCR'};
}
if (!requestBodyData.hasOwnProperty('images'))
requestBodyData['images'] = [];
requestBodyData['images'].push(messageImage);
// If this is true, 'subject' field will be added to the response
const requestSubjectDetection = (
[MessageSource.USER, MessageSource.IMAGE_OCR, MessageSource.SAMPLE_QUESTION].includes(source)
);
const apiUrl = 'https://www.numerade.com/chat/v1';
const body = JSON.stringify({
"messages": chatManager.getMessagesHistory(),
...requestBodyData,
...extraParamsOCRRequest,
"subject": requestSubjectDetection,
});
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body
});
if (!response.ok) {
chatManager.addError('Sorry, there was a connection issue, please try again.');
const metadata = {
error: `There was an error sending the message. ${response.statusText}}`,
}
saveMessages('', 0, source, metadata);
throw new Error(`There was an error sending the message.: ${response.statusText}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let assistantMessage = '';
let currentChunk = '';
let currentSentence = '';
let isLaTex = false;
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split("\n");
lines.forEach(async line => {
line = line.trim();
if (line) {
const lineObj = JSON.parse(line);
let content;
if (lineObj?.search_result) {
const questionId = lineObj?.search_result?.question_id;
const questionType = lineObj?.search_result?.type;
const metadata = {
'question_id': questionId,
'question_type': questionType,
}
await getQuestionData(questionId, questionType)
.then(questionData => {
assistantMessage += questionData.text;
const videoEmbedData = {
slug: questionData.slug,
lazyLoadUrl: 'https://cdn-www.numerade.com/static/lazyload.95c829fcfb1f.svg',
videoUrl: questionData.video_url,
posterUrl: questionData.poster_url,
duration: questionData.duration,
animationUrl: questionData.animation_url,
questionType,
text: questionData.text,
}
const videoEmbed = new VideoEmbed(videoEmbedData);
// Update the context with this new question data
requestBodyData.question_texts = questionData.text;
requestBodyData.step_by_step_json = questionData.step_by_step_json;
requestBodyData.textbook_answer = questionData.textbook_answer;
requestBodyData.transcription = questionData.transcription;
chatManager.addAnswer(videoEmbed.getHtml(), `answer-${answerId}`);
chatManager.updatePinnedQuestion(questionData.text);
const responseTime = (Date.now() - start) / 1000;
saveMessages(assistantMessage, responseTime, source, metadata);
})
.catch (error => {
chatManager.addError('Sorry, there was an error getting the suggested video, please try again.');
metadata['error'] = `Sorry, there was an error getting the suggested video.`;
const responseTime = (Date.now() - start) / 1000;
saveMessages('', responseTime, source, metadata);
throw new Error('Sorry, there was an error getting the suggested video.');
});
} else if (lineObj?.assistant_message_delta) {
content = lineObj?.assistant_message_delta?.delta;
if (content) {
if (content == '\r') {
chatManager.addAnswer(currentSentence, `answer-${answerId}`, getRandomId());
currentSentence = '';
answerId = getRandomId();
}
content = content.replaceAll('$$', '$');
assistantMessage += content;
Array.prototype.forEach.call(content, function(ch, index) {
currentChunk += ch;
currentSentence += ch;
if ((['\n',' ','.',','].includes(ch)) && currentChunk != '\n' && currentChunk != '\n\n' ) {
currentChunk = '';
}
let previousCh = (content.length > 1) ? content[index-1] : '';
let nextCh = (content.length > index) ? content[index + 1] : '';
if ((ch === '$' && nextCh == '$') || (ch === '$' && previousCh != '$' && nextCh != '$')) {
isLaTex = !isLaTex;
}
previousCh = (currentSentence.length > 1) ? currentSentence[currentSentence.length-2] : '';
if ((ch === '[' || ch === '(') && previousCh === '\\') {
isLaTex = true;
}
if ((ch === ']' || ch === ')') && previousCh === '\\') {
isLaTex = false;
}
// Remove ++followup_question++ and split in two answers
if (currentSentence.includes('++followup_question++')) {
const regex = /\+\+followup_question\+\+?(:|\s*|\n|W*)/gm;
currentSentence = currentSentence.replace(regex, '');
currentSentence = currentSentence.replaceAll('\n', '').trim();
answerId = getRandomId();
}
if (!isLaTex && ['\n','.'].includes(ch) && currentSentence != '\n' && currentSentence != '\n\n' ) {
/* STU-1282 Disable audio for now
let sentenceId = speakManager.addToSpeakList(`answer-${answerId}`, currentSentence);
*/
let sentenceId;
currentSentence = currentSentence.replaceAll('\n\n\n', '\n\n').replaceAll('\n', '
')
if (sentenceId === undefined) {
// Prevent duplicate sentence ids, which causes multiple empty lines.
sentenceId = getRandomId();
}
chatManager.addAnswer(currentSentence, `answer-${answerId}`, sentenceId)
currentSentence = '';
}
});
}
}
}
});
}
if (currentSentence != '') {
/* STU-1282 Disable audio for now
let sentenceId = speakManager.addToSpeakList(`answer-${answerId}`, currentSentence);
*/
let sentenceId = getRandomId();
currentSentence = currentSentence.replaceAll('\n\n\n', '\n\n').replaceAll('\n', '
');
if (sentenceId === 0 && $(`#answer-${answerId}-sentence-${sentenceId}`).length > 1) {
sentenceId = getRandomId();
}
chatManager.addAnswer(currentSentence, `answer-${answerId}`, sentenceId)
}
try {
if (assistantMessage != '') {
const responseTime = (Date.now() - start) / 1000;
saveMessages(assistantMessage, responseTime, source);
}
} catch (error) {
console.error('Error speaking the text', error);
}
chatManager.setIsAnswering(false);
} catch (error) {
chatManager.addError('Sorry, there was an error processing the message, please try again.');
const responseTime = (Date.now() - start) / 1000;
saveMessages('', responseTime, source, {error: error});
throw new Error(JSON.stringify(error))
chatManager.setIsAnswering(false);
}
}
/* Actions */
$('.chatbot-btn').on('click', (event) => {
chatManager.togglePopup();
const btnId = event.target.id;
if (btnId == 'livechat-button') {
userEvent.send('CBT_CLKBTN_1');
} else if (btnId == 'livechat-button-2') {
userEvent.send('CBT_CLKBTN_2');
}
});
$('#chatbot-welcome-popup-start').on('click', () => {
chatManager.togglePopup();
userEvent.send('CBT_CLKBTN_START');
});
// Fix z-index of Chatbot when menu was opened
$('.navbar-toggler').on('click', () => {
setTimeout(() => {
if ($('.navbar-toggler').hasClass('collapsed')) {
$('.chatbot').css('z-index', '1040');
} else {
$('.chatbot').css('z-index', '1000');
}
}, 200);
});
function showSubRegModal() {
$(isUserAuthenticated ? '#subscribe-modal' : '#register-modal').modal('show');
// userEvent.send();
document.getElementById('chatbot').style.zIndex = '1000';
};
document.addEventListener('click', event => {
if (event.target?.classList?.contains('customContinueButton')) showSubRegModal();
});
function setCookie(name, value, days) {
const expires = new Date();
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/`;
};
function getCookie(name) {
const cookieName = `${name}=`;
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.indexOf(cookieName) === 0) {
return decodeURIComponent(cookie.substring(cookieName.length));
}
}
return null;
};
if (getCookie('acechat-welcome-popup') != 'dismissed') {
$('#chatbot-welcome-popup').show();
if (document.getElementById('chatbot-welcome-popup')) $('#chatbot-floating-btn').fadeOut();
}
function hideWelcomePopup() {
$('#chatbot-welcome-popup').fadeOut();
$('#chatbot-floating-btn').fadeIn();
setCookie('acechat-welcome-popup', 'dismissed', 365);
}
$('.dismiss-button, #chatbot-welcome-popup-start').click(() => {
hideWelcomePopup();
});
document.acechat_explain_step = (step, houdini=false) => {
chatManager.togglePopup();
sendMessage('Get more help with step '+step);
if (houdini) {
userEvent.send('CBT_BTN_HOUDINI');
} else {
userEvent.send('CBT_BTN_AI_VIDEO');
}
}
// Check API status and update the global variable
APIStatus = await getAPIStatus();
});