mohamedhassan22 commited on
Commit
452a375
·
verified ·
1 Parent(s): 6a8e23f

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +287 -55
static/index.html CHANGED
@@ -244,10 +244,89 @@
244
  .assistant-answer strong {
245
  color: #8b5cf6;
246
  }
247
- /* Image Grids */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  .images-grid {
249
  display: grid;
250
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
251
  gap: 1.5rem;
252
  margin-top: 1rem;
253
  }
@@ -266,7 +345,7 @@
266
  .image-card a {
267
  display: block;
268
  overflow: hidden;
269
- height: 180px;
270
  }
271
  .image-card img {
272
  width: 100%;
@@ -284,46 +363,86 @@
284
  .image-filename {
285
  font-weight: 600;
286
  color: #f1f5f9;
287
- font-size: 0.95rem;
288
  white-space: nowrap;
289
  overflow: hidden;
290
  text-overflow: ellipsis;
 
291
  }
292
- /* Text Sources */
293
- .source-card {
294
- background: rgba(30, 41, 59, 0.4);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  border: 1px solid var(--border-color);
296
- border-radius: 0.75rem;
297
- padding: 1.25rem;
298
- margin-top: 0.75rem;
299
- transition: background 0.2s;
 
 
300
  }
301
- .source-card:hover {
302
- background: rgba(30, 41, 59, 0.8);
303
- border-color: #475569;
 
 
304
  }
305
- .source-title {
 
 
 
 
 
 
 
 
 
 
306
  font-weight: 600;
307
- color: var(--primary);
308
- margin-bottom: 0.5rem;
309
  font-size: 0.95rem;
 
 
 
310
  }
311
- .source-excerpt {
312
- font-style: italic;
313
- color: #cbd5e1;
314
- font-size: 0.9rem;
315
- background: rgba(0, 0, 0, 0.2);
316
- padding: 0.75rem;
317
- border-radius: 0.5rem;
318
- border-left: 3px solid var(--primary);
319
- word-wrap: break-word;
320
  }
321
- .source-meta {
322
- margin-top: 0.75rem;
323
- font-size: 0.8rem;
324
- color: var(--text-muted);
325
- text-align: right;
326
  }
 
327
  /* Animations */
328
  @keyframes fadeInDown {
329
  from {
@@ -436,8 +555,9 @@
436
  return div.innerHTML;
437
  }
438
 
439
- async function askQuestion() {
440
- const question = input.value.trim();
 
441
  if (!question) return;
442
 
443
  // UI State updates
@@ -487,11 +607,86 @@
487
  assistantAnswer.innerHTML = `<strong>Assistant:</strong><br>${escapeHtml(data.answer).replace(/\n/g, '<br>')}`;
488
  messageBlock.appendChild(assistantAnswer);
489
 
490
- // Display Images
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  if (data.images && data.images.length > 0) {
492
- const relevantImages = data.images.filter(img => (img.score || 0) >= 0.3).slice(0, 3);
493
 
494
  if (relevantImages.length > 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  const imagesWrapper = document.createElement('div');
496
  imagesWrapper.className = 'images-grid';
497
 
@@ -504,33 +699,50 @@
504
  </a>
505
  <div class="image-meta">
506
  <div class="image-filename">${escapeHtml(img.filename || 'Unknown')}</div>
 
 
 
507
  </div>
508
  `;
509
  imagesWrapper.appendChild(div);
510
  });
511
-
512
- messageBlock.appendChild(imagesWrapper);
 
513
  }
514
  }
515
 
516
- // Display Texts
517
- if (data.texts && data.texts.length > 0) {
518
- const topTexts = data.texts.slice(0, 3);
519
-
520
- topTexts.forEach(txt => {
521
- const div = document.createElement('div');
522
- div.className = 'source-card';
523
- const truncatedText = txt.text.length > 200 ? txt.text.substring(0, 200) + '...' : txt.text;
524
- div.innerHTML = `
525
- <div class="source-title">${escapeHtml(txt.file || 'Document')}</div>
526
- <div class="source-excerpt">"${escapeHtml(truncatedText)}"</div>
527
- <div class="source-meta">
528
- Page ${escapeHtml(String(txt.page || 'N/A'))} • ${Math.round((txt.score || 0) * 100)}% match
529
- </div>
530
- `;
531
- messageBlock.appendChild(div);
532
- });
533
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
534
 
535
  chatHistoryContainer.appendChild(messageBlock);
536
 
@@ -557,6 +769,26 @@
557
  }
558
  }
559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  async function downloadPDFReport() {
561
  if (conversationData.length === 0) {
562
  alert('No conversation to download');
 
244
  .assistant-answer strong {
245
  color: #8b5cf6;
246
  }
247
+
248
+ /* Text Sources - Now displayed FIRST */
249
+ .sources-section {
250
+ margin-top: 1rem;
251
+ }
252
+
253
+ .sources-header {
254
+ font-weight: 600;
255
+ color: var(--primary);
256
+ margin-bottom: 0.75rem;
257
+ font-size: 1rem;
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 0.5rem;
261
+ }
262
+
263
+ .source-card {
264
+ background: rgba(30, 41, 59, 0.4);
265
+ border: 1px solid var(--border-color);
266
+ border-radius: 0.75rem;
267
+ padding: 1.25rem;
268
+ margin-bottom: 0.75rem;
269
+ transition: all 0.2s;
270
+ cursor: pointer;
271
+ }
272
+ .source-card:hover {
273
+ background: rgba(30, 41, 59, 0.8);
274
+ border-color: var(--primary);
275
+ transform: translateX(5px);
276
+ }
277
+ .source-title {
278
+ font-weight: 600;
279
+ color: var(--primary);
280
+ margin-bottom: 0.5rem;
281
+ font-size: 0.95rem;
282
+ display: flex;
283
+ align-items: center;
284
+ gap: 0.5rem;
285
+ }
286
+ .source-title svg {
287
+ flex-shrink: 0;
288
+ }
289
+ .source-excerpt {
290
+ font-style: italic;
291
+ color: #cbd5e1;
292
+ font-size: 0.9rem;
293
+ background: rgba(0, 0, 0, 0.2);
294
+ padding: 0.75rem;
295
+ border-radius: 0.5rem;
296
+ border-left: 3px solid var(--primary);
297
+ word-wrap: break-word;
298
+ line-height: 1.6;
299
+ }
300
+ .source-meta {
301
+ margin-top: 0.75rem;
302
+ font-size: 0.8rem;
303
+ color: var(--text-muted);
304
+ display: flex;
305
+ justify-content: space-between;
306
+ align-items: center;
307
+ }
308
+ .view-source-link {
309
+ color: var(--primary);
310
+ text-decoration: none;
311
+ font-weight: 500;
312
+ display: inline-flex;
313
+ align-items: center;
314
+ gap: 0.25rem;
315
+ transition: all 0.2s;
316
+ }
317
+ .view-source-link:hover {
318
+ color: #60a5fa;
319
+ text-decoration: underline;
320
+ }
321
+
322
+ /* Image Grids - Now displayed SECOND */
323
+ .images-section {
324
+ margin-top: 1.5rem;
325
+ }
326
+
327
  .images-grid {
328
  display: grid;
329
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
330
  gap: 1.5rem;
331
  margin-top: 1rem;
332
  }
 
345
  .image-card a {
346
  display: block;
347
  overflow: hidden;
348
+ height: 200px;
349
  }
350
  .image-card img {
351
  width: 100%;
 
363
  .image-filename {
364
  font-weight: 600;
365
  color: #f1f5f9;
366
+ font-size: 0.9rem;
367
  white-space: nowrap;
368
  overflow: hidden;
369
  text-overflow: ellipsis;
370
+ margin-bottom: 0.25rem;
371
  }
372
+ .image-source {
373
+ font-size: 0.75rem;
374
+ color: var(--text-muted);
375
+ }
376
+
377
+ /* Follow-up Question Box */
378
+ .followup-container {
379
+ max-width: 800px;
380
+ margin: 1.5rem auto 0;
381
+ padding: 1.5rem;
382
+ background: rgba(30, 41, 59, 0.5);
383
+ border-radius: 1rem;
384
+ border: 1px dashed var(--border-color);
385
+ }
386
+
387
+ .followup-label {
388
+ font-size: 0.9rem;
389
+ color: var(--text-muted);
390
+ margin-bottom: 0.75rem;
391
+ display: flex;
392
+ align-items: center;
393
+ gap: 0.5rem;
394
+ }
395
+
396
+ .followup-input-group {
397
+ display: flex;
398
+ gap: 0.75rem;
399
+ }
400
+
401
+ .followup-input-group input {
402
+ flex: 1;
403
+ background: rgba(15, 23, 42, 0.6);
404
  border: 1px solid var(--border-color);
405
+ padding: 0.75rem 1rem;
406
+ border-radius: 0.5rem;
407
+ font-size: 1rem;
408
+ color: white;
409
+ font-family: 'Outfit', sans-serif;
410
+ transition: all 0.2s;
411
  }
412
+
413
+ .followup-input-group input:focus {
414
+ outline: none;
415
+ border-color: var(--primary);
416
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
417
  }
418
+
419
+ .followup-input-group input::placeholder {
420
+ color: #64748b;
421
+ }
422
+
423
+ .followup-btn {
424
+ background: rgba(59, 130, 246, 0.2);
425
+ color: #93c5fd;
426
+ border: 1px solid var(--primary);
427
+ padding: 0.75rem 1.5rem;
428
+ border-radius: 0.5rem;
429
  font-weight: 600;
 
 
430
  font-size: 0.95rem;
431
+ cursor: pointer;
432
+ transition: all 0.2s;
433
+ white-space: nowrap;
434
  }
435
+
436
+ .followup-btn:hover:not(:disabled) {
437
+ background: rgba(59, 130, 246, 0.3);
438
+ border-color: #60a5fa;
 
 
 
 
 
439
  }
440
+
441
+ .followup-btn:disabled {
442
+ opacity: 0.5;
443
+ cursor: not-allowed;
 
444
  }
445
+
446
  /* Animations */
447
  @keyframes fadeInDown {
448
  from {
 
555
  return div.innerHTML;
556
  }
557
 
558
+ async function askQuestion(questionText = null) {
559
+ // Get question from parameter or main input
560
+ const question = questionText || input.value.trim();
561
  if (!question) return;
562
 
563
  // UI State updates
 
607
  assistantAnswer.innerHTML = `<strong>Assistant:</strong><br>${escapeHtml(data.answer).replace(/\n/g, '<br>')}`;
608
  messageBlock.appendChild(assistantAnswer);
609
 
610
+ // ========================================
611
+ // CHANGE 2: Display TEXT SOURCES FIRST
612
+ // ========================================
613
+ if (data.texts && data.texts.length > 0) {
614
+ const sourcesSection = document.createElement('div');
615
+ sourcesSection.className = 'sources-section';
616
+
617
+ const sourcesHeader = document.createElement('div');
618
+ sourcesHeader.className = 'sources-header';
619
+ sourcesHeader.innerHTML = `
620
+ <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
621
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
622
+ d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
623
+ </svg>
624
+ Referenced Sources
625
+ `;
626
+ sourcesSection.appendChild(sourcesHeader);
627
+
628
+ const topTexts = data.texts.slice(0, 3);
629
+
630
+ topTexts.forEach((txt, index) => {
631
+ const div = document.createElement('div');
632
+ div.className = 'source-card';
633
+ const truncatedText = txt.text.length > 250 ? txt.text.substring(0, 250) + '...' : txt.text;
634
+
635
+ // ========================================
636
+ // CHANGE 1: Add clickable link to source
637
+ // ========================================
638
+ const sourceLink = txt.link ? `<a href="${escapeHtml(txt.link)}" target="_blank" class="view-source-link" onclick="event.stopPropagation()">
639
+ View in document →
640
+ </a>` : '';
641
+
642
+ div.innerHTML = `
643
+ <div class="source-title">
644
+ <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
645
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
646
+ d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
647
+ </svg>
648
+ ${escapeHtml(txt.file || 'Document')}
649
+ </div>
650
+ <div class="source-excerpt">"${escapeHtml(truncatedText)}"</div>
651
+ <div class="source-meta">
652
+ <span>Page ${escapeHtml(String(txt.page || 'N/A'))} • ${Math.round((txt.score || 0) * 100)}% match</span>
653
+ ${sourceLink}
654
+ </div>
655
+ `;
656
+
657
+ // Make entire card clickable
658
+ if (txt.link) {
659
+ div.style.cursor = 'pointer';
660
+ div.onclick = () => window.open(txt.link, '_blank');
661
+ }
662
+
663
+ sourcesSection.appendChild(div);
664
+ });
665
+
666
+ messageBlock.appendChild(sourcesSection);
667
+ }
668
+
669
+ // ========================================
670
+ // CHANGE 2: Display IMAGES SECOND (and limit to 1-2)
671
+ // ========================================
672
  if (data.images && data.images.length > 0) {
673
+ const relevantImages = data.images.filter(img => (img.score || 0) >= 0.3).slice(0, 2); // Max 2 images
674
 
675
  if (relevantImages.length > 0) {
676
+ const imagesSection = document.createElement('div');
677
+ imagesSection.className = 'images-section';
678
+
679
+ const imagesHeader = document.createElement('div');
680
+ imagesHeader.className = 'sources-header';
681
+ imagesHeader.innerHTML = `
682
+ <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
683
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
684
+ d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
685
+ </svg>
686
+ Referenced Figures
687
+ `;
688
+ imagesSection.appendChild(imagesHeader);
689
+
690
  const imagesWrapper = document.createElement('div');
691
  imagesWrapper.className = 'images-grid';
692
 
 
699
  </a>
700
  <div class="image-meta">
701
  <div class="image-filename">${escapeHtml(img.filename || 'Unknown')}</div>
702
+ <div class="image-source">
703
+ ${escapeHtml(img.file || 'Unknown')} • Page ${escapeHtml(String(img.page || 'N/A'))}
704
+ </div>
705
  </div>
706
  `;
707
  imagesWrapper.appendChild(div);
708
  });
709
+
710
+ imagesSection.appendChild(imagesWrapper);
711
+ messageBlock.appendChild(imagesSection);
712
  }
713
  }
714
 
715
+ // ========================================
716
+ // CHANGE 3: Add follow-up question box
717
+ // ========================================
718
+ const followupContainer = document.createElement('div');
719
+ followupContainer.className = 'followup-container';
720
+ followupContainer.innerHTML = `
721
+ <div class="followup-label">
722
+ <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
723
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
724
+ d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
725
+ </svg>
726
+ Ask a follow-up question
727
+ </div>
728
+ <div class="followup-input-group">
729
+ <input type="text" placeholder="e.g., Can you explain that in more detail?" class="followup-input">
730
+ <button class="followup-btn" onclick="askFollowup(this)">
731
+ <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="display: inline; vertical-align: middle;">
732
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
733
+ </svg>
734
+ </button>
735
+ </div>
736
+ `;
737
+ messageBlock.appendChild(followupContainer);
738
+
739
+ // Add enter key support for follow-up input
740
+ const followupInput = followupContainer.querySelector('.followup-input');
741
+ followupInput.addEventListener('keypress', function(e) {
742
+ if (e.key === 'Enter') {
743
+ askFollowup(followupContainer.querySelector('.followup-btn'));
744
+ }
745
+ });
746
 
747
  chatHistoryContainer.appendChild(messageBlock);
748
 
 
769
  }
770
  }
771
 
772
+ // New function to handle follow-up questions
773
+ function askFollowup(button) {
774
+ const container = button.closest('.followup-container');
775
+ const followupInput = container.querySelector('.followup-input');
776
+ const followupQuestion = followupInput.value.trim();
777
+
778
+ if (!followupQuestion) return;
779
+
780
+ // Disable the follow-up input and button
781
+ followupInput.disabled = true;
782
+ button.disabled = true;
783
+ button.innerHTML = '...';
784
+
785
+ // Ask the question
786
+ askQuestion(followupQuestion);
787
+
788
+ // Clear the follow-up input
789
+ followupInput.value = '';
790
+ }
791
+
792
  async function downloadPDFReport() {
793
  if (conversationData.length === 0) {
794
  alert('No conversation to download');