// This project used the world "Chat with GPT model" as a base for which project-specific requirements could be expanded upon
// Cloned by Torbjorn Hoban on 22 Nov 2023 from World "Chat with GPT model" by Starter user
// talk to OpenAI GPT model (ChatGPT)
// adapted from:
// https://platform.openai.com/docs/api-reference/making-requests
const openaiURL = "https://api.openai.com/v1/chat/completions"; // can POST to this 3rd party URL
const themodel = "gpt-3.5-turbo"; // the OpenAI model we are going to talk to
// default API key, prompt and genre:
var apikey = "";
var theprompt = "hello";
var selectedGenre = "";
$('body').css("margin", "20px");
$('body').css("padding", "20px");
document.write(`
<h1 style="font-size: 28px; font-weight: bold;">Musical Textgenerator</h1>
<p><strong>Running World:</strong> <a href='https://ancientbrain.com/world.php?world=3939342136' style="color: #3366cc; text-decoration: underline;">Musical Textgenerator</a>.</p>
<p>Welcome to the Musical Textgenerator! Generate song lyrics with the power of the GPT-3.5 API. Craft verses and choruses based on your input. Try make something interesting!</p>
<hr>
<h3>An <a href="https://platform.openai.com/api-keys" style="color: #3366cc; text-decoration: underline;">API key</a> is required for communicating with GPT</h3>
<div id="enterkey">
<p style="color: #FF0000;"><strong>Important:</strong> If you encounter issues, make sure to check if your API key has expired. You can get a free API key by creating an OpenAI account, but it expires after three months.</p>
<label for="apikey">Enter API key:</label>
<input style="width: 25vw;" maxlength="2000" name="apikey" id="apikey" value="" type="password">
<button onclick="setkey();" class="ab-normbutton">Set API key</button>
</div>
<hr>
<div style="width: 60vw; background-color: white; border: 1px solid black; margin: 20; padding: 20px;">
<h3>Select Temperature</h3>
<input type="range" min="0" max="1" step="0.1" value="0.7" id="temperatureSlider" oninput="updateTemperatureLabel()">
<span id="temperatureLabel">0.7</span>
<p style="font-size: 14px; color: #555;">Temperature controls the creativity of the generated text. Higher values (e.g. 0.8-1.0) result in more randomness and creativity, while lower values (e.g. 0.1-0.5) create more focused and deterministic responses.</p>
</div>
<div style="width: 60vw; background-color: white; border: 1px solid black; margin: 20; padding: 20px;">
<h3>Settings</h3>
<label for="numVerses">Number of Verses:</label>
<input type="number" min="1" max="10" value="3" id="numVerses">
<h3>Select Undertone</h3>
<select style="width: 50vw;" id="styleDropdown">
<option value="poetic">Poetic</option>
<option value="melancholic">Melancholic</option>
<option value="serious">Serious</option>
<option value="up-beat">Up-beat</option>
<option value="nostalgic">Nostalgic</option>
<option value="mysterious">Mysterious</option>
</select>
<button onclick="addGenre();" class="ab-normbutton">Apply Settings</button>
<p style="color: #FF0000;" id="prompt-feedback"></p>
</div>
<div style="width: 60vw; background-color: white; border: 1px solid black; margin: 20; padding: 20px;">
<h3>Pick a genre!</h3>
<select style="width: 50vw;" id="genreDropdown">
<option value="rock">Rock</option>
<option value="pop">Pop</option>
<option value="hip-hop">Hip-Hop</option>
<option value="romance">Romance</option>
<option value="rhythms & blues">Rhythms & Blues</option>
<option value="country">Country</option>
<option value="jazz">Jazz</option>
<option value="classical">Classical</option>
<option value="alternative">Alternative</option>
</select>
<button onclick="addGenre();" class="ab-normbutton">Add genre</button>
<p style="color: #FF0000;" id="prompt-feedback"></p>
</div>
<div style="width: 60vw; background-color: white; border: 1px solid black; margin: 20; padding: 20px;">
<h3>Write the song chorus!</h3>
<div style="display: flex; align-items: center;">
<input style="width: 50vw; flex-grow: 1; margin-right: 4px" id="me">
<button onclick="sendchat();" class="ab-normbutton">Generate</button>
</div>
<p style="color: #FF0000;" id="prompt-feedback"></p>
<div id="loading-message" style="display: none;">
Generating lyrics. Please wait...
</div>
</div>
<hr>
<div style="width: 60vw; background-color: #f2f2f2; border: 1px solid #999; border-radius: 8px; margin: 20; padding: 20px;">
<h3 style="margin-bottom: 10px;">Your very own AI-generated song</h3>
<div id="them" style="font-size: 14px; color: #333;"></div>
<button onclick="clearGeneratedText();" class="ab-normbutton">Clear Generated Text</button>
</div>
`);
// Clears both generated text and song chorus so user can continue without
// reloading webpage
function clearGeneratedText()
{
$("#them").html("");
$("#me").val("");
$("#prompt-feedback").text("");
}
function addGenre()
{
selectedGenre = $("#genreDropdown").val();
$("#prompt-feedback").text("Genre added: " + selectedGenre);
}
function updateTemperatureLabel()
{
var sliderValue = $("#temperatureSlider").val();
$("#temperatureLabel").text(sliderValue);
}
function setkey()
{
apikey = jQuery("input#apikey").val();
apikey = apikey.trim();
$("#enterkey").html("<b> API key has been set. </b>");
}
// Enter will also send chat:
document.getElementById('me').onkeydown = function(event) {
if (event.keyCode == 13)
sendchat();
};
// --- Send my line of text ----------------------------------------------------------------
function sendchat()
{
theprompt = $("#me").val();
var numVerses = $("#numVerses").val();
var selectedStyle = $("#styleDropdown").val();
var promptWithIntro = `Compose a ${selectedGenre.toLowerCase()} song with ${
numVerses} verses. Infuse it with a ${
selectedStyle
.toLowerCase()} undertone. The chorus should be inspired by the following text: "${
theprompt}"`;
$("#me").val("");
var thedata = {
"model" : themodel,
"temperature" : parseFloat($("#temperatureSlider").val()),
"messages" : [ { "role" : "user", "content" : promptWithIntro } ]
};
$("#loading-message").show();
// then as string representing that JSON:
var thedatastring = JSON.stringify(thedata);
// HTTP headers must be set up with API key:
$.ajaxSetup({
headers : {
"Content-Type" : "application/json",
"Authorization" : "Bearer " + apikey
}
});
// POST to 3rd party URL:
$.ajax({
type : "POST",
url : openaiURL,
data : thedatastring,
dataType : "json",
success : function(d, rc) { successfn(d, rc); },
error : function() { errorfn(); },
complete : function() { $("#loading-message").hide(); }
});
}
// global variable to examine return data in console
var a;
function successfn(data, rc)
{
a = data;
var answer = a["choices"][0].message.content;
$("#them").html(answer);
}
function errorfn()
{
if (apikey == "")
$("#them").html(
"<font color=red><b> Enter API key to be able to chat. </b></font>");
else
$("#them").html("<font color=red><b> Unknown error. </b></font>");
}