LiamKhoaLe commited on
Commit
3992b0b
·
1 Parent(s): c102985

Upd UI with report link

Browse files
Files changed (3) hide show
  1. static/index.html +4 -4
  2. static/script.js +63 -35
  3. static/styles.css +18 -0
static/index.html CHANGED
@@ -203,15 +203,15 @@
203
  <div class="chat-input-wrapper">
204
  <textarea id="question" placeholder="Ask something about your documents..." rows="2" disabled></textarea>
205
  <button id="ask" class="btn-primary" disabled>
206
- <span class="btn-text">Ask</span>
207
  <span class="btn-loading" style="display:none;">
208
  <div class="spinner"></div>
209
  Thinking...
210
  </span>
211
  </button>
212
- <button id="report-toggle" class="btn-secondary btn-muted" title="Generate report from selected document" disabled>
213
- Report
214
- </button>
215
  </div>
216
  <div class="chat-hint" id="chat-hint">
217
  Upload documents first to start chatting
 
203
  <div class="chat-input-wrapper">
204
  <textarea id="question" placeholder="Ask something about your documents..." rows="2" disabled></textarea>
205
  <button id="ask" class="btn-primary" disabled>
206
+ <span class="btn-text">Submit</span>
207
  <span class="btn-loading" style="display:none;">
208
  <div class="spinner"></div>
209
  Thinking...
210
  </span>
211
  </button>
212
+ </div>
213
+ <div class="chat-underbar">
214
+ <a href="#" id="report-link" class="report-link" title="Generate report from selected document">Report</a>
215
  </div>
216
  <div class="chat-hint" id="chat-hint">
217
  Upload documents first to start chatting
static/script.js CHANGED
@@ -14,7 +14,7 @@
14
  const askBtn = document.getElementById('ask');
15
  const chatHint = document.getElementById('chat-hint');
16
  const messages = document.getElementById('messages');
17
- const reportToggle = document.getElementById('report-toggle');
18
  const loadingOverlay = document.getElementById('loading-overlay');
19
  const loadingMessage = document.getElementById('loading-message');
20
 
@@ -101,9 +101,12 @@
101
  } catch {}
102
  });
103
  }
104
- // Report trigger button
105
- if (reportToggle) {
106
- reportToggle.addEventListener('click', handleGenerateReport);
 
 
 
107
  }
108
  }
109
 
@@ -175,10 +178,10 @@
175
  const files = data.files || [];
176
  renderStoredFiles(files);
177
  // Enable Report button when at least one file exists
178
- if (reportToggle) {
179
- reportToggle.disabled = (files.length === 0);
180
- reportToggle.title = 'Generate report from selected document';
181
- reportToggle.classList.toggle('enabled', !reportToggle.disabled);
182
  }
183
  window.__sb_current_filenames = new Set((data.filenames || []).map(f => (f || '').toLowerCase()));
184
  } catch {}
@@ -496,31 +499,42 @@
496
  showButtonLoading(askBtn, true);
497
 
498
  try {
499
- const formData = new FormData();
500
- formData.append('user_id', user.user_id);
501
- formData.append('project_id', currentProject.project_id);
502
- formData.append('question', question);
503
- formData.append('k', '6');
504
-
505
- const response = await fetch('/chat', { method: 'POST', body: formData });
506
- const data = await response.json();
507
-
508
- if (response.ok) {
509
- // Remove thinking message
510
- thinkingMsg.remove();
511
-
512
- // Add assistant response
513
- appendMessage('assistant', data.answer || 'No answer received');
514
-
515
- // Save assistant message to chat history
516
- await saveChatMessage(user.user_id, currentProject.project_id, 'assistant', data.answer || 'No answer received');
517
-
518
- // Add sources if available
519
- if (data.sources && data.sources.length > 0) {
520
- appendSources(data.sources);
521
  }
522
  } else {
523
- throw new Error(data.detail || 'Failed to get answer');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
524
  }
525
  } catch (error) {
526
  thinkingMsg.remove();
@@ -536,6 +550,22 @@
536
  }
537
  }
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  function autoGrowTextarea() {
540
  if (!questionInput) return;
541
  questionInput.style.height = 'auto';
@@ -590,10 +620,8 @@
590
  if (tgt && tgt.classList && tgt.classList.contains('pill') && tgt.parentElement && tgt.parentElement.id === 'stored-file-items') {
591
  document.querySelectorAll('#stored-file-items .pill').forEach(el => el.classList.remove('active'));
592
  tgt.classList.add('active');
593
- if (reportToggle) {
594
- reportToggle.disabled = false;
595
- reportToggle.classList.add('enabled');
596
- }
597
  }
598
  });
599
 
 
14
  const askBtn = document.getElementById('ask');
15
  const chatHint = document.getElementById('chat-hint');
16
  const messages = document.getElementById('messages');
17
+ const reportLink = document.getElementById('report-link');
18
  const loadingOverlay = document.getElementById('loading-overlay');
19
  const loadingMessage = document.getElementById('loading-message');
20
 
 
101
  } catch {}
102
  });
103
  }
104
+ // Report link toggle
105
+ if (reportLink) {
106
+ reportLink.addEventListener('click', (e) => {
107
+ e.preventDefault();
108
+ toggleReportMode();
109
+ });
110
  }
111
  }
112
 
 
178
  const files = data.files || [];
179
  renderStoredFiles(files);
180
  // Enable Report button when at least one file exists
181
+ if (reportLink) {
182
+ // Disable visually by muted color when no files
183
+ reportLink.style.pointerEvents = (files.length === 0) ? 'none' : 'auto';
184
+ reportLink.title = 'Generate report from selected document';
185
  }
186
  window.__sb_current_filenames = new Set((data.filenames || []).map(f => (f || '').toLowerCase()));
187
  } catch {}
 
499
  showButtonLoading(askBtn, true);
500
 
501
  try {
502
+ // Branch: if report mode is active → call /report with textarea as instructions
503
+ if (isReportModeActive()) {
504
+ const filename = pickActiveFilename();
505
+ if (!filename) throw new Error('Please select a document to generate a report');
506
+ const form = new FormData();
507
+ form.append('user_id', user.user_id);
508
+ form.append('project_id', currentProject.project_id);
509
+ form.append('filename', filename);
510
+ form.append('outline_words', '200');
511
+ form.append('report_words', '1200');
512
+ form.append('instructions', question);
513
+ const response = await fetch('/report', { method: 'POST', body: form });
514
+ const data = await response.json();
515
+ if (response.ok) {
516
+ thinkingMsg.remove();
517
+ appendMessage('assistant', data.report_markdown || 'No report');
518
+ if (data.sources && data.sources.length) appendSources(data.sources);
519
+ } else {
520
+ throw new Error(data.detail || 'Failed to generate report');
 
 
 
521
  }
522
  } else {
523
+ const formData = new FormData();
524
+ formData.append('user_id', user.user_id);
525
+ formData.append('project_id', currentProject.project_id);
526
+ formData.append('question', question);
527
+ formData.append('k', '6');
528
+ const response = await fetch('/chat', { method: 'POST', body: formData });
529
+ const data = await response.json();
530
+ if (response.ok) {
531
+ thinkingMsg.remove();
532
+ appendMessage('assistant', data.answer || 'No answer received');
533
+ await saveChatMessage(user.user_id, currentProject.project_id, 'assistant', data.answer || 'No answer received');
534
+ if (data.sources && data.sources.length > 0) appendSources(data.sources);
535
+ } else {
536
+ throw new Error(data.detail || 'Failed to get answer');
537
+ }
538
  }
539
  } catch (error) {
540
  thinkingMsg.remove();
 
550
  }
551
  }
552
 
553
+ function toggleReportMode() {
554
+ if (!reportLink) return;
555
+ reportLink.classList.toggle('active');
556
+ }
557
+
558
+ function isReportModeActive() {
559
+ return reportLink && reportLink.classList.contains('active');
560
+ }
561
+
562
+ function pickActiveFilename() {
563
+ const candidates = Array.from(document.querySelectorAll('#stored-file-items .pill'));
564
+ let active = candidates.find(el => el.classList.contains('active'));
565
+ if (!active && candidates.length) active = candidates[0];
566
+ return active ? active.textContent.trim() : '';
567
+ }
568
+
569
  function autoGrowTextarea() {
570
  if (!questionInput) return;
571
  questionInput.style.height = 'auto';
 
620
  if (tgt && tgt.classList && tgt.classList.contains('pill') && tgt.parentElement && tgt.parentElement.id === 'stored-file-items') {
621
  document.querySelectorAll('#stored-file-items .pill').forEach(el => el.classList.remove('active'));
622
  tgt.classList.add('active');
623
+ // Enable link visually
624
+ if (reportLink) reportLink.classList.add('active');
 
 
625
  }
626
  });
627
 
static/styles.css CHANGED
@@ -833,6 +833,24 @@
833
  resize: none;
834
  }
835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836
  #question:focus {
837
  outline: none;
838
  border-color: var(--accent);
 
833
  resize: none;
834
  }
835
 
836
+ .chat-underbar {
837
+ display: flex;
838
+ justify-content: flex-end;
839
+ margin-top: 6px;
840
+ }
841
+
842
+ .report-link {
843
+ color: var(--muted);
844
+ text-decoration: underline;
845
+ cursor: pointer;
846
+ user-select: none;
847
+ }
848
+
849
+ .report-link.active {
850
+ color: var(--accent);
851
+ font-weight: 600;
852
+ }
853
+
854
  #question:focus {
855
  outline: none;
856
  border-color: var(--accent);