/* ai_vs_irctc.js — irctc1 truth vs OpenAI, with origin->boarding day-offset correction. irctc1 reports running days AT the from-station. OpenAI reports ORIGIN days. We shift OpenAI's answer by the train's stored day_offset at the from-station, then compare. Trains not in our timetable (offset unknown) are shown but not scored. */ (function () { var ORDER = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; var IDX = { Mon: 0, Tue: 1, Wed: 2, Thu: 3, Fri: 4, Sat: 5, Sun: 6 }; function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); } function shiftDays(days, off) { off = ((off % 7) + 7) % 7; var set = {}; days.forEach(function (d) { if (d in IDX) set[ORDER[(IDX[d] + off) % 7]] = 1; }); return ORDER.filter(function (d) { return set[d]; }); } document.addEventListener('DOMContentLoaded', function () { var form = document.getElementById('cmp-form'); if (!form) return; form.addEventListener('submit', function (ev) { ev.preventDefault(); var btn = document.getElementById('cmp-run'); var orig = btn.textContent; var csrf = form.querySelector('input[name=csrf]').value; var model = (document.getElementById('model').value || '').trim() || 'gpt-5.5'; var max = parseInt(document.getElementById('max').value, 10) || 6; var tbody = document.getElementById('cmp-rows'); var summary = document.getElementById('cmp-summary'); var box = document.getElementById('cmp-results'); tbody.innerHTML = ''; summary.innerHTML = ''; box.style.display = 'block'; btn.disabled = true; btn.textContent = 'Fetching irctc1 truth…'; var p = new URLSearchParams({ action: 'irctc', csrf: csrf, from: document.getElementById('from').value, to: document.getElementById('to').value, date: document.getElementById('date').value }); fetch(window.location.pathname, { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: p }) .then(function (r) { if (!r.ok) throw new Error('irctc HTTP ' + r.status); return r.json(); }) .then(function (data) { if (data.err) throw new Error(data.err); var trains = (data.trains || []).slice(0, max); if (!trains.length) { summary.innerHTML = errBox('irctc1 returned no trains for this route/date.'); reset(); return; } var rows = []; trains.forEach(function (t) { var tr = document.createElement('tr'); tr.style.borderBottom = '1px solid #eee'; tr.style.verticalAlign = 'top'; tr.innerHTML = '' + esc(t.tn) + '' + '' + esc(t.name) + '' + '' + esc((t.days || []).join(',') || '(none)') + '' + '…querying OpenAI…'; tbody.appendChild(tr); rows.push({ t: t, tr: tr }); }); var i = 0, pass = 0, fail = 0, errc = 0, judged = 0; function next() { if (i >= rows.length) { var cls = (fail > 0 || errc > 0) ? 'flash-error' : 'flash-info'; var m = 'PASS ' + pass + ' \u00b7 FAIL ' + fail + ' \u00b7 ERROR ' + errc + '. '; if (judged === 0) m += 'Nothing scored (no truth or no offset data).'; else if (fail > 0) m += 'After offset correction, OpenAI still disagreed with irctc1 on ' + fail + ' of ' + judged + ' scored train(s) — those are real differences. Per your rule, irctc1 wins.'; else if (errc > 0) m += 'OpenAI matched on all ' + judged + ' scored, but some calls errored/timed out — rerun those (try gpt-5.4-mini) before concluding.'; else m += 'OpenAI matched irctc1 on all ' + judged + ' scored (offset-corrected). Widen across routes and include obscure/weekly trains before trusting it.'; summary.innerHTML = '
' + m + '
'; reset(); return; } var row = rows[i++]; var t = row.t; var tr = row.tr; var truth = (t.days || []).join(','); btn.textContent = 'OpenAI: ' + t.tn + ' (' + i + '/' + rows.length + ')…'; var b = new URLSearchParams({ action: 'one', csrf: csrf, train: t.tn, model: model }); fetch(window.location.pathname, { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: b }) .then(function (r) { if (!r.ok) { var x = r.status === 504 ? ' (gateway timeout — try gpt-5.4-mini)' : ''; throw new Error('HTTP ' + r.status + x); } return r.json(); }) .then(function (d) { if (d.err) { errc++; fillErr(tr, d.err); return; } var originDays = d.got || []; var off = t.offset; var oCell, match; if (off === null || off === undefined) { oCell = esc(originDays.join(',') || '(none)') + ' (origin; no offset data — not scored)'; match = null; } else { var shifted = off === 0 ? originDays : shiftDays(originDays, off); oCell = (off === 0) ? esc(originDays.join(',') || '(none)') : esc(originDays.join(',') || '(none)') + ' \u2192 ' + esc(shifted.join(',') || '(none)') + ' (off +' + off + ')'; match = truth === '' ? null : (shifted.join(',') === truth); } if (match === true) pass++; else if (match === false) fail++; if (match !== null) judged++; fillResult(tr, oCell, match, d.conf, d.src); }) .catch(function (e) { errc++; fillErr(tr, e.message); }) .then(next); } next(); }) .catch(function (e) { summary.innerHTML = errBox(e.message); reset(); }); function reset() { btn.disabled = false; btn.textContent = orig; } function errBox(msg) { return '
' + esc(msg) + '
'; } function fillResult(tr, openaiHtml, match, conf, src) { var color = match === true ? '#197b3a' : (match === false ? '#c0392b' : '#888'); var label = match === true ? 'PASS' : (match === false ? 'FAIL' : '—'); while (tr.children.length > 3) tr.removeChild(tr.children[3]); tr.insertAdjacentHTML('beforeend', '' + openaiHtml + '' + '' + label + '' + '' + esc(conf) + '' + '' + esc(src) + ''); } function fillErr(tr, msg) { while (tr.children.length > 3) tr.removeChild(tr.children[3]); tr.insertAdjacentHTML('beforeend', '\u26a0 ' + esc(msg) + ''); } }); }); })();