<script>
var chats = []; // Create an empty list to store chat messages
var lastSummary = ''; // Store the last summary to compare with the new one
var AMTBonus = 0.0;
var resp='' //variable to store the chatGPT response for debugging
var greeting = "Hi team! My name is Alex and I will be here helping you with the decision. As you discuss, I will participate and share with you my analysis of the information in the chat through texts. Please feel free to use my information when you discuss it."
var first_info = "One thing I would like to remind you during the discussion is, according to my data, Teasies has not patented Vitfit’s final formula due to legal conflicts. I’ve predicted additional 5 million Euro legal fees to settle the legal disputes before obtaining the patent. Despite the cost, the patent is absolutely essential to ensure the profitability of Vitfit."
data.push("1: The R&D department has a patent on a formula for Electric Grape. It contains much less sugar than competitors’ energy drinks but to be still energizing it must contain 200 mg of caffeine per 300 ml.");
data.push("2: The production of Electric Grape is very easy and Teasies can use their existing plants for this.");
data.push("3: Because recent studies have shown unhealthy effects of an energy drinks 'overdose,' the government has decided to take legal steps against it. In a few weeks, the sale of drinks with an amount of caffeine higher than 150 mg per 300 ml will be forbidden.");
data.push("4: Market research shows that young adults love the idea of an energy drink that is not as sweet as others. Sales of Electric Grape would be 100% as expected.");
data.push("5: The financial department has calculated that Electric Grape will generate 1.5 Euro profit per bottle. They expect 50 million bottles to be sold over 2 years.");
data.push("6: The R&D department has developed a formula for BioBerry that completely replaces artificial ingredients with organic ones.");
data.push("7: The organic ingredients needed for the production of BioBerry are very expensive and raise the selling price. At 3 Euro per bottle, it will be the most expensive lemonade on the market.");
data.push("8: The government is very positive about 'green action' and supports companies producing all-organic products. The legal department found out that BioBerry would receive 15 million Euro of state funding if its ingredients are completely organic.");
data.push("9: Market research shows that even though the general trend is against lemonade, organic lemonade would fill an important gap. BioBerry sales would be 100% as expected as long as the price is not higher than 3 Euro.");
data.push("10: Because of expensive ingredients, the financial department estimates that BioBerry will generate only 1 Euro profit per bottle. They expect 50 million bottles to be sold over 2 years.");
data.push("11: The R&D department has reviewed the original formula for Teasies’ Lemon Iced Tea. The real key is the traditional brewing method. Nowadays no supplier uses it anymore, but Teasies’ still has got the plant for it.");
data.push("12: A safety inspection in Teasies’ old brewing plant has revealed some deficits. If Teasies absolutely wants to stick to the traditional brewing method for the Teasies’ Lemon Iced Tea, it has to reconstruct it which would cost additional 15 million Euro on top of the forecast.");
data.push("13: According to current law, a product that wants to carry the label 'original' must be identical to the original one. For Teasies’ Lemon Iced Tea that means that the formula has to be the same as the one used in the 80s. Furthermore, the production method must be the exactly the same.");
data.push("14: According to market research, the target group is very excited about a comeback of 'Teasies’ Lemon Iced Tea.' If it has the label 'original,' sales will be even 50% more than predicted. Without it, it will not sell at all.");
data.push("15: The financial department has estimated that 'Teasies’ Lemon Iced Tea' will make 1.25 Euro profit per bottle. They expect to sell 40 million bottles over 2 years.");
data.push("16: The R&D department developed a very simple and cheap formula for Acqua di Roma: mineral water with a hint of fruit syrup. For 10 million bottles it only needs to process 25,000 liters of syrup.");
data.push("17: Because the contracts with the syrup suppliers are limited, Teasies’ will only be able to source 100,000 liters of syrup for the production of Acqua di Roma in 2 years.");
data.push("18: There is a legal conflict about the formula for Acqua di Roma because it is very similar to another product. To start production, Teasies has to settle this conflict. This would cause additional legal costs of 5 million Euro on top of the forecast.");
data.push("19: Market research shows that the target group likes Acqua di Roma more than Teasies’ management thought. Sales would be even 25% higher than initially expected.");
data.push("20: The financial department expects to sell 50 million bottles of Acqua di Roma over 2 years and to make 1.5 Euro profit per bottle.");
data.push("21: The R&D department has a basic formula for Vitfit, but it has still to do some final tests to release it to the market. This would cost additional 5 million Euro on top of the forecast.");
data.push("22: Some production space that is suitable for Vitfit has unexpectedly freed up. This would save Teasies 10 million Euro of rent costs they had calculated for Vitfit’s production.");
data.push("23: Vitfit’s final formula is still not patented because there are some legal conflicts. To finalize the patent process, Teasies would need to pay additional 5 million Euro of legal fees on top of the forecast. The patent is necessary; otherwise, Vitfit would be immediately copied by competitors and become unprofitable.");
data.push("24: Market research shows that consumers are not very enthusiastic about Vitfit. It would sell okay, but only fulfill 2/3 of the sales expectations.");
data.push("25: The financial department has calculated that Vitfit would give 1.5 Euro profit per bottle. They expect to sell 50 million bottles over 2 years.");
var data = [];
var botname='Alex'
var gptTimer='' //used to stop the chat GPT timer later
var countdowns = new Object(); // holds the timeout in milliseconds
var botReminderTriggered = false;
function chatReceived(from,val) {
var color = "blue";
if (from == myid) {
color = "green";
$('#chat_conversation').append('<div color="'+color+'"> <strong> You (Member '+from+'):</strong> '+ val+'</div>');
chats.push(val);
} else if (from ==99){
//if it's the bot, append it with the botname
$('#chat_conversation').append('<div color="'+color+'"><strong>'+botname+':</strong>'+ val+'</div>');
} else {
$('#chat_conversation').append('<div color="'+color+'"> <strong> Member '+from+':</strong> '+ val+'</div>');
chats.push(val);
}
$('#chat_conversation').scrollTop = $('#chat_conversation').scrollHeight;
}
function appendToChatConversation(message, sender = 'User') {
console.log('resp2 '+ message)
// Create the formatted HTML string
let formattedMessage = `<div><strong>${sender}:</strong> ${message}</div>`;
// Append the formatted message to the HTML element with the ID "chat_conversation"
$('#chat_conversation').append(formattedMessage);
}
function greetFromGpt(message){
console.log('resp2 '+ message)
// Create the formatted HTML string
let greetMessage = `<div><strong>${botname}:</strong> ${greeting}</div>`;
let firstInfo = `<div><strong>${botname}:</strong> ${first_info}</div>`;
// Append the formatted message to the HTML element with the ID "chat_conversation"
$('#chat_conversation').append(greetMessage);
$('#chat_conversation').append(firstInfo);
}
// Function to generate a summary using OpenAI API
function generateSummary() {
// Prepare the message payload
model='gpt-3.5-turbo-0125' //User specifies the model they want
temperature = .7 //user specifies the temperature variable (default to .7 if they do not specify)
const message = {
role: 'user',
content: `Please read the following conversation:\n\n${chats}. And point out what did they miss from ${data}.You are only allowed to give some vague hints to them instead of give any actual information.When you point out hints, please start with something like: Here is something for you to consider in your discussion: + hint; or One thing I would like to remind you during the discussion is + hint.`
};
// Call the OpenAI function to get the summary
openai_chat_completions_create(message,temperature,model)
.then(response => {
console.log(response); // This will log the actual response
resp=response.response
console.log('resp1 '+ resp)
sendComBot(99,resp,-1)
//appendToChatConversation(resp,sender='Gptbot');
});
}
// This function calls OpenAI and handles the response
async function openai_chat_completions_create(message, temperature=.7, model='gpt-3.5-turbo-0125'){
const openAIResponse = await fetch("https://volunteerscience.com/openai/chat/", {
method: "POST",
body: JSON.stringify({
message: message,
temperature: temperature,
model: model
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
});
const result = await openAIResponse.json(); //get the json from the returned response
//console.log(result); //handle the returned response with the format {'response': 'text from chatGPT'}
return result
}
// Function to handle message sending
function handleMessageSend() {
const chatInput = $('#chat_input').val();
if (chatInput.trim()) {
appendToChatConversation(chatInput);
chatReceived('User', chatInput);
$('#chat_input').val(''); // Clear the input field
}
}
function startGPT(){
gptTimer= setInterval(() => {
console.log('running gpt timer')
for (var i = 1; i < myid; i++) {
if (activePlayers[i]) return;
}
if (botReminderTriggered == false){generateSummary()}
}, 240000);
}
// Initialize chat functionality
function receiveMessage(event) {
// if we detect the survey is over, hide the iframe and end experiment.
if (event.data == "closeQSIWindow") {
document.getElementById("qualFrame").style.display = 'none';
experimentComplete();
}
// if researcher calls popupConsent in survey and user has not already consented before, pop up the experiment's consent form
if (event.data == "popupConsent") {
if (REQUEST_CONSENT) {
requestConsent();
}
}
// if researcher calls "payAMT" in survey and it's a turker, pay the base plus whatever bonus AMTBonus is set to.
if (event.data == "payAMT") {
if (IS_AMT){
payAMT(true, AMTBonus);
}
}
}
function setCountdown(id,seconds) {
countdowns[id] = [];
countdowns[id][0] = +new Date() + seconds*1000;
countdowns[id][1] = seconds*1000;
var mins = Math.floor(seconds/60);
var secondRemainder = seconds%60;
var secondsStr = ('0'+secondRemainder).slice(-2); // add leading zero, then use last 2 digits
$('#'+id).html('<div class="countdown-clock">'+mins+':'+secondsStr+'</div><div class="countdown-bar"><div class="countdown-progress"></div></div>');
}
/**
* Call this routinely
*/
function advanceCountdowns() {
for (id in countdowns) {
updateCountdown(id);
}
}
function updateCountdown(id) {
var now = +new Date();
var diff = countdowns[id][0]-now;
var clockString = "0:00";
if (diff > 0) {
var fraction = 100*diff/countdowns[id][1];
var seconds = ~~(diff/1000);
var mins = Math.floor(seconds/60);
var secondRemainder = seconds%60;
var secondsStr = ('0'+secondRemainder).slice(-2); // add leading zero, then use last 2 digits
clockString = mins+":"+secondsStr;
$('#'+id+' .countdown-progress').css("width",fraction+"%");
} else {
$('#'+id+' .countdown-progress').css("width","0");
if(typeof countdownExpired == 'function') {
countdownExpired(id);
}
delete countdowns[id];
}
$('#'+id+' .countdown-clock').html(clockString);
if (typeof countdownUpdate == "function") {
countdownUpdate(id,diff,clockString);
}
if (diff <= 240000 && !botReminderTriggered) {
remindLastMinutes(diff); // Call the reminder function
}
}
function stopCountdown(id) {
delete countdowns[id];
}
function remindLastMinutes(diff) {
botReminderTriggered = true; // Set flag to prevent multiple triggers
setInterval(function() {
let minsLeft = Math.floor(diff / 60000);
if (minsLeft === 3) {
appendToChatConversation("You only have 3 minutes left. Make sure you reach anagreement and submit your rank order to win your $10 bonus. You can no longer change your rank in 3 minutes!", 'Alex');
} else if (minsLeft === 2) {
appendToChatConversation("You only have 2 minutes left. Reach an agreement and submit your rank order!", 'Alex');
} else if (minsLeft === 1) {
appendToChatConversation("Finalize your rank now! No changes can be made after the timer runs out in 1 minute.", 'Alex');
} else if (minsLeft <= 0) {
appendToChatConversation("Time is up. Please submit your rank now.", 'Alex');
clearInterval(reminderInterval);
}
diff -= 60000;
}, 60000); // Trigger the reminder every minute
}
// Start the study
function initialize() {
initializeChat();
greetFromGpt();
startGPT();
setCountdown("timer",1500);// this is second here
setInterval(advanceCountdowns, 1000);
// place the title on the survey page
document.getElementById("survey_title").innerHTML = variables["title"];
// create a listener for qualtrics
window.addEventListener("message", receiveMessage, false);
// Create an iframe called "qualFrame" that goes to the qualtrics URL and pass the testId and subjectID variables in the URL
document.getElementById("qualFrame").setAttribute("src", variables["survey_link"] + "&testId=" + seed + "&subjectId=" + myid);
document.getElementById("qualFrame").style.height = variables["survey_height"];
document.getElementById("qualFrame").style.display = 'block';
}
</script>
<div id='flexbox' style='display: flex; align-items: flex-start; gap: 20px;'>
<div id='survey' style="width: 100%;">
<!-- format the html page with the title placeholder <h1> and the iframe placeholder <iframe> -->
<h1 id="survey_title"></h1>
<iframe id="qualFrame"
name="qualtrics" scrolling="auto" frameborder="no" align="center"
width="100%"
style="display: none;"></iframe>
</div>
<div id='chat-container' style="width: 40%; margin-top: 20px;">
<div id="container-fluid"> <!-- Creates a small box centered on page -->
<div class="row" style="border: 1px solid; background: #fff"> <!-- Puts the chat system in a single row with a border around it and white background -->
<div id='chat_conversation' class="col-sm-12" style="height: 420px; overflow-y: scroll;"></div> <!-- Creates padding for the chat text -->
</div>
<div class="row" style="border: 1px solid"> <!-- Puts the chat input and button on a row below the box with a border -->
<div class="col-sm-10"> <!-- Sets the width of the chat input box -->
<!-- Volunteer Science is looking for <input id='chat_input'>. If this is not here, chat does not work. -->
<input id='chat_input' type="text" class="form-control" placeholder="Type a message..." />
</div>
<!-- Volunteer Science is looking for <button id="chat_send_button">. If this is not here, chat does not work. -->
<button id="chat_send_button" class="btn btn-warning">Send</button>
</div>
</div>
</div>
</div>