// Default API key and prompt
let apikey = "";
const flanT5ComparisonAPI = "https://api-inference.huggingface.co/models/google/flan-t5-large"; // Hugging Face Flan-T5 for comparison
const myMemoryAPI = "https://api.mymemory.translated.net/get"; // MyMemory API
// Default language-to-model mapping for Helsinki API
const languageModelMap = {
Spanish: "opus-mt-en-es",
French: "opus-mt-en-fr",
Italian: "opus-mt-en-it",
German: "opus-mt-en-de",
Arabic: "opus-mt-en-ar",
Japanese: "opus-mt-en-jap",
Bulgarian: "opus-mt-en-bg",
};
// Default body styling
$('body').css("margin", "20px");
$('body').css("padding", "20px");
document.write(`
<h1> Translate Text Using Two APIs and then comparing </h1>
<div style="width:100%; padding: 20px; background-color: #B6D0E2;">
<h2> Set Up Translation </h2>
<h3> 1. Enter API key </h3>
<div id="enterkey">
API key: <input style="width:50%;" maxlength="2000" id="apikey" placeholder="Enter your Hugging Face API key">
<button onclick="setkey();" class="ab-normbutton bg-orange-100">Set API Key</button>
</div>
<h3> 2. Enter text to translate </h3>
<div>
<input style="width:100%;" id="textInput" placeholder="Enter text to translate">
</div>
<h3> 3. Select language </h3>
<select id="languageSelect">
<option value="Spanish">Spanish</option>
<option value="French">French</option>
<option value="Italian">Italian</option>
<option value="German">German</option>
<option value="Arabic">Arabic</option>
<option value="Japanese">Japanese</option>
<option value="Bulgarian">Bulgarian</option>
</select>
<button onclick="translateWithBothAPIs();" class="ab-normbutton bg-orange-100">Translate</button>
</div>
<div style="width:100%; display: flex; justify-content: space-between; margin-top: 20px;">
<!-- Helsinki Translation -->
<div style="width:48%; border: 1px solid black; padding: 20px; background-color: #B6D0E2;">
<h2> Helsinki Translation </h2>
<h4> Sometimes you have to refresh the page for this to load :)</h4>
<div id="helsinkiResult" style="background-color: #ffffcc; padding: 10px; border: 1px solid black;"></div>
</div>
<!-- MyMemory Translation -->
<div style="width:48%; border: 1px solid black; padding: 20px; backround:blue">
<h2> MyMemory Translation </h2>
<h4>...</h4>
<div id="myMemoryResult" style="background-color: #ffffcc; padding: 10px; border: 1px solid black;"></div>
</div>
</div>
<!-- Comparison Section -->
<div style="width:100%; border: 1px solid black; padding: 20px; margin-top: 20px; background-color: #B6D0E2;">
<h2> Compare Translations </h2>
<h4> Sometimes these are incorrect answers but this is because it was the best AI with a free API key we could find :(</h4>
<button onclick="compareTranslations();" class="ab-normbutton bg-orange-100">Compare Results</button>
<h3> Which translation is better? 1: "Helsinki Translation" or 2: "MyMemory Translation".</h3>
<div id="comparisonResult" style="background-color: #ffffcc; padding: 10px; border: 1px solid black;"></div>
</div>
`);
// Function to set API key
function setkey() {
apikey = $("#apikey").val().trim();
if (apikey) {
$("#enterkey").html("<b>API key has been set.</b>");
} else {
alert("Please enter a valid API key.");
}
}
// Translate with both APIs
async function translateWithBothAPIs() {
const inputText = $("#textInput").val().trim();
const selectedLanguage = $("#languageSelect").val();
if (!inputText) {
alert("Please enter text to translate.");
return;
}
if (!apikey) {
alert("Please set your API key first.");
return;
}
const modelName = languageModelMap[selectedLanguage];
if (!modelName) {
alert(`No model found for the selected language: ${selectedLanguage}`);
return;
}
// Display loading messages
$("#helsinkiResult").html("<i>Loading Helsinki translation...</i>");
$("#myMemoryResult").html("<i>Loading MyMemory translation...</i>");
try {
const [helsinkiTranslation, myMemoryTranslation] = await Promise.all([
translateWithHelsinki(inputText, modelName),
translateWithMyMemory(inputText, selectedLanguage)
]);
$("#helsinkiResult").html(`<b>Translation:</b> ${helsinkiTranslation}`);
$("#myMemoryResult").html(`<b>Translation:</b> ${myMemoryTranslation}`);
} catch (error) {
console.error("Translation Error:", error);
}
}
// Utility function for a timeout because a lot of the api's are slow and need time to give a response
function timeoutPromise(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error("Request timed out")), ms);
});
}
//We have tested all of the available languages and they usually work but sometimes you have to refresh the page for them to work
// Translate with Helsinki API https://huggingface.co/Helsinki-NLP/opus-mt-en-ar?text=My+name+is+Wolfgang+and+I+live+in+Berlin
//there is a specific one for each language so the modelName changes for each language
async function translateWithHelsinki(inputText, modelName) {
const huggingFaceURL = `https://api-inference.huggingface.co/models/Helsinki-NLP/${modelName}`;
const payload = { inputs: inputText };
try {
const response = await Promise.race([
fetch(huggingFaceURL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apikey}`,
},
body: JSON.stringify(payload),
}),
timeoutPromise(30000), // 30 seconds timeout
]);
if (response.ok) {
const data = await response.json();
return data[0]?.translation_text || "No translation generated.";
} else {
const errorText = await response.text();
throw new Error(`Helsinki API error: ${errorText}`);
}
} catch (error) {
console.error("Helsinki API Error:", error);
return "Error connecting to Helsinki API.";
}
}
// Translate with MyMemory API
//https://mymemory.translated.net/en/English/Spanish/hey
async function translateWithMyMemory(inputText, targetLang) {
const languageCodes = {
Spanish: "es",
French: "fr",
Italian: "it",
German: "de",
Arabic: "pl",
Japanese: "ja",
Bulgarian: "bg",
};
const langCode = languageCodes[targetLang];
const url = `${myMemoryAPI}?q=${encodeURIComponent(inputText)}&langpair=en|${langCode}`;
try {
const response = await fetch(url);
const data = await response.json();
return data.responseData.translatedText || "No translation available.";
} catch (error) {
console.error("MyMemory API Error:", error);
return "Error connecting to MyMemory API.";
}
}
// Compare Translations
//https://huggingface.co/google/flan-t5-large?text=Which+translation+for+%22I+like+shrimp+in+soup%22+to+%22spanish%22+is+better%3F+%22me+gustan+los+camarones+en+sopa%22+or+%22me+gustan+las+gambas+en+sopa%22%60
async function compareTranslations() {
const helsinkiResult = $("#helsinkiResult").text().trim();
const myMemoryResult = $("#myMemoryResult").text().trim();
const inputText = $("#textInput").val().trim();
const lang = $("#languageSelect").val();
if (!apikey) {
$("#comparisonResult").html("<font color=red><b>Please set the API key first.</b></font>");
return;
}
const comparisonPrompt = `Which translation for "${inputText}" to "${lang}" is better? "${helsinkiResult}" or "${myMemoryResult}"`;
$("#comparisonResult").html("<i>Loading...</i>");
try {
const response = await Promise.race([
fetch(flanT5ComparisonAPI, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apikey}`,
},
body: JSON.stringify({ inputs: comparisonPrompt }),
}),
timeoutPromise(30000), // 30 seconds timeout
]);
if (response.ok) {
const data = await response.json();
const comparison = data[0]?.generated_text || "No comparison available.";
$("#comparisonResult").html(`<b>Comparison Result:</b><br>${comparison}`);
} else {
const errorText = await response.text();
throw new Error(`Flan-T5 API error: ${errorText}`);
}
} catch (error) {
console.error("Flan-T5 API Error:", error);
$("#comparisonResult").html("<font color=red><b>Error: Unable to connect to Flan-T5 Comparison API.</b></font>");
}
}