wop commited on
Commit
aed95f4
·
verified ·
1 Parent(s): 3d9e926

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +92 -10
templates/index.html CHANGED
@@ -3,6 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 
6
  <title>{{ app_title }}</title>
7
  <style>
8
  :root {
@@ -57,9 +58,10 @@
57
  .brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
58
  .logo {
59
  width: 30px; height: 30px; border-radius: 10px;
60
- display: grid; place-items: center; font-size: 15px;
61
- background: linear-gradient(135deg, var(--accent), var(--accent2));
62
  box-shadow: 0 6px 18px rgba(108,131,255,.25);
 
63
  flex: 0 0 auto;
64
  }
65
  .brand-title { font-weight: 700; letter-spacing: -.03em; font-size: 15px; }
@@ -351,6 +353,10 @@
351
  background: rgba(255,255,255,.02);
352
  animation: fadeUp 200ms ease both;
353
  }
 
 
 
 
354
  .other-answer-head {
355
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
356
  color: var(--muted); font-family: var(--mono); font-size: 10px;
@@ -472,10 +478,42 @@
472
 
473
  /* ── Diffusion ── */
474
  .diffusion-text {
475
- filter: blur(4px); opacity: .4;
476
- transition: filter 600ms ease, opacity 600ms ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  }
478
- .diffusion-text.revealed { filter: blur(0); opacity: 1; }
479
 
480
  /* ── Composer (questions only) ── */
481
  .compose {
@@ -621,7 +659,7 @@
621
  <div id="app">
622
  <div id="topbar">
623
  <div class="brand">
624
- <div class="logo">🧠</div>
625
  <div>
626
  <div class="brand-title">Human Intelligence</div>
627
  <div class="brand-sub">community answers</div>
@@ -694,6 +732,7 @@
694
  clientId: null,
695
  conversation: null,
696
  currentQuestion: "",
 
697
  loading: false,
698
  animMode: localStorage.getItem("hi_anim") || "none",
699
  };
@@ -740,6 +779,16 @@
740
  requestAnimationFrame(() => { c.scrollTop = c.scrollHeight; });
741
  }
742
  function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
 
 
 
 
 
 
 
 
 
 
743
 
744
  async function animateText(el, text) {
745
  const mode = S.animMode;
@@ -764,10 +813,14 @@
764
  await sleep(d);
765
  }
766
  } else if (mode === "diffusion") {
767
- el.innerHTML = `<span class="diffusion-text">${nl2br(text)}</span>`;
768
  scrollBottom();
769
- await sleep(80);
770
- el.querySelector(".diffusion-text").classList.add("revealed");
 
 
 
 
771
  } else {
772
  el.innerHTML = nl2br(text);
773
  }
@@ -910,6 +963,28 @@
910
  </div>`;
911
  }
912
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
913
  /* ── Main render ── */
914
  async function renderConversation(questionText, doAnimate) {
915
  const tr = $("transcript");
@@ -948,6 +1023,7 @@
948
  <div class="bubble no-answer-bubble">No answer yet. Be the first to write one.</div>
949
  <div class="turn-meta"><span class="chip warn">awaiting answer</span></div>
950
  ${renderWriteAnswer()}
 
951
  </div>
952
  </div>`);
