Code viewer for World: Language Translator and Reader

// Cloned by Darius Beril on 7 Dec 2023 from World "Language Quizzer" by Darius Beril 
// Please leave this clone trail here.
 


// Cloned by Darius Beril on 6 Dec 2023 from World "Chat with GPT model" by Starter user 
// Please leave this clone trail here.
 


// 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 and prompt:

var apikey = "";
//var theprompt = "reply with one word, a word, no translation included, in english";


 
// default body is margin 0 and padding 0 
// give it more whitespace:

  $('body').css( "margin", "20px" );
  $('body').css( "padding", "20px" );



 
document.write ( `

<h1> AI Language Translator and Reader </h1>

Running World:
<a href='https://ancientbrain.com/world.php?world=2037050070'>AI Language Translator and Reader</a>.
<br>
<br>

Welcome to my language translator.<br>
Select the language you want to translate to.<br>
Type what you want to translate and hit translate or press enter.<br>
You can translate from ANY! language.<br>
You can also hear audio pronounciation for your translation.<br>
<pre>
</pre>

<h3> Enter API key </h3>

You need an openai API key to use this translating tool. <br>
Register for free and get your API key  
<a href='https://platform.openai.com/account/api-keys'>here</a>.
<br>
You enter your API key below and then translate away.
<br>
<p>

<div id=enterkey>
Enter API key: 
	<input    style='width:25vw;'    maxlength='2000'   NAME="apikey"    id="apikey"       VALUE='' >  
	<button onclick='setkey();'  class=ab-normbutton >Set API key</button>
</div>

<div id=languageselect>
Select the language you would like to translate to:

<select id="languageSelect">
    <option value="en-US">English</option>
    <option value="de-DE">German</option>
    <option value="fr-FR">French</option>
    <option value="es-ES">Spanish</option>
    <option value="it-IT">Italian</option>
    <option value="pt-PT">Portuguese</option>
    <option value="nl-NL">Dutch</option>
    <option value="sv-SE">Swedish</option>
    <option value="da-DK">Danish</option>
</select>
</div>

<pre>

</pre>

<div style="width:80vw; background-color:#F8B195;  border: 1px solid black; margin:20; padding: 20px;">
<h3> Translate </h3>
<input type="text" id="me" placeholder="Type Here!">
<button onclick="sendchat();" class=ab-normbutton > Translate </button> 
</div>


<div style="width:80vw; background-color:#F8B195; border: 1px solid black; margin:20; padding: 20px; height: 200px; overflow: auto;">
    <h3> Translation </h3>
    <div id="them" style="font-size: 16px; overflow-y: auto; height: 100%;"> </div>
    
</div>
<button onclick="speakText();" class="ab-normbutton">Read Out Loud</button>
<h3>Speech Settings</h3>
<label for="volumeSlider">Volume:</label>
<input type="range" id="volumeSlider" min="0" max="1" step="0.1" value="1">
<br>
<label for="rateSlider">Rate:</label>
<input type="range" id="rateSlider" min="0.1" max="2" step="0.1" value="1">
<br>
<label for="pitchSlider">Pitch:</label>
<input type="range" id="pitchSlider" min="0.1" max="2" step="0.1" value="1">
 <p> <i> Disclaimer: ChatGPT Translations may not always be accurate.<br></i> </p>

<pre>

</pre>


` );




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 entered text

function sendchat() {
  // Get the prompt from the input field
  var promptInput = document.getElementById('me');
  var promptText = promptInput.value;

  // Ensure that the prompt is not empty
  if (promptText.trim() === '') {
    alert('Please enter a prompt.');
    return;
  }

  // Set the prompt in the request data
  var thedata = {
    "model": themodel,
    "temperature": 0.7,
    "messages": [{
      "role": "user",
      "content": promptText
    }]
  };

  // Update theprompt variable with the current prompt
  theprompt = promptText;
    var selectedLanguage = document.getElementById('languageSelect').value;

    // Ensure that the prompt is not empty
    if (promptText.trim() === '') {
        alert('Please enter a prompt.');
        return;
    }

    // Format the prompt for chatgpt translation
    var translationPrompt = "Translate this paragraph into " + selectedLanguage + ": " + promptText;

    // Set the formatted prompt in the request data
    var thedata = {
        "model": themodel,
        "temperature": 0.7,
        "messages": [{
            "role": "user",
            "content": translationPrompt
        }]
    };

    // Convert the data to a JSON string
    var thedatastring = JSON.stringify(thedata); 


   
// 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 (); }
 });
 
}


 
 // global variable to examine return data in console 
 var a;
 
 
 
 function successfn ( data, rc )
 {
     console.log(data)
     a = data;
     var answer = a["choices"][0].message.content;
     $("#them").html ( answer );
 }
 
 function errorfn(jqXHR, textStatus, errorThrown)
 {
     if ( apikey == "" )    $("#them").html ( "<font color=red><b> Enter API key to be able to chat. </b></font>" );
     
     if (jqXHR.status === 401) {
        $("#them").html("<font color=red><b>Authentication failed. Check your API key.</b></font>");
    } else if (jqXHR.status === 429) {
        $("#them").html("<font color=red><b>Rate limit exceeded. Reduce your request rate.</b></font>");
    } else {
        $("#them").html("<font color=red><b>Unknown error: " + errorThrown + "</b></font>");
    }
 }
 


 
// Check if the browser supports the Web Speech API
if ('speechSynthesis' in window) {
  var synth = window.speechSynthesis;
  var utterance = new SpeechSynthesisUtterance('');
  
  // List available voices
  var voices = synth.getVoices();
  
  // Set the voice (optional)
  utterance.voice = voices[0];
  
  // Set other properties (optional)
  // utterance.rate = 1.0; // Speech rate (1.0 is normal)
  // utterance.pitch = 1.0; // Speech pitch (1.0 is normal)
  
  // Speak the text
  synth.speak(utterance);
} else {
  console.error('Speech synthesis is not supported in this browser.');
}

function speakText() {
    window.speechSynthesis.cancel(); // Cancel any ongoing speech
    var textToSpeak = document.getElementById('them').innerText;
    var selectedLanguage = document.getElementById('languageSelect').value;

    globalUtterance.text = textToSpeak; // Set the text to speak

    // Dynamically choose the best available voice for the selected language
    var voices = window.speechSynthesis.getVoices();
    var selectedVoice = voices.find(voice => voice.lang === selectedLanguage);

    if (selectedVoice) {
        globalUtterance.voice = selectedVoice;
    } else {
        console.warn('No matching voice found for the selected language');
    }

    window.speechSynthesis.speak(globalUtterance);
}

var volumeSlider = document.getElementById('volumeSlider');
var rateSlider = document.getElementById('rateSlider');
var pitchSlider = document.getElementById('pitchSlider');

volumeSlider.addEventListener('input', updateSpeechProperties);
rateSlider.addEventListener('input', updateSpeechProperties);
pitchSlider.addEventListener('input', updateSpeechProperties);

var globalUtterance = new SpeechSynthesisUtterance(); // Global utterance object

function updateSpeechProperties() {
    // Update properties of the global utterance object
    globalUtterance.volume = parseFloat(volumeSlider.value);
    globalUtterance.rate = parseFloat(rateSlider.value);
    globalUtterance.pitch = parseFloat(pitchSlider.value);
}