Skip to content

Commit 8e1edf0

Browse files
harryli0088Harry Li
andauthored
Chat api restructure (#12)
* progress restructuring * useMainChatAPI * rearranged runQuery to show results faster * edited styling * copyright, added LLM warning to query history names * added linkq status type, refactored LinkQChatMessageType * linkq status checkpoint * fixed type issues, added status badge * can edit API key through UI * separated settings component --------- Co-authored-by: Harry Li <harry.li@ll.mit.edu>
1 parent 23de07d commit 8e1edf0

28 files changed

+682
-355
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# duplicate this file and rename the new file as .env.local
22

3+
VITE_BASE_URL=
34
VITE_OPENAI_API_KEY=
45
VITE_DEMO_MODE=false
56

src/App.module.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,5 @@
2020
#results-content {
2121
color: white;
2222
padding: 1em;
23-
24-
#empty-results-message {
25-
text-align: center;
26-
}
2723
}
2824
}

src/App.tsx

Lines changed: 21 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,47 @@
11
// Copyright (c) 2024 Massachusetts Institute of Technology
22
// SPDX-License-Identifier: MIT
3-
import { Title } from '@mantine/core';
43

54
import { ApiKeyWarning } from 'components/ApiKeyWarning';
65
import { Chat } from 'components/Chat/Chat';
76
import { DemoModeModal } from 'components/DemoModeModal';
8-
import { ErrorMessage } from 'components/ErrorMessage';
97
import { IDTableContainer } from 'components/IDTable/IDTable';
10-
import { InfoModal } from 'components/InfoModal';
11-
import { LLMWarning } from 'components/LLMWarning';
128
import { QueryEditor } from 'components/QueryEditor/QueryEditor'
139
import { QueryVisualization } from "components/QueryVisualization/QueryVisualization";
14-
import { ResultsTable } from 'components/ResultsTable/ResultsTable';
10+
import { Results } from 'components/Results/Results';
1511

16-
import { useAppSelector } from 'redux/store';
17-
18-
import { useRunQuery, RunQueryProvider } from 'hooks/useRunQuery';
12+
import { MainChatAPIProvider } from 'hooks/useMainChatAPI';
13+
import { RunQueryProvider } from 'hooks/useRunQuery';
1914

2015
import styles from 'App.module.scss'
2116

2217

2318
function App() {
2419
return (
25-
<RunQueryProvider>
26-
<div id={styles["app"]}>
27-
<div id={styles["sidebar"]}>
28-
<Chat/>
29-
</div>
30-
31-
<div id={styles["content"]}>
32-
<QueryEditor/>
20+
<MainChatAPIProvider>
21+
<RunQueryProvider>
22+
<div id={styles["app"]}>
23+
<div id={styles["sidebar"]}>
24+
<Chat/>
25+
</div>
26+
27+
<div id={styles["content"]}>
28+
<QueryEditor/>
3329

34-
<IDTableContainer/>
30+
<IDTableContainer/>
3531

36-
<QueryVisualization/>
32+
<QueryVisualization/>
3733

38-
<div id={styles["results-content"]}>
39-
<Results/>
34+
<div id={styles["results-content"]}>
35+
<Results/>
36+
</div>
4037
</div>
4138
</div>
42-
</div>
4339

44-
<DemoModeModal/>
45-
<ApiKeyWarning/>
46-
</RunQueryProvider>
40+
<DemoModeModal/>
41+
<ApiKeyWarning/>
42+
</RunQueryProvider>
43+
</MainChatAPIProvider>
4744
)
4845
}
4946