953
  } else {
@@ -960,6 +1036,7 @@
960
  ${renderAnswerBlock(best, 0, true)}
961
  ${renderWriteAnswer()}
962
  ${renderOtherAnswers(answers)}
 
963
  </div>
964
  </div>`);
965
 
@@ -1089,7 +1166,9 @@
1089
  ws.textContent = "Saving…";
1090
  showStatus("Saving answer…");
1091
  const res = await callAPI("answer", {
1092
- conversation_id: S.conversation.id, text,
 
 
1093
  });
1094
  hideStatus();
1095
  ws.disabled = false; ws.textContent = orig;
@@ -1129,6 +1208,7 @@
1129
  if (!res.ok) { toast(res.error||"Error","bad"); return; }
1130
  S.conversation = res.conversation;
1131
  S.currentQuestion = q;
 
1132
  save();
1133
  toast(res.matched ? "Existing answer found" : "New question created", "good");
1134
  await renderConversation(q, true);
@@ -1159,6 +1239,7 @@
1159
  if (res.ok && res.conversation) {
1160
  S.conversation = res.conversation;
1161
  S.currentQuestion = res.conversation.question || "";
 
1162
  renderConversation(S.currentQuestion, false);
1163
  }
1164
  }
@@ -1166,6 +1247,7 @@
1166
  function newChat() {
1167
  S.conversation = null;
1168
  S.currentQuestion = "";
 
1169
  localStorage.removeItem("hi_last_cid");
1170
  $("transcript").innerHTML = "";
1171
  $("welcome").style.display = "block";
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="icon" type="image/png" href="/logo.png" />
7
  <title>{{ app_title }}</title>
8
  <style>
9
  :root {
 
58
  .brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
59
  .logo {
60
  width: 30px; height: 30px; border-radius: 10px;
61
+ display: block;
62
+ object-fit: cover;
63
  box-shadow: 0 6px 18px rgba(108,131,255,.25);
64
+ border: 1px solid rgba(255,255,255,.08);
65
  flex: 0 0 auto;
66
  }
67
  .brand-title { font-weight: 700; letter-spacing: -.03em; font-size: 15px; }
 
353
  background: rgba(255,255,255,.02);
354
  animation: fadeUp 200ms ease both;
355
  }
356
+ .other-answer-card.related {
357
+ background: linear-gradient(180deg, rgba(108,131,255,.05), rgba(255,255,255,.02));
358
+ border-color: rgba(108,131,255,.16);
359
+ }
360
  .other-answer-head {
361
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
362
  color: var(--muted); font-family: var(--mono); font-size: 10px;
 
478
 
479
  /* ── Diffusion ── */
480
  .diffusion-text {
481
+ display: inline;
482
+ }
483
+ .diffusion-token {
484
+ display: inline-block;
485
+ filter: blur(var(--blur, 8px));
486
+ opacity: var(--opacity, .18);
487
+ transform: translateY(var(--shift, 0px));
488
+ transition:
489
+ filter 420ms cubic-bezier(.22,.61,.36,1),
490
+ opacity 320ms ease,
491
+ transform 360ms cubic-bezier(.22,.61,.36,1);
492
+ will-change: filter, opacity, transform;
493
+ }
494
+ .diffusion-token.revealed {
495
+ filter: blur(0);
496
+ opacity: 1;
497
+ transform: translateY(0);
498
+ }
499
+ .related-stack {
500
+ margin-top: 14px;
501
+ padding-top: 12px;
502
+ border-top: 1px solid rgba(255,255,255,.06);
503
+ }
504
+ .related-stack .chip {
505
+ margin-bottom: 6px;
506
+ }
507
+ .related-score {
508
+ color: var(--accent);
509
+ border-color: rgba(108,131,255,.22);
510
+ }
511
+ .related-note {
512
+ color: var(--muted);
513
+ font-size: 11px;
514
+ line-height: 1.5;
515
+ margin-top: 6px;
516
  }
 
517
 
518
  /* ── Composer (questions only) ── */
519
  .compose {
 
659
  <div id="app">
660
  <div id="topbar">
661
  <div class="brand">
662
+ <img class="logo" src="/logo.png" alt="Human Intelligence logo" />
663
  <div>
664
  <div class="brand-title">Human Intelligence</div>
665
  <div class="brand-sub">community answers</div>
 
732
  clientId: null,
733
  conversation: null,
734
  currentQuestion: "",
735
+ relatedAnswers: [],
736
  loading: false,
737
  animMode: localStorage.getItem("hi_anim") || "none",
738
  };
 
779
  requestAnimationFrame(() => { c.scrollTop = c.scrollHeight; });
780
  }
781
  function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
782
+ function diffusionTokens(text) {
783
+ return String(text || "").split(/(\s+)/).map((part, i) => {
784
+ if (!part) return "";
785
+ if (/^\s+$/.test(part)) return part.replace(/ /g, "&nbsp;").replace(/\n/g, "<br>");
786
+ const blur = (5 + (i % 4) * 1.4).toFixed(1);
787
+ const opacity = (0.14 + (i % 3) * 0.08).toFixed(2);
788
+ const shift = ((i % 2 === 0 ? 1 : -1) * ((i % 3) + 1)).toFixed(0);
789
+ return `<span class="diffusion-token" style="--blur:${blur}px;--opacity:${opacity};--shift:${shift}px;">${esc(part)}</span>`;
790
+ }).join("");
791
+ }
792
 
793
  async function animateText(el, text) {
794
  const mode = S.animMode;
 
813
  await sleep(d);
814
  }
815
  } else if (mode === "diffusion") {
816
+ el.innerHTML = `<span class="diffusion-text">${diffusionTokens(text)}</span>`;
817
  scrollBottom();
818
+ const tokens = Array.from(el.querySelectorAll(".diffusion-token"));
819
+ for (let i = 0; i < tokens.length; i++) {
820
+ tokens[i].classList.add("revealed");
821
+ if (i % 5 === 0) scrollBottom();
822
+ await sleep(26 + Math.random() * 30);
823
+ }
824
  } else {
825
  el.innerHTML = nl2br(text);
826
  }
 
963
  </div>`;
964
  }
