Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat settings #603

Merged
merged 2 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions app/components/Chatbot/ChatEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Link} from '@remix-run/react'
import MarkdownIt from 'markdown-it'
import QuestionMarkIcon from '~/components/icons-generated/QuestionMark'
import BotIcon from '~/components/icons-generated/Bot'
import LinkIcon from '~/components/icons-generated/Link'
import PersonIcon from '~/components/icons-generated/Person'
import StampyIcon from '~/components/icons-generated/Stampy'
import Contents from '~/components/Article/Contents'
Expand Down Expand Up @@ -104,8 +105,9 @@ const Reference = ({id, title, authors, source, url, index}: Citation) => {
<div>
<Authors authors={authors} />
<span>{' · '}</span>
<Link className="source-link" to={url}>
{referenceSources[source as keyof typeof referenceSources] || new URL(url).host}
<Link className="source-link" to={url} target="_blank" rel="noopener noreferrer">
{referenceSources[source as keyof typeof referenceSources] || new URL(url).host}{' '}
<LinkIcon width="16" height="16" />
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this icon will have to be changed, but this will suffice for styling

</Link>
</div>
</div>
Expand Down Expand Up @@ -158,7 +160,12 @@ const ChatbotReply = ({phase, content, citationsMap}: AssistantEntry) => {
}
})}
</div>
{citations?.slice(0, MAX_REFERENCES).map(Reference)}
{citations && citations.length > 0 && (
<>
<hr />
<div className="padding-top-32">{citations?.slice(0, MAX_REFERENCES).map(Reference)}</div>
</>
)}
{phase === 'followups' ? <p>Checking for followups...</p> : undefined}
</div>
)
Expand Down
12 changes: 9 additions & 3 deletions app/components/Chatbot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {Link, useFetcher} from '@remix-run/react'
import StampyIcon from '~/components/icons-generated/Stampy'
import SendIcon from '~/components/icons-generated/PlaneSend'
import Button from '~/components/Button'
import {queryLLM, Entry, AssistantEntry, StampyEntry, Followup} from '~/hooks/useChat'
import {queryLLM, Entry, AssistantEntry, StampyEntry, Followup, ChatSettings} from '~/hooks/useChat'
import ChatEntry from './ChatEntry'
import './widgit.css'
import {questionUrl} from '~/routesMapper'
Expand Down Expand Up @@ -138,7 +138,12 @@ const SplashScreen = ({
</>
)

export const Chatbot = ({question, questions}: {question?: string; questions?: string[]}) => {
type ChatbotProps = {
question?: string
questions?: string[]
settings?: ChatSettings
}
export const Chatbot = ({question, questions, settings}: ChatbotProps) => {
const [followups, setFollowups] = useState<Followup[]>()

// FIXME: Generate session id
Expand Down Expand Up @@ -231,7 +236,8 @@ export const Chatbot = ({question, questions}: {question?: string; questions?: s
[...history, message],
updateReply,
sessionId,
newController
newController,
settings
)
if (!newController.signal.aborted) {
updateReply(result)
Expand Down
13 changes: 13 additions & 0 deletions app/components/Chatbot/widgit.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@
width: 100%;
}
}

.settings-container {
position: absolute;
bottom: var(--spacing-16);
left: var(--spacing-16);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aw thanks. Feel free to do the minimum when it comes to CSS

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I will :D

.settings {
padding: var(--spacing-32);
margin-bottom: var(--spacing-24);
flex-direction: column;
gap: var(--spacing-24);
}
23 changes: 18 additions & 5 deletions app/hooks/useChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,18 @@ export type SearchResult = {
result: Entry
}

export type Mode = 'rookie' | 'concise' | 'default' | 'discord'
type Model =
| 'gpt-3.5-turbo'
| 'gpt-4'
| 'gpt-4-turbo-preview'
| 'claude-3-opus-20240229'
| 'claude-3-sonnet-20240229'
| 'claude-3-haiku-20240307'
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of these models should work, in case you want a faster/simpler model

export type Mode = 'rookie' | 'concise' | 'default'
export type ChatSettings = {
mode?: Mode
completions?: Model
}

const DATA_HEADER = 'data: '
const EVENT_END_HEADER = 'event: close'
Expand Down Expand Up @@ -229,7 +240,8 @@ export const extractAnswer = async (
const fetchLLM = async (
sessionId: string | undefined,
history: HistoryEntry[],
controller: AbortController
controller: AbortController,
settings?: ChatSettings
): Promise<Response | void> =>
fetch(CHATBOT_URL, {
signal: controller.signal,
Expand All @@ -240,18 +252,19 @@ const fetchLLM = async (
'Content-Type': 'application/json',
Accept: 'text/event-stream',
},
body: JSON.stringify({sessionId, history, settings: {mode: 'default'}}),
body: JSON.stringify({sessionId, history, settings}),
}).catch(ignoreAbort)

export const queryLLM = async (
history: HistoryEntry[],
setCurrent: (e: AssistantEntry) => void,
sessionId: string | undefined,
controller: AbortController
controller: AbortController,
settings?: ChatSettings
): Promise<SearchResult> => {
setCurrent({...makeEntry(), phase: 'started'})
// do SSE on a POST request.
const res = await fetchLLM(sessionId, history, controller)
const res = await fetchLLM(sessionId, history, controller, settings)

if (!res) {
return {result: {role: 'error', content: 'No response from server'}}
Expand Down
4 changes: 4 additions & 0 deletions app/root.css
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ svg {
cursor: pointer;
}

.full-height {
height: 100%;
}

/* for troubleshooting */

.pink {
Expand Down
40 changes: 39 additions & 1 deletion app/routes/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,62 @@
import {useState} from 'react'
import {ShouldRevalidateFunction, useSearchParams} from '@remix-run/react'
import SettingsIcon from '~/components/icons-generated/Settings'
import Page from '~/components/Page'
import Chatbot from '~/components/Chatbot'
import {ChatSettings, Mode} from '~/hooks/useChat'
import Button from '~/components/Button'

export const shouldRevalidate: ShouldRevalidateFunction = () => false

export default function App() {
const [params] = useSearchParams()
const [showSettings, setShowSettings] = useState(false)
const [chatSettings, setChatSettings] = useState({mode: 'default'} as ChatSettings)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change this to e.g. {mode: 'default', completions: 'gpt-3.5-turbo'} if you want to use a different model

const question = params.get('question') || undefined

const ModeButton = ({name, mode}: {name: string; mode: Mode}) => (
<Button
className={chatSettings.mode === mode ? 'primary-alt' : ''}
action={() => setChatSettings({...chatSettings, mode})}
>
{name}
</Button>
)

const stopBubbling = (e: any) => {
e.preventDefault()
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation()
}

return (
<Page noFooter>
<div className="page-body">
<div className="page-body full-height" onClick={stopBubbling}>
<Chatbot
question={question}
questions={[
'What is AI Safety?',
'How would the AI even get out in the world?',
'Do people seriously worry about existential risk from AI?',
]}
settings={chatSettings}
/>
<div className="settings-container" onClick={stopBubbling}>
{showSettings && (
<div className="settings bordered flex-container">
<div>Answer detail</div>
<ModeButton mode="default" name="Default" />
<ModeButton mode="rookie" name="Detailed" />
<ModeButton mode="concise" name="Concise" />
</div>
)}
<SettingsIcon
width="32"
height="32"
className="pointer"
onClick={() => setShowSettings((current) => !current)}
/>
</div>
</div>
</Page>
)
Expand Down
Loading