xenux4u commited on
Commit
fe9d227
Β·
verified Β·
1 Parent(s): 7088e35

Update static/js/script.js

Browse files
Files changed (1) hide show
  1. static/js/script.js +32 -15
static/js/script.js CHANGED
@@ -1,6 +1,6 @@
1
  /**
2
  * ORBIT – Educational Research Assistant
3
- * SAFE SCRIPT: Sinkron dengan ID HTML asli & Anti-Crash
4
  */
5
 
6
  // ─────────────────────────────────────
@@ -13,11 +13,12 @@ const addEvt = (id, event, handler) => {
13
  };
14
 
15
  // ─────────────────────────────────────
16
- // 2. State & Data
17
  // ─────────────────────────────────────
18
  let currentUser = null;
19
  let appSettings = null;
20
- let sessions = JSON.parse(localStorage.getItem('orbit_sessions')) || {};
 
21
  let currentSid = null;
22
  let pdfText = null;
23
  let pdfFilename = null;
@@ -50,9 +51,14 @@ async function initApp() {
50
  } catch (error) {
51
  console.error("Init Error:", error);
52
  } finally {
53
- // Harus selalu dijalankan meskipun gagal fetch
54
  populateModelSelect();
55
 
 
 
 
 
 
 
56
  const ids = Object.keys(sessions).sort((a, b) => Number(b) - Number(a));
57
  if (ids.length > 0) {
58
  loadSession(ids[0]);
@@ -66,7 +72,7 @@ async function initApp() {
66
  // 4. Session & History Logic
67
  // ─────────────────────────────────────
68
  function saveSessions() {
69
- localStorage.setItem('orbit_sessions', JSON.stringify(sessions));
70
  }
71
 
72
  function newSession() {
@@ -78,6 +84,12 @@ function newSession() {
78
  function loadSession(id) {
79
  if (!sessions[id]) return;
80
  currentSid = id;
 
 
 
 
 
 
81
  if(chatMessages) chatMessages.innerHTML = '';
82
 
83
  const msgs = sessions[id].messages || [];
@@ -113,13 +125,15 @@ function renderSidebar() {
113
  return `
114
  <button onclick="window.loadSession('${id}')" class="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm transition-all text-left truncate ${activeClass}">
115
  <svg class="w-4 h-4 shrink-0 opacity-60" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"></path></svg>
116
- <span class="truncate">${sessions[id].title}</span>
117
  </button>`;
118
  }).join('');
119
  }
120
 
121
  function appendMessage(role, content, displayContent) {
122
- if(!sessions[currentSid]) return;
 
 
123
  sessions[currentSid].messages.push({ role, content, displayContent });
124
 
125
  if (role === "user" && sessions[currentSid].messages.filter(m => m.role === "user").length === 1) {
@@ -143,7 +157,6 @@ function scrollBottom() {
143
  if(chatMessages) chatMessages.scrollTop = chatMessages.scrollHeight;
144
  }
145
 
146
- // Fallback Markdown jika Marked.js gagal load
147
  function simpleMarkdown(text) {
148
  let h = String(text || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
149
  h = h.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, c) => `<pre><code>${c.trim()}</code></pre>`);
@@ -222,6 +235,11 @@ async function sendChat() {
222
  if(chatTextarea) { chatTextarea.value = ""; chatTextarea.style.height = "auto"; }
223
  if($("welcome-msg")) $("welcome-msg").remove();
224
 
 
 
 
 
 
225
  setBusy(true);
226
  renderBubble("user", displayPrompt);
227
  appendMessage("user", fullPrompt, displayPrompt);
@@ -236,7 +254,7 @@ async function sendChat() {
236
  const payload = {
237
  prompt: fullPrompt,
238
  model: $("model-select") ? $("model-select").value : (appSettings?.current_model || ""),
239
- messages: sessions[currentSid].messages.slice(0, -1)
240
  };
241
 
242
  const res = await fetch("/api/chat", {
@@ -341,8 +359,7 @@ function closeSettings() {
341
  if($("settings-modal")) $("settings-modal").classList.add("hidden");
342
  }
343
 
344
- // Event Listeners Modal Settings
345
- addEvt("btn-open-settings", "click", openSettings); // Sesuai dengan ID HTML terbaru
346
  addEvt("btn-close-settings", "click", closeSettings);
347
  addEvt("btn-cancel-settings", "click", closeSettings);
348
 
@@ -391,9 +408,9 @@ addEvt("btn-save-settings", "click", async () => {
391
  appSettings = await res.json();
392
  populateModelSelect();
393
  closeSettings();
394
- renderSys("Settings berhasil disimpan.");
395
  } catch (err) {
396
- renderSys(`Gagal save setting: ${err.message}`, true);
397
  }
398
  });
399
 
@@ -424,7 +441,7 @@ addEvt("btn-validate-doi-submit", "click", async () => {
424
  const res = await fetch("/api/validate_doi", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ doi }) });
425
  const data = await res.json();
426
  if (!res.ok || data.error) {
427
- resDiv.innerHTML = `<p class="text-red-500 font-medium">Error: ${data.error || "Gagal validasi"}</p>`;
428
  } else {
429
  resDiv.innerHTML = `
430
  <div class="space-y-2">
@@ -464,7 +481,7 @@ addEvt("sidebar-overlay", "click", toggleSidebar);
464
  addEvt("btn-new-chat", "click", newSession);
465
 
466
  function handleClear() {
467
- if (!currentSid) return;
468
  sessions[currentSid].messages = [];
469
  sessions[currentSid].title = "New Chat";
470
  saveSessions();
 
1
  /**
2
  * ORBIT – Educational Research Assistant
3
+ * V2 SCRIPT: Anti-Crash, Safe Storage, Full Logic
4
  */
5
 
6
  // ─────────────────────────────────────
 
13
  };
14
 
15
  // ─────────────────────────────────────
16
+ // 2. State & Data (GANTI KEY KE V2 BIAR BERSIH)
17
  // ─────────────────────────────────────
18
  let currentUser = null;
19
  let appSettings = null;
20
+ // Pakai key baru "orbit_sessions_v2" untuk menghindari data korup lama
21
+ let sessions = JSON.parse(localStorage.getItem('orbit_sessions_v2')) || {};
22
  let currentSid = null;
23
  let pdfText = null;
24
  let pdfFilename = null;
 
51
  } catch (error) {
52
  console.error("Init Error:", error);
53
  } finally {
 
54
  populateModelSelect();
55
 
56
+ // Bersihkan data jika bentuknya Array (korup dari versi lama)
57
+ if (Array.isArray(sessions)) {
58
+ sessions = {};
59
+ saveSessions();
60
+ }
61
+
62
  const ids = Object.keys(sessions).sort((a, b) => Number(b) - Number(a));
63
  if (ids.length > 0) {
64
  loadSession(ids[0]);
 
72
  // 4. Session & History Logic
73
  // ─────────────────────────────────────
74
  function saveSessions() {
75
+ localStorage.setItem('orbit_sessions_v2', JSON.stringify(sessions));
76
  }
77
 
78
  function newSession() {
 
84
  function loadSession(id) {
85
  if (!sessions[id]) return;
86
  currentSid = id;
87
+
88
+ // Sabuk pengaman: Pastikan array messages selalu ada
89
+ if (!sessions[currentSid].messages) {
90
+ sessions[currentSid].messages = [];
91
+ }
92
+
93
  if(chatMessages) chatMessages.innerHTML = '';
94
 
95
  const msgs = sessions[id].messages || [];
 
125
  return `
126
  <button onclick="window.loadSession('${id}')" class="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm transition-all text-left truncate ${activeClass}">
127
  <svg class="w-4 h-4 shrink-0 opacity-60" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"></path></svg>
128
+ <span class="truncate">${sessions[id].title || "New Chat"}</span>
129
  </button>`;
130
  }).join('');
131
  }
132
 
133
  function appendMessage(role, content, displayContent) {
134
+ if(!sessions[currentSid]) newSession();
135
+ if(!sessions[currentSid].messages) sessions[currentSid].messages = [];
136
+
137
  sessions[currentSid].messages.push({ role, content, displayContent });
138
 
139
  if (role === "user" && sessions[currentSid].messages.filter(m => m.role === "user").length === 1) {
 
157
  if(chatMessages) chatMessages.scrollTop = chatMessages.scrollHeight;
158
  }
159
 
 
160
  function simpleMarkdown(text) {
161
  let h = String(text || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
162
  h = h.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, c) => `<pre><code>${c.trim()}</code></pre>`);
 
235
  if(chatTextarea) { chatTextarea.value = ""; chatTextarea.style.height = "auto"; }
236
  if($("welcome-msg")) $("welcome-msg").remove();
237
 
238
+ // Safety check session
239
+ if (!sessions[currentSid] || !sessions[currentSid].messages) {
240
+ newSession();
241
+ }
242
+
243
  setBusy(true);
244
  renderBubble("user", displayPrompt);
245
  appendMessage("user", fullPrompt, displayPrompt);
 
254
  const payload = {
255
  prompt: fullPrompt,
256
  model: $("model-select") ? $("model-select").value : (appSettings?.current_model || ""),
257
+ messages: sessions[currentSid].messages.slice(0, -1) // Aman karena udah di-check di atas
258
  };
259
 
260
  const res = await fetch("/api/chat", {
 
359
  if($("settings-modal")) $("settings-modal").classList.add("hidden");
360
  }
361
 
362
+ addEvt("btn-open-settings", "click", openSettings);
 
363
  addEvt("btn-close-settings", "click", closeSettings);
364
  addEvt("btn-cancel-settings", "click", closeSettings);
365
 
 
408
  appSettings = await res.json();
409
  populateModelSelect();
410
  closeSettings();
411
+ renderSys("Settings saved.");
412
  } catch (err) {
413
+ renderSys(`Failed to save: ${err.message}`, true);
414
  }
415
  });
416
 
 
441
  const res = await fetch("/api/validate_doi", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ doi }) });
442
  const data = await res.json();
443
  if (!res.ok || data.error) {
444
+ resDiv.innerHTML = `<p class="text-red-500 font-medium">Error: ${data.error || "Failed"}</p>`;
445
  } else {
446
  resDiv.innerHTML = `
447
  <div class="space-y-2">
 
481
  addEvt("btn-new-chat", "click", newSession);
482
 
483
  function handleClear() {
484
+ if (!currentSid || !sessions[currentSid]) return;
485
  sessions[currentSid].messages = [];
486
  sessions[currentSid].title = "New Chat";
487
  saveSessions();