From 5dd5223a4140c106f70563652a5b753cbaa6b03d Mon Sep 17 00:00:00 2001 From: Harry Li Date: Tue, 21 Jan 2025 17:20:51 -0500 Subject: [PATCH 01/10] progress restructuring --- .env | 1 + src/App.tsx | 39 ++++--- src/components/Chat/Chat.tsx | 105 +++++++++++++----- src/hooks/useMainChatAPIInstance.tsx | 32 ++++++ ...Instance.tsx => useMakeChatAPIInstance.ts} | 14 ++- src/hooks/useRunQuery.tsx | 8 +- src/redux/chatHistorySlice.ts | 12 +- src/redux/settingsSlice.ts | 17 ++- src/utils/{ChatGPTAPI.ts => ChatAPI.ts} | 75 +++++-------- src/utils/demoData.ts | 2 +- .../mintaka-wikidata/mintakaEvaluation.ts | 12 +- src/utils/handleUserChat.ts | 4 +- src/utils/queryBuildingWorkflow.ts | 10 +- src/utils/staticChat.ts | 4 +- src/utils/summarizeQueryResults.ts | 10 +- 15 files changed, 215 insertions(+), 130 deletions(-) create mode 100644 src/hooks/useMainChatAPIInstance.tsx rename src/hooks/{useMakeChatGPTAPIInstance.tsx => useMakeChatAPIInstance.ts} (79%) rename src/utils/{ChatGPTAPI.ts => ChatAPI.ts} (65%) diff --git a/.env b/.env index e0c98f1..94ca9cf 100644 --- a/.env +++ b/.env @@ -1,5 +1,6 @@ # duplicate this file and rename the new file as .env.local +VITE_BASE_URL= VITE_OPENAI_API_KEY= VITE_DEMO_MODE=false diff --git a/src/App.tsx b/src/App.tsx index 02bee58..7bb8609 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,32 +18,35 @@ import { useAppSelector } from 'redux/store'; import { useRunQuery, RunQueryProvider } from 'hooks/useRunQuery'; import styles from 'App.module.scss' +import { MainChatAPIProvider } from 'hooks/useMainChatAPIInstance'; function App() { return ( - -
-
- -
- -
- + + +
+
+ +
+ +
+ - + - + -
- +
+ +
-
- - -
+ + + +
) } @@ -73,7 +76,7 @@ function Results() {

This results summary was generated by an LLM that can make mistakes. Refer below to the Results Table from KG for ground-truth data.

-

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.

+

Note that the absence of data does not necessairly mean that there is actually no data in the data source. It is possible that the query did not find what that you are looking for.

{results.summary}

@@ -86,7 +89,7 @@ function Results() { Results Table from KG

These are ground-truth results retrieved from the KG using the query you executed.

-

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.

+

Note that the absence of data does not necessairly mean that there is actually no data in the data source. It is possible that the query did not find what that you are looking for.

diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx index 3d6e6cf..9e8629a 100644 --- a/src/components/Chat/Chat.tsx +++ b/src/components/Chat/Chat.tsx @@ -4,23 +4,23 @@ import CodeMirror from '@uiw/react-codemirror'; import { StreamLanguage } from '@codemirror/language'; import { sparql } from '@codemirror/legacy-modes/mode/sparql'; -import { ActionIcon, Button, Checkbox, Modal, TextInput } from "@mantine/core"; -import { useEffect, useMemo, useRef, useState } from "react"; -import { useMutation } from "@tanstack/react-query"; +import { ActionIcon, Button, Checkbox, Modal, Select, TextInput } from "@mantine/core"; +import { useContext, useEffect, useMemo, useRef, useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; import { IconCaretRight, IconSettings, IconZoomCode } from '@tabler/icons-react'; import { ErrorMessage } from 'components/ErrorMessage'; import { LLMWarning } from 'components/LLMWarning'; -import { useMakeChatGPTAPIInstance } from 'hooks/useMakeChatGPTAPIInstance'; +import { MainChatAPIContext } from 'hooks/useMainChatAPIInstance'; import { useRunQuery } from 'hooks/useRunQuery'; import { addMessageToSimpleChatHistory, toggleShowFullChatHistory } from 'redux/chatHistorySlice'; +import { setBaseURL, setModel } from 'redux/settingsSlice'; import { setQueryValue } from 'redux/queryValueSlice'; import { useAppDispatch, useAppSelector } from 'redux/store'; import { handleUserChat } from 'utils/handleUserChat'; -import { INITIAL_SYSTEM_MESSAGE } from 'utils/knowledgeBase/prompts'; import { tryParsingOutQuery } from 'utils/tryParsingOutQuery'; import styles from "./Chat.module.scss" @@ -44,19 +44,11 @@ export function Chat() { } }, [chatHistory.length]) - const [showSettingsModal, setShowSettingsModal] = useState(false) - const closeSettingsModal = () => setShowSettingsModal(false) // const [inputText, setInputText] = useState("Who won the 2023 Formula One Championship?"); // prefill the chat const [inputText, setInputText] = useState(""); - const makeChatGPTAPIInstance = useMakeChatGPTAPIInstance() - const chatGPT = useMemo(() => { - return makeChatGPTAPIInstance({ - chatId: 0, - systemMessage: INITIAL_SYSTEM_MESSAGE, - }) - },[]) + const chatAPI = useContext(MainChatAPIContext) const {error, isPending, mutate:submitChat, reset} = useMutation({ mutationKey: ['submit-chat'], @@ -68,13 +60,13 @@ export function Chat() { mutationFn: async (text:string) => { //add the user's message to the simple chat history dispatch(addMessageToSimpleChatHistory({ - chatId: chatGPT.chatId, + chatId: chatAPI.chatId, content: text, name: "user", role: "user", })) - const llmResponse = await handleUserChat(text, chatGPT) + const llmResponse = await handleUserChat(text, chatAPI) //add the LLM's final response to the simple chat dispatch(addMessageToSimpleChatHistory(llmResponse)) @@ -86,17 +78,7 @@ export function Chat() { return (
- - dispatch(toggleShowFullChatHistory())} - label="Show full chat history" - /> - - - setShowSettingsModal(true)}> - - +
{chatHistory.map((c, i) => { @@ -224,4 +206,73 @@ function RenderSparqlQuery({ ) +} + + + +function Settings() { + const dispatch = useAppDispatch() + + const baseURL = useAppSelector(state => state.settings.baseURL) + const model = useAppSelector(state => state.settings.model) + const showFullChatHistory = useAppSelector(state => state.chatHistory.showFullChatHistory) + + const [showSettingsModal, setShowSettingsModal] = useState(false) + const closeSettingsModal = () => setShowSettingsModal(false) + + const chatAPI = useContext(MainChatAPIContext) + + const {data, error, isLoading} = useQuery({ + queryKey: [baseURL], + queryFn: async () => { + //https://platform.openai.com/docs/api-reference/models/list + const list = await chatAPI.openAI.models.list() + return list.data.map(({id}) => id).sort() + }, + }) + useEffect(() => { + //if the model chosen is no longer in the list + if(data && !data.includes(model) && data[0]) { + //auto-pick the first option + dispatch(setModel(data[0])) + } + }, [data]) + + return ( + <> + + dispatch(toggleShowFullChatHistory())} + label="Show full chat history" + /> +
+ dispatch(setBaseURL(event.currentTarget.value))} + /> +
+ {isLoading ?

Loading models...

: ( + <> + value && dispatch(setModel(value))} - /> - {error && {error.message}} - - )} - -
- - setShowSettingsModal(true)}> - - - - ) -} - - function LinkQStatus({ chatIsPending, }:{ diff --git a/src/components/Settings/Settings.module.scss b/src/components/Settings/Settings.module.scss new file mode 100644 index 0000000..b8d122b --- /dev/null +++ b/src/components/Settings/Settings.module.scss @@ -0,0 +1,9 @@ +/* Copyright (c) 2024 Massachusetts Institute of Technology */ +/* SPDX-License-Identifier: MIT */ + +.settings-button { + position: absolute; + top: 0.5rem; + left: 0.5rem; + z-index: 1; +} \ No newline at end of file diff --git a/src/components/Settings/Settings.tsx b/src/components/Settings/Settings.tsx new file mode 100644 index 0000000..e6d1aa0 --- /dev/null +++ b/src/components/Settings/Settings.tsx @@ -0,0 +1,95 @@ +import { useEffect, useState } from "react" + +import { useQuery } from "@tanstack/react-query" + +import { ActionIcon, Checkbox, Modal, Select, TextInput } from "@mantine/core" +import { IconSettings } from "@tabler/icons-react" + +import { ErrorMessage } from "components/ErrorMessage" + +import { useMainChatAPI } from "hooks/useMainChatAPI" + +import { setApiKey, setBaseURL, setModel } from "redux/settingsSlice" +import { toggleShowFullChatHistory } from "redux/chatHistorySlice" +import { useAppDispatch, useAppSelector } from "redux/store" + +import styles from "./Settings.module.scss" + +export function Settings() { + const dispatch = useAppDispatch() + + const apiKey = useAppSelector(state => state.settings.apiKey) + const baseURL = useAppSelector(state => state.settings.baseURL) + const model = useAppSelector(state => state.settings.model) + const showFullChatHistory = useAppSelector(state => state.chatHistory.showFullChatHistory) + + const [showSettingsModal, setShowSettingsModal] = useState(false) + const closeSettingsModal = () => setShowSettingsModal(false) + + const chatAPI = useMainChatAPI() + + const {data, error, isLoading} = useQuery({ + queryKey: [baseURL], + queryFn: async () => { + //https://platform.openai.com/docs/api-reference/models/list + const list = await chatAPI.openAI.models.list() + return list.data.map(({id}) => id).sort() + }, + }) + useEffect(() => { + //if the model chosen is no longer in the list + if(data && !data.includes(model) && data[0]) { + //auto-pick the first option + dispatch(setModel(data[0])) + } + }, [data]) + + return ( + <> + + dispatch(toggleShowFullChatHistory())} + label="Show full chat history" + /> +
+ { + //IDK if this is necessary, but we don't want to accidentally send an API key to the wrong baseURL + dispatch(setApiKey("")) + dispatch(setBaseURL(event.currentTarget.value)) + }} + /> +
+ dispatch(setApiKey(event.currentTarget.value))} + /> +
+ {isLoading ?

Loading models...

: ( + <> +