965
 
966
+ function renderRelated(rel) {
967
+ if (!rel || !rel.length) return "";
968
+
969
+ return `
970
+ <div class="related-stack">
971
+ <div class="chip muted">from similar questions</div>
972
+ ${rel.map(r => `
973
+ <div class="other-answer-card related">
974
+ <div class="other-answer-head">
975
+ <span class="chip matched">related</span>
976
+ <span>${esc(r.question || "")}</span>
977
+ <span>·</span>
978
+ <span class="chip related-score">score ${(Number(r.score || 0)).toFixed(2)}</span>
979
+ </div>
980
+ <div class="other-answer-text">${nl2br(r.answer || "")}</div>
981
+ </div>
982
+ `).join("")}
983
+ <div class="related-note">These are read-only answers from semantically similar questions, so you can reuse context without writing into the wrong thread.</div>
984
+ </div>
985
+ `;
986
+ }
987
+
988
  /* ── Main render ── */
989
  async function renderConversation(questionText, doAnimate) {
990
  const tr = $("transcript");
 
1023
  <div class="bubble no-answer-bubble">No answer yet. Be the first to write one.</div>
1024
  <div class="turn-meta"><span class="chip warn">awaiting answer</span></div>
1025
  ${renderWriteAnswer()}
1026
+ ${renderRelated(S.relatedAnswers)}
1027
  </div>
1028
  </div>`);
1029
  } else {
 
1036
  ${renderAnswerBlock(best, 0, true)}
1037
  ${renderWriteAnswer()}
1038
  ${renderOtherAnswers(answers)}
1039
+ ${renderRelated(S.relatedAnswers)}
1040
  </div>
1041
  </div>`);
1042
 
 
1166
  ws.textContent = "Saving…";
1167
  showStatus("Saving answer…");
1168
  const res = await callAPI("answer", {
1169
+ conversation_id: S.conversation.id,
1170
+ text,
1171
+ question: S.currentQuestion,
1172
  });
1173
  hideStatus();
1174
  ws.disabled = false; ws.textContent = orig;
 
1208
  if (!res.ok) { toast(res.error||"Error","bad"); return; }
1209
  S.conversation = res.conversation;
1210
  S.currentQuestion = q;
1211
+ S.relatedAnswers = Array.isArray(res.related) ? res.related : [];
1212
  save();
1213
  toast(res.matched ? "Existing answer found" : "New question created", "good");
1214
  await renderConversation(q, true);
 
1239
  if (res.ok && res.conversation) {
1240
  S.conversation = res.conversation;
1241
  S.currentQuestion = res.conversation.question || "";
1242
+ S.relatedAnswers = [];
1243
  renderConversation(S.currentQuestion, false);
1244
  }
1245
  }
 
1247
  function newChat() {
1248
  S.conversation = null;
1249
  S.currentQuestion = "";
1250
+ S.relatedAnswers = [];
1251
  localStorage.removeItem("hi_last_cid");
1252
  $("transcript").innerHTML = "";
1253
  $("welcome").style.display = "block";