zhlajiex commited on
Commit
4626437
·
1 Parent(s): 0aaf25d

UI: Implement Expandable Thought Core - Reasoning blocks (Kimi/DeepSeek) are now hidden by default behind a sleek toggle

Browse files
Files changed (1) hide show
  1. backend/public/chat.html +37 -5
backend/public/chat.html CHANGED
@@ -82,6 +82,16 @@
82
  .source-pill:hover { background: var(--accent); color: #000; border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 243, 255, 0.3); }
83
  .source-pill img { width: 12px; height: 12px; border-radius: 2px; }
84
 
 
 
 
 
 
 
 
 
 
 
85
  .input-anchor { position: absolute; bottom: 0; left: 0; width: 100%; padding: 1.5rem; background: linear-gradient(transparent, #000 60%); pointer-events: none; z-index: 50; }
86
  .input-hub { max-width: 800px; margin: 0 auto; background: rgba(15, 15, 15, 0.98); backdrop-filter: blur(50px); border: 1px solid var(--border); border-radius: 2rem; padding: 0.5rem 1rem; display: flex; align-items: center; gap: 0.5rem; pointer-events: auto; box-shadow: 0 20px 50px rgba(0,0,0,0.8); transition: border-color 0.3s; }
87
  .input-hub:focus-within { border-color: var(--accent); }
@@ -444,14 +454,35 @@
444
  const div = document.createElement('div');
445
  div.className = `msg-node ${role}`;
446
 
447
- // NEURAL SOURCE PARSER
 
448
  let cleanText = text;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  let sourceLinks = [];
450
- const sourceMarker = text.match(/SOURCES:/i);
451
  if (role === 'ai' && sourceMarker) {
452
  const markerIndex = sourceMarker.index;
453
- cleanText = text.substring(0, markerIndex);
454
- const rawLinks = text.substring(markerIndex).match(/(https?:\/\/[^\s\)]+)/g);
 
 
455
  if (rawLinks) sourceLinks = [...new Set(rawLinks)];
456
  }
457
 
@@ -462,7 +493,8 @@
462
  </div>
463
  <div class="bubble">
464
  ${attachmentUrl ? `<img src="${attachmentUrl}" class="max-w-[300px] w-full rounded-xl mb-3 border border-white/10 shadow-lg cursor-zoom-in block" onclick="window.open(this.src)">` : ''}
465
- <div class="prose max-w-none">${marked.parse(cleanText)}</div>
 
466
  ${sourceLinks.length > 0 ? `<div class="sources-grid"></div>` : ''}
467
  </div>
468
  <div class="msg-toolkit">
 
82
  .source-pill:hover { background: var(--accent); color: #000; border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 243, 255, 0.3); }
83
  .source-pill img { width: 12px; height: 12px; border-radius: 2px; }
84
 
85
+ /* THINKING / REASONING BLOCKS */
86
+ .thought-core { margin-bottom: 1rem; border-left: 2px solid rgba(0, 243, 255, 0.2); background: rgba(0, 243, 255, 0.02); border-radius: 0 1rem 1rem 0; overflow: hidden; transition: 0.3s; }
87
+ .thought-header { padding: 8px 15px; display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; background: rgba(0, 243, 255, 0.05); }
88
+ .thought-header:hover { background: rgba(0, 243, 255, 0.1); }
89
+ .thought-header i { font-size: 8px; color: var(--accent); transition: transform 0.3s; }
90
+ .thought-header span { font-family: 'JetBrains Mono'; font-size: 8px; font-weight: 900; color: rgba(0, 243, 255, 0.5); text-transform: uppercase; letter-spacing: 0.1em; }
91
+ .thought-content { padding: 15px; font-size: 12px; color: rgba(255,255,255,0.5); line-height: 1.5; font-style: italic; display: none; border-top: 1px solid rgba(0, 243, 255, 0.05); }
92
+ .thought-core.expanded .thought-content { display: block; }
93
+ .thought-core.expanded .thought-header i { transform: rotate(90deg); }
94
+
95
  .input-anchor { position: absolute; bottom: 0; left: 0; width: 100%; padding: 1.5rem; background: linear-gradient(transparent, #000 60%); pointer-events: none; z-index: 50; }
96
  .input-hub { max-width: 800px; margin: 0 auto; background: rgba(15, 15, 15, 0.98); backdrop-filter: blur(50px); border: 1px solid var(--border); border-radius: 2rem; padding: 0.5rem 1rem; display: flex; align-items: center; gap: 0.5rem; pointer-events: auto; box-shadow: 0 20px 50px rgba(0,0,0,0.8); transition: border-color 0.3s; }
97
  .input-hub:focus-within { border-color: var(--accent); }
 
454
  const div = document.createElement('div');
455
  div.className = `msg-node ${role}`;
456
 
457
+ // NEURAL THOUGHT PARSER
458
+ let thoughtHtml = "";
459
  let cleanText = text;
460
+
461
+ // Detect various thought patterns (DeepSeek, Kimi, etc.)
462
+ const thoughtMatch = text.match(/<(thought|thinking)>([\s\S]*?)<\/\1>|\[THOUGHT\]([\s\S]*?)\[\/THOUGHT\]/i);
463
+ if (role === 'ai' && thoughtMatch) {
464
+ const thoughtContent = (thoughtMatch[2] || thoughtMatch[3]).trim();
465
+ cleanText = text.replace(thoughtMatch[0], "").trim();
466
+ thoughtHtml = `
467
+ <div class="thought-core">
468
+ <div class="thought-header" onclick="this.parentElement.classList.toggle('expanded')">
469
+ <i class="fas fa-chevron-right"></i>
470
+ <span>Neural Thought Trace [DECRYPTED]</span>
471
+ </div>
472
+ <div class="thought-content">${marked.parse(thoughtContent)}</div>
473
+ </div>
474
+ `;
475
+ }
476
+
477
+ // NEURAL SOURCE PARSER
478
  let sourceLinks = [];
479
+ const sourceMarker = cleanText.match(/SOURCES:/i);
480
  if (role === 'ai' && sourceMarker) {
481
  const markerIndex = sourceMarker.index;
482
+ const finalReply = cleanText.substring(0, markerIndex);
483
+ const linkSection = cleanText.substring(markerIndex);
484
+ cleanText = finalReply;
485
+ const rawLinks = linkSection.match(/(https?:\/\/[^\s\)]+)/g);
486
  if (rawLinks) sourceLinks = [...new Set(rawLinks)];
487
  }
488
 
 
493
  </div>
494
  <div class="bubble">
495
  ${attachmentUrl ? `<img src="${attachmentUrl}" class="max-w-[300px] w-full rounded-xl mb-3 border border-white/10 shadow-lg cursor-zoom-in block" onclick="window.open(this.src)">` : ''}
496
+ ${thoughtHtml}
497
+ <div class="prose max-w-none">${marked.parse(cleanText || (thoughtHtml ? "..." : "[SIGNAL]"))}</div>
498
  ${sourceLinks.length > 0 ? `<div class="sources-grid"></div>` : ''}
499
  </div>
500
  <div class="msg-toolkit">