5047
export default App
51-
52-
53-
function Results() {
54-
const { runQueryIsPending } = useRunQuery()
55-
const results = useAppSelector(state => state.results.results)
56-
57-
if(runQueryIsPending) {
58-
return <p>Loading...</p>
59-
}
60-
else if(results?.error) {
61-
return (
62-
<>
63-
<p>There was an error running your query</p>
64-
<pre>{results.error}</pre>
65-
</>
66-
)
67-
}
68-
else if(results?.data) {
69-
return (
70-
<>
71-
<Title order={4}>Results Summary from LLM</Title>
72-
{results.summary ? (
73-
<div>
74-
<LLMWarning>
75-
<p>This results summary was generated by an LLM that can make mistakes. Refer below to the Results Table from KG for ground-truth data.</p>
76-
<p>Note that the absence of data does not necessairly mean that there is no data. It is possible that the query did not find what that you are looking for.</p>
77-
</LLMWarning>
78-
79-
<p>{results.summary}</p>
80-
</div>
81-
) : <ErrorMessage>There was an error generating a summary.</ErrorMessage>}
82-
83-
<hr/>
84-
85-
<Title order={4}>
86-
Results Table from KG
87-
<InfoModal title="Results Table from KG">
88-
<p>These are ground-truth results retrieved from the KG using the query you executed.</p>
89-
<p>Note that the absence of data does not necessairly mean that there is no data. It is possible that the query did not find what that you are looking for.</p>
90-
</InfoModal>
91-
</Title>
92-
<ResultsTable data={results.data}/>
93-
</>
94-
)
95-
}
96-
else {
97-
return <p id={styles["empty-results-message"]}><b>Run a query to see results!</b></p>
98-
}
99-
}

src/components/ApiKeyWarning.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import { useAppSelector } from "redux/store"
55

6+
import { Settings } from "./Settings/Settings"
7+
68
import { IS_DEMO_MODE } from "utils/demoData"
79

810
export function ApiKeyWarning() {
@@ -17,7 +19,9 @@ export function ApiKeyWarning() {
1719
display: "flex", justifyContent: "center", alignItems: "center",
1820
zIndex: 1,
1921
}}>
20-
<p>You need to configure the <code>VITE_OPENAI_API_KEY</code> environment variable in your <code>.env.local</code> file.</p>
22+
<Settings/>
23+
24+
<p>You need to configure the <code>VITE_OPENAI_API_KEY</code> environment variable in your <code>.env.local</code> file or update your API key in the settings menu.</p>
2125
</div>
2226
)
2327
}

src/components/Chat/Chat.module.scss

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,8 @@
66
height: 100vh;
77
position: relative;
88

9-
#chat-settings-button {
10-
position: absolute;
11-
top: 0.5rem;
12-
left: 0.5rem;
13-
z-index: 1;
14-
}
15-
169
#chat-scroll-container {
17-
height: calc(100% - 35px - 1rem);
10+
height: calc(100% - 35px - 2.5rem);
1811
overflow-y: auto;
1912
margin-bottom: 3px;
2013
padding: 0.5rem;
@@ -41,8 +34,15 @@
4134
.chat {
4235
background-color: #444;
4336
padding: 0.5rem;
44-
margin-bottom: 0.5rem;
4537
border-radius: 5px;
38+
39+
&:not(:last-child) {
40+
margin-bottom: 0.5rem;
41+
}
42+
43+
button {
44+
margin-top: 0.5rem;
45+
}
4646
}
4747

