benroshan commited on
Commit
d203cbe
·
1 Parent(s): 46c1407

feat: add briefing UI — summary card + clickable suggested questions after upload

Browse files
frontend/src/App.jsx CHANGED
@@ -6,6 +6,8 @@ import ChatArea from "./components/ChatArea";
6
  function App() {
7
  const [documents, setDocuments] = useState([]);
8
  const [evalLog, setEvalLog] = useState([]);
 
 
9
 
10
  useEffect(() => {
11
  getDocuments().then((d) => setDocuments(d.documents || []));
@@ -14,12 +16,13 @@ function App() {
14
  async function handleNewConversation() {
15
  await clearMemory();
16
  setEvalLog([]);
 
 
17
  window.location.reload();
18
  }
19
 
20
  return (
21
  <div className="min-h-screen bg-gray-50 flex flex-col">
22
- {/* Header */}
23
  <header className="bg-white px-6 py-4 shrink-0 shadow-sm">
24
  <div className="flex items-center gap-3">
25
  <div className="w-1 h-8 bg-indigo-600 rounded-full" />
@@ -32,17 +35,21 @@ function App() {
32
  </div>
33
  </header>
34
 
35
- {/* Main */}
36
  <main className="flex-1 flex">
37
  <Sidebar
38
  documents={documents}
39
  setDocuments={setDocuments}
40
  onNewConversation={handleNewConversation}
41
  evalLog={evalLog}
 
 
 
42
  />
43
  <ChatArea
44
  onEvalEntry={(entry) => setEvalLog((prev) => [...prev, entry])}
45
  hasDocuments={documents.length > 0}
 
 
46
  />
47
  </main>
48
  </div>
 
6
  function App() {
7
  const [documents, setDocuments] = useState([]);
8
  const [evalLog, setEvalLog] = useState([]);
9
+ const [briefing, setBriefing] = useState(null);
10
+ const [suggestedQuestion, setSuggestedQuestion] = useState("");
11
 
12
  useEffect(() => {
13
  getDocuments().then((d) => setDocuments(d.documents || []));
 
16
  async function handleNewConversation() {
17
  await clearMemory();
18
  setEvalLog([]);
19
+ setBriefing(null);
20
+ setSuggestedQuestion("");
21
  window.location.reload();
22
  }
23
 
24
  return (
25
  <div className="min-h-screen bg-gray-50 flex flex-col">
 
26
  <header className="bg-white px-6 py-4 shrink-0 shadow-sm">
27
  <div className="flex items-center gap-3">
28
  <div className="w-1 h-8 bg-indigo-600 rounded-full" />
 
35
  </div>
36
  </header>
37
 
 
38
  <main className="flex-1 flex">
39
  <Sidebar
40
  documents={documents}
41
  setDocuments={setDocuments}
42
  onNewConversation={handleNewConversation}
43
  evalLog={evalLog}
44
+ onBriefing={setBriefing}
45
+ briefing={briefing}
46
+ onSuggestedQuestion={setSuggestedQuestion}
47
  />
48
  <ChatArea
49
  onEvalEntry={(entry) => setEvalLog((prev) => [...prev, entry])}
50
  hasDocuments={documents.length > 0}
51
+ suggestedQuestion={suggestedQuestion}
52
+ onSuggestedQuestionUsed={() => setSuggestedQuestion("")}
53
  />
54
  </main>
55
  </div>
frontend/src/components/ChatArea.jsx CHANGED
@@ -1,13 +1,20 @@
1
- import { useState } from "react";
2
  import { sendMessage } from "../api";
3
  import MessageBubble from "./MessageBubble";
4
 
5
- export default function ChatArea({ onEvalEntry, hasDocuments }) {
6
  const [messages, setMessages] = useState([]);
7
  const [input, setInput] = useState("");
8
  const [loading, setLoading] = useState(false);
9
  const [webSearch, setWebSearch] = useState(false);
10
 
 
 
 
 
 
 
 
11
  async function handleSend(e) {
12
  e.preventDefault();
13
  if (!input.trim() || loading || !hasDocuments) return;
 
1
+ import { useState, useEffect } from "react";
2
  import { sendMessage } from "../api";
3
  import MessageBubble from "./MessageBubble";
4
 
5
+ export default function ChatArea({ onEvalEntry, hasDocuments, suggestedQuestion, onSuggestedQuestionUsed }) {
6
  const [messages, setMessages] = useState([]);
7
  const [input, setInput] = useState("");
8
  const [loading, setLoading] = useState(false);
9
  const [webSearch, setWebSearch] = useState(false);
10
 
11
+ useEffect(() => {
12
+ if (suggestedQuestion) {
13
+ setInput(suggestedQuestion);
14
+ onSuggestedQuestionUsed?.();
15
+ }
16
+ }, [suggestedQuestion]);
17
+
18
  async function handleSend(e) {
19
  e.preventDefault();
20
  if (!input.trim() || loading || !hasDocuments) return;
frontend/src/components/Sidebar.jsx CHANGED
@@ -37,6 +37,8 @@ export default function Sidebar({
37
  onNewConversation,
38
  evalLog,
39
  onBriefing,
 
 
40
  }) {
41
  const [deletingDoc, setDeletingDoc] = useState(null);
42
 
@@ -79,6 +81,39 @@ export default function Sidebar({
79
  <FileUpload onUploadComplete={setDocuments} onBriefing={onBriefing} />
80
  </div>
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  {/* Uploaded Documents */}
83
  <div className="bg-gray-50/80 rounded-xl p-3.5">
84
  <h3 className="text-xs font-semibold text-indigo-500 uppercase tracking-wider mb-2.5">
 
37
  onNewConversation,
38
  evalLog,
39
  onBriefing,
40
+ briefing,
41
+ onSuggestedQuestion,
42
  }) {
43
  const [deletingDoc, setDeletingDoc] = useState(null);
44
 
 
81
  <FileUpload onUploadComplete={setDocuments} onBriefing={onBriefing} />
82
  </div>
83
 
84
+ {/* Briefing card */}
85
+ {briefing && (
86
+ <div className="bg-indigo-50 border border-indigo-100 rounded-xl p-3.5 space-y-2">
87
+ <h3 className="text-xs font-semibold text-indigo-500 uppercase tracking-wider truncate">
88
+ {briefing.doc_name.length > 30
89
+ ? briefing.doc_name.slice(0, 30) + "…"
90
+ : briefing.doc_name}
91
+ </h3>
92
+ <ul className="space-y-1">
93
+ {briefing.summary.map((point, i) => (
94
+ <li key={i} className="text-xs text-gray-600 flex gap-1.5">
95
+ <span className="text-indigo-400 shrink-0">•</span>
96
+ {point}
97
+ </li>
98
+ ))}
99
+ </ul>
100
+ {briefing.suggested_questions.length > 0 && (
101
+ <div className="pt-1 space-y-1">
102
+ <p className="text-xs text-indigo-400 font-medium">Try asking:</p>
103
+ {briefing.suggested_questions.map((q, i) => (
104
+ <button
105
+ key={i}
106
+ onClick={() => onSuggestedQuestion(q)}
107
+ className="block w-full text-left text-xs bg-white border border-indigo-200 rounded-lg px-2.5 py-1.5 text-gray-700 hover:bg-indigo-50 hover:border-indigo-400 transition-colors"
108
+ >
109
+ {q}
110
+ </button>
111
+ ))}
112
+ </div>
113
+ )}
114
+ </div>
115
+ )}
116
+
117
  {/* Uploaded Documents */}
118
  <div className="bg-gray-50/80 rounded-xl p-3.5">
119
  <h3 className="text-xs font-semibold text-indigo-500 uppercase tracking-wider mb-2.5">