Code viewer for World: Simple AI Translation Accu...

// "New World" by Tharakesh Aravindan
// https://ancientbrain.com/edit.world.php?world=3654434791

// Simple AI Translation Accuracy Tester (English → Spanish)
// Using OpenAI (requires key) and MyMemory (no key needed, browser-safe)
// Author: Tharakesh Aravindan, Date: 23/11/2025
// Ancient Brain World for empirical API evaluation
// My OpenAi API Key: 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


// Credits & References:
// - OpenAI API: https://openai.com/
// - MyMemory API: https://mymemory.translated.net/doc/spec.php
// - Ancient Brain coding platform: https://ancientbrain.com/
// - Example World reference: https://run.ancientbrain.com/run.php?world=2850716357 (World: Chat with GPT Model) 
// - Mozilla Developer Network (MDN) JavaScript documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
// - Humphrys, M. (2025). Bringing AI APIs into the classroom with a JavaScript coding site. IJIET Vol.15, No.2. https://humphryscomputing.com/Publications/london.ijiet.pdf

// All project code is original except for referenced sample Worlds and official API documentation.


const DATA = [
  {id:1, en:"The cat is sitting on the table.", es:"El gato está sentado en la mesa."},
  {id:2, en:"She will arrive tomorrow.", es:"Ella llegará mañana."},
  {id:3, en:"I don't like cold weather.", es:"No me gusta el clima frío."},
  {id:4, en:"Can you help me with this problem?", es:"¿Puedes ayudarme con este problema?"},
  {id:5, en:"He bought three red apples.", es:"Compró tres manzanas rojas."},
  {id:6, en:"I have been learning Spanish for two years.", es:"He estado aprendiendo español durante dos años."},
  {id:7, en:"We met at the station at six o'clock.", es:"Nos conocimos en la estación a las seis."},
  {id:8, en:"Water boils at 100 degrees Celsius.", es:"El agua hierve a 100 grados Celsius."},
  {id:9, en:"My favorite sport is football.", es:"Mi deporte favorito es el fútbol."},
  {id:10, en:"The quick brown fox jumps over the lazy dog.", es:"El rápido zorro marrón salta sobre el perro perezoso."}
];

// ---- HTML UI ----
let html = `
<h1>AI Translation Accuracy Tester</h1>
<p>Compare two AI translation APIs: OpenAI (requires key) and MyMemory (no key needed).</p>

<label>OpenAI API Key:</label>
<input id='openaiKey' placeholder='sk-...' style='width:100%'><br><br>

<label>Select test sentence:</label>
<select id='testSelect'></select><br><br>

<button id='runBtn'>Run Both Translators</button>
<button id='runAllBtn'>Run Full Dataset</button><br><br>

<h2>Expected Answer:</h2>
<pre id='expected'>(choose a test)</pre>

<h2>OpenAI Result:</h2>
<pre id='openaiOut'>-</pre>
<p>Match: <span id='openaiPass'>-</span></p>

<h2>MyMemory Result:</h2>
<pre id='mymemOut'>-</pre>
<p>Match: <span id='mymemPass'>-</span></p>

<h2>Metrics:</h2>
<div id='metrics'></div>
`;

document.write(html);

// ---- Populate dropdown ----
const select = document.getElementById('testSelect');
DATA.forEach(t => {
  const opt = document.createElement('option');
  opt.value = t.id;
  opt.textContent = `${t.id}: ${t.en}`;
  select.appendChild(opt);
});

const expectedEl = document.getElementById('expected');
const openaiOut = document.getElementById('openaiOut');
const mymemOut = document.getElementById('mymemOut');
const openaiPass = document.getElementById('openaiPass');
const mymemPass = document.getElementById('mymemPass');
const metrics = document.getElementById('metrics');

function getTestById(id){ return DATA.find(d=>d.id==id); }
function normalize(s){ return String(s||'').normalize('NFKD').replace(/[\u0300-\u036f]/g,'').toLowerCase().replace(/[^\w]+/g,' ').trim(); }
function tokenOverlap(a,b){ const A=normalize(a).split(/\s+/),B=normalize(b).split(/\s+/); const common=A.filter(x=>B.includes(x)).length; return common/Math.max(A.length,B.length); }

function setExpected(){ const t=getTestById(select.value); expectedEl.textContent=t.es; }
select.addEventListener('change', setExpected);
setExpected();

// ---- Run OpenAI ----
async function callOpenAI(text,key){
  try{
    const prompt=`Translate the following English sentence into Spanish. Return only the translation:\n"${text}"`;
    const resp=await fetch('https://api.openai.com/v1/chat/completions',{
      method:'POST',
      headers:{'Content-Type':'application/json','Authorization':`Bearer ${key}`},
      body:JSON.stringify({
        model:'gpt-4o-mini',
        messages:[{role:'user',content:prompt}],
        max_tokens:200,
        temperature:0
      })
    });
    const j=await resp.json();
    return j?.choices?.[0]?.message?.content || JSON.stringify(j);
  }catch(e){ return 'ERROR:'+e; }
}

// ---- Run MyMemory Translation ----
async function callMyMemory(text){
  try{
    // language pair: en|es for English->Spanish
    const url =
      "https://api.mymemory.translated.net/get?q=" +
      encodeURIComponent(text) + "&langpair=en|es";

    const resp = await fetch(url);
    if (!resp.ok) throw new Error('API request failed with status: ' + resp.status);
    const j = await resp.json();
    // The translation is usually in j.responseData.translatedText
    return j?.responseData?.translatedText || JSON.stringify(j);
  }catch(e){
    return 'ERROR:' + e;
  }
}

// ---- Run one test ----
async function runTest(t,openaiKey,display=true){
  const expected = t.es;
  const openaiText = await callOpenAI(t.en,openaiKey);
  const mymemText = await callMyMemory(t.en);

  const openaiScore = tokenOverlap(openaiText, expected);
  const mymemScore = tokenOverlap(mymemText, expected);

  const openaiPassBool = (normalize(openaiText) === normalize(expected)) || openaiScore >= 0.8;
  const mymemPassBool = (normalize(mymemText) === normalize(expected)) || mymemScore >= 0.8;

  if (display) {
    openaiOut.textContent = openaiText;
    mymemOut.textContent = mymemText;
    openaiPass.textContent = openaiPassBool ? 'PASS' : 'FAIL';
    openaiPass.className = openaiPassBool ? 'pass' : 'fail';
    mymemPass.textContent = mymemPassBool ? 'PASS' : 'FAIL';
    mymemPass.className = mymemPassBool ? 'pass' : 'fail';
    metrics.innerHTML = `OpenAI overlap: ${openaiScore.toFixed(2)} — MyMemory overlap: ${mymemScore.toFixed(2)}`;
  }

  return { openaiText, mymemText, openaiPass: openaiPassBool, mymemPass: mymemPassBool };
}

// ---- Button listeners ----
document.getElementById('runBtn').addEventListener('click', async () => {
  const key = document.getElementById('openaiKey').value.trim();
  if (!key) { alert('Paste OpenAI key'); return; }
  const t = getTestById(select.value);
  await runTest(t, key);
});

document.getElementById('runAllBtn').addEventListener('click', async () => {
  const key = document.getElementById('openaiKey').value.trim();
  if (!key) { alert('Paste OpenAI key'); return; }
  const results = [];
  for (const t of DATA) {
    const r = await runTest(t, key, false);
    results.push({ id: t.id, openaiPass: r.openaiPass, mymemPass: r.mymemPass });
  }
  const openaiAcc = results.filter(r => r.openaiPass).length / results.length;
  const mymemAcc = results.filter(r => r.mymemPass).length / results.length;
  metrics.innerHTML = `OpenAI accuracy: ${(openaiAcc * 100).toFixed(1)}%<br>MyMemory accuracy: ${(mymemAcc * 100).toFixed(1)}%<br><br>Per-item results:<br><pre>${JSON.stringify(results, null, 2)}</pre>`;
});