4848
&.user {
@@ -55,10 +55,6 @@
5555

5656
&.system {
5757
justify-content: flex-end;
58-
59-
.chat {
60-
// background-color: #154360;
61-
}
6258
}
6359

6460
.copy-query-buttons {

src/components/Chat/Chat.tsx

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
import CodeMirror from '@uiw/react-codemirror';
55
import { StreamLanguage } from '@codemirror/language';
66
import { sparql } from '@codemirror/legacy-modes/mode/sparql';
7-
import { ActionIcon, Button, Checkbox, Modal, TextInput } from "@mantine/core";
8-
import { useEffect, useMemo, useRef, useState } from "react";
7+
import { Badge, Button, Modal, TextInput } from "@mantine/core";
8+
import { useEffect, useRef, useState } from "react";
99
import { useMutation } from "@tanstack/react-query";
10-
import { IconCaretRight, IconSettings, IconZoomCode } from '@tabler/icons-react';
10+
import { IconCaretRight, IconZoomCode } from '@tabler/icons-react';
1111

1212
import { ErrorMessage } from 'components/ErrorMessage';
1313
import { LLMWarning } from 'components/LLMWarning';
14+
import { Settings } from 'components/Settings/Settings';
1415

15-
import { useMakeChatGPTAPIInstance } from 'hooks/useMakeChatGPTAPIInstance';
16+
import { useMainChatAPI } from 'hooks/useMainChatAPI';
1617
import { useRunQuery } from 'hooks/useRunQuery';
1718

18-
import { addMessageToSimpleChatHistory, toggleShowFullChatHistory } from 'redux/chatHistorySlice';
19+
import { addMessageToSimpleChatHistory } from 'redux/chatHistorySlice';
1920
import { setQueryValue } from 'redux/queryValueSlice';
2021
import { useAppDispatch, useAppSelector } from 'redux/store';
2122

2223
import { handleUserChat } from 'utils/handleUserChat';
23-
import { INITIAL_SYSTEM_MESSAGE } from 'utils/knowledgeBase/prompts';
2424
import { tryParsingOutQuery } from 'utils/tryParsingOutQuery';
2525

2626
import styles from "./Chat.module.scss"
@@ -44,19 +44,11 @@ export function Chat() {
4444
}
4545
}, [chatHistory.length])
4646

47-
const [showSettingsModal, setShowSettingsModal] = useState<boolean>(false)
48-
const closeSettingsModal = () => setShowSettingsModal(false)
4947

5048
// const [inputText, setInputText] = useState<string>("Who won the 2023 Formula One Championship?"); // prefill the chat
5149
const [inputText, setInputText] = useState<string>("");
5250

53-
const makeChatGPTAPIInstance = useMakeChatGPTAPIInstance()
54-
const chatGPT = useMemo(() => {
55-
return makeChatGPTAPIInstance({
56-
chatId: 0,
57-
systemMessage: INITIAL_SYSTEM_MESSAGE,
58-
})
59-
},[])
51+
const chatAPI = useMainChatAPI()
6052

6153
const {error, isPending, mutate:submitChat, reset} = useMutation({
6254
mutationKey: ['submit-chat'],
@@ -68,13 +60,14 @@ export function Chat() {
6860
mutationFn: async (text:string) => {
6961
//add the user's message to the simple chat history
7062
dispatch(addMessageToSimpleChatHistory({
71-
chatId: chatGPT.chatId,
63+
chatId: chatAPI.chatId,
7264
content: text,
7365
name: "user",
7466
role: "user",
67+
stage: "Question Refinement",
7568
}))
7669

77-
const llmResponse = await handleUserChat(text, chatGPT)
70+
const llmResponse = await handleUserChat(text, chatAPI)
7871

7972
//add the LLM's final response to the simple chat
8073
dispatch(addMessageToSimpleChatHistory(llmResponse))
@@ -86,17 +79,7 @@ export function Chat() {
8679

8780
return (
8881
<div id={styles["chat-container"]}>
89-
<Modal opened={showSettingsModal} onClose={closeSettingsModal} title="Settings">
90-
<Checkbox
91-
checked={showFullChatHistory}
92-
onChange={() => dispatch(toggleShowFullChatHistory())}
93-
label="Show full chat history"
94-
/>
95-
</Modal>
96-
97-
<ActionIcon id={styles["chat-settings-button"]} size="sm" variant="filled" aria-label="Show Settings" onClick={() => setShowSettingsModal(true)}>
98-
<IconSettings/>
99-
</ActionIcon>
82+
<Settings/>
10083

10184
<div id={styles["chat-scroll-container"]}>
10285
{chatHistory.map((c, i) => {
@@ -121,7 +104,8 @@ export function Chat() {
121104
<ErrorMessage>{error.message}</ErrorMessage>
122105
</Modal>
123106
)}
124-
{isPending && <p className={styles.loading}>Loading...</p>}
107+
{/* {isPending && <p className={styles.loading}>Loading...</p>} */}
108+
<LinkQStatus chatIsPending={isPending}/>
125109

126110
<form
127111
onSubmit={e => {
@@ -156,6 +140,7 @@ function RenderLLMResponse({
156140
<LLMWarning>
157141
<p>This was generated by an LLM that can make mistakes.</p>
158142
</LLMWarning>
143+
<br/>
159144

160145
<RenderSparqlQuery
161146
pre={parsedQuery.pre}
@@ -217,11 +202,42 @@ function RenderSparqlQuery({
217202
</div>
218203
<pre>{post}</pre>
219204
<br/>
220-
<Button onClick={() => setInputText("You identified the wrong data. I was actually looking for: ")} style={{marginTop:"0.5rem"}}>You identified the wrong data</Button>
205+
<Button onClick={() => setInputText("You identified the wrong data. I was actually looking for: ")}>You identified the wrong data</Button>
221206
<br/>
222-
<Button onClick={() => setInputText("You misunderstood my question. I was actually asking about: ")} style={{marginTop:"0.5rem"}}>You misunderstood my question</Button>
207+
<Button onClick={() => setInputText("You misunderstood my question. I was actually asking about: ")}>You misunderstood my question</Button>
223208
<br/>
224209
<Button onClick={() => setInputText("I want to ask something different: ")}>I want to ask something different</Button>
225210
</>
226211
)
212+
}
213+
214+
215+
216+
function LinkQStatus({
217+
chatIsPending,
218+
}:{
219+
chatIsPending: boolean,
220+
}) {
221+
const fullChatHistory = useAppSelector(state => state.chatHistory.fullChatHistory)
222+
const { runQueryIsPending, summarizeResultsIsPending } = useRunQuery()
223+
224+
let color = "blue"
225+
let displayMessage = "Waiting for User Input"
226+
const stage = fullChatHistory.at(-1)?.stage
227+
if(chatIsPending) {
228+
color = "yellow"
229+
displayMessage = stage || ""
230+
}
231+
else if(runQueryIsPending) {
232+
color = "yellow"
233+
displayMessage = "Executing Query"
234+
}
235+
else if(summarizeResultsIsPending) {
236+
color = "yellow"
237+
displayMessage = "Query Summarization"
238+
}
239+
240+
return (
241+
<p className={styles.loading}><Badge color={color}>{displayMessage}</Badge></p>
242+
)
227243
}

src/components/LLMWarning.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const LLMWarning = ({
1515
{children}
1616
</Modal>
1717

18-
<ActionIcon size="xs" variant="filled" aria-label="LLM Hallucination Warning" color="yellow" onClick={open} style={{float:"right"}}>
18+
<ActionIcon size="xs" variant="filled" aria-label="LLM Hallucination Warning" color="yellow" onClick={open} style={{float:"right", marginTop: 0}}>
1919
<IconAlertTriangle/>
2020
</ActionIcon>
2121
</>

src/components/QueryEditor/QueryEditor.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useAppDispatch, useAppSelector } from 'redux/store';
1515
import { useRunQuery } from 'hooks/useRunQuery';
1616

1717
import styles from "./QueryEditor.module.scss"
18+
import { LLMWarning } from 'components/LLMWarning';
1819

1920
export function QueryEditor() {
2021
const dispatch = useAppDispatch()
@@ -48,7 +49,13 @@ export function QueryEditor() {
4849
</div>
4950

5051
<Modal opened={historyOpened} onClose={closeHistory} size="lg" withCloseButton={false}>
51-
<Title order={2}>Query History</Title>
52+
<Title order={2}>
53+
Query History
54+
55+
<LLMWarning>
56+
<p>These query names are generated by an LLM</p>
57+
</LLMWarning>
58+
</Title>
5259
<Divider/>
5360
{queryHistory.map((record,i) => {
5461
return (
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* Copyright (c) 2024 Massachusetts Institute of Technology */
2+
/* SPDX-License-Identifier: MIT */
3+
4+
#empty-results-message {
5+
text-align: center;
6+
}

0 commit comments

Comments
 (0)