gpt5-fix / index.html
llamameta's picture
Update index.html
9f207c1 verified
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>GPT-5</title>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<style>
html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
#loading {
position: fixed; inset: 0; background: rgba(255,255,255,0.9);
display: flex; justify-content: center; align-items: center;
font-size: 18px; z-index: 1000;
}
iframe { width: 100%; height: 100vh; border: none; }
</style>
</head>
<body>
<div id="loading">Please wait... Memilih server optimal...</div>
<iframe id="streamlit-frame" referrerpolicy="no-referrer"></iframe>
<script>
const VERSION = "v1";
const SERVERS = [
"https://gepatest-hwak3xkal5nltlveztf5nn.streamlit.app/?embed=true"
];
// Timeout definisi
const pingTimeoutMs = 5000; // timeout ping img
const iframeLoadTimeoutMs = 12000; // waktu nunggu iframe dianggap "siap"
const overallTryTimeoutMs = 20000; // batas keras setiap percobaan server
// Ping ringan via <img> untuk menghindari no-cors opaque fetch
function ping(url, timeout = pingTimeoutMs) {
return new Promise((resolve) => {
const start = performance.now();
const img = new Image();
let done = false;
const timer = setTimeout(() => {
if (done) return;
done = true;
// Timeout dianggap gagal (Infinity)
resolve({ url, ok: false, latency: Infinity });
img.src = ""; // abort
}, timeout);
const onComplete = (ok) => {
if (done) return;
done = true;
clearTimeout(timer);
const latency = performance.now() - start;
resolve({ url, ok, latency });
};
img.onload = () => onComplete(true);
img.onerror = () => onComplete(false);
// Gunakan endpoint root dengan cache buster (Streamlit akan render HTML, img akan gagal, tapi kita tetap dapat latency)
// Trik: walau img gagal (onerror), kita catat latency untuk RTT awal.
// Tambah cb agar tidak cached.
const u = new URL(url);
u.searchParams.set("cb", Date.now().toString());
img.src = u.toString();
});
}
async function rankServersByPing(urls) {
const results = await Promise.all(urls.map(u => ping(u)));
// Urutkan berdasarkan latency terkecil
return results
.sort((a,b) => a.latency - b.latency)
.map(r => r.url);
}
function setIframeSrc(iframe, baseUrl) {
const u = new URL(baseUrl);
u.searchParams.set("cb", Date.now().toString());
iframe.src = u.toString();
}
// Coba load satu server dengan mekanisme timeout. Kembalikan true jika dianggap siap, false jika gagal.
function tryLoadServer(iframe, url) {
return new Promise((resolve) => {
let settled = false;
// Hard timeout untuk satu percobaan
const hardTimer = setTimeout(() => {
if (settled) return;
settled = true;
resolve(false);
}, overallTryTimeoutMs);
// Timer "app-ready" (karena onload bisa sukses walau app error)
const readyTimer = setTimeout(() => {
if (settled) return;
// Lewati: tidak ada sinyal ready; anggap gagal
settled = true;
clearTimeout(hardTimer);
resolve(false);
}, iframeLoadTimeoutMs);
// onload: dokumen termuat. Namun belum tentu app sehat.
iframe.onload = () => {
// Tetap menunggu sampai readyTimer. Jika Anda punya postMessage dari app,
// di sini seharusnya menunggu pesan "ready" untuk resolve(true).
// Karena tidak ada, kita pakai heuristik: beri sedikit grace period lalu anggap OK.
// Grace singkat agar tidak menunggu lama kalau memang error.
setTimeout(() => {
if (settled) return;
settled = true;
clearTimeout(readyTimer);
clearTimeout(hardTimer);
resolve(true);
}, 1500); // grace 1.5s setelah onload
};
// onerror hanya terjadi untuk kegagalan jaringan keras
iframe.onerror = () => {
if (settled) return;
settled = true;
clearTimeout(readyTimer);
clearTimeout(hardTimer);
resolve(false);
};
setIframeSrc(iframe, url);
});
}
async function loadWithFallback() {
const iframe = document.getElementById("streamlit-frame");
const loading = document.getElementById("loading");
const storageKey = `streamlitUrl_${VERSION}`;
// Coba baca cache sebelumnya
const cached = sessionStorage.getItem(storageKey);
// Urutkan server berdasarkan ping (kasih prioritas yang lebih cepat).
let prioritized = await rankServersByPing(SERVERS);
// Jika ada cache, letakkan di depan daftar supaya dicoba dulu
if (cached && prioritized.includes(cached)) {
prioritized = [cached, ...prioritized.filter(u => u !== cached)];
}
for (const url of prioritized) {
const ok = await tryLoadServer(iframe, url);
if (ok) {
// Anggap server siap. Simpan ke sessionStorage.
sessionStorage.setItem(storageKey, url);
loading.style.display = "none";
// Pasang watchdog: jika nanti ada kegagalan reload (jarang), bersihkan cache.
iframe.addEventListener('error', () => {
sessionStorage.removeItem(storageKey);
});
return;
}
}
// Semua gagal: bersihkan cache dan tampilkan pesan sederhana
sessionStorage.removeItem(storageKey);
loading.textContent = "Semua server gagal dimuat. Coba refresh halaman.";
}
window.addEventListener("load", loadWithFallback);
</script>
</body>
</html>