Skip to content

Commit

Permalink
some improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
adnanfajlur committed Oct 20, 2024
1 parent 99a20e2 commit 94dc2be
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 32 deletions.
9 changes: 8 additions & 1 deletion app/libs/theme.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, createTheme, CSSVariablesResolver, DEFAULT_THEME, defaultVariantColorsResolver, isLightColor, parseThemeColor, rgba, Tooltip } from '@mantine/core'
import { Button, Container, createTheme, CSSVariablesResolver, DEFAULT_THEME, defaultVariantColorsResolver, isLightColor, parseThemeColor, rgba, Tooltip } from '@mantine/core'

export const theme = createTheme({
cursorType: 'pointer',
Expand All @@ -8,6 +8,13 @@ export const theme = createTheme({
autoContrast: true,
fontFamily: '"Inter", sans-serif',
headings: { fontFamily: '"Greycliff CF", sans-serif' },
breakpoints: {
xs: '36em',
sm: '52em',
md: '62em',
lg: '75em',
xl: '88em',
},
components: {
Tooltip: Tooltip.extend({
defaultProps: { withArrow: true, openDelay: 200 },
Expand Down
59 changes: 40 additions & 19 deletions app/routes/api/completion.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export async function action({ request, params }: ActionFunctionArgs) {

if (isNewConversation) {
conversation = await prisma.conversation.create({
data: { title: '', userId: user.id },
data: { title: 'New chat', userId: user.id },
include: conversationInclude,
})
} else {
Expand All @@ -42,6 +42,9 @@ export async function action({ request, params }: ActionFunctionArgs) {
return json({ message: 'Conversation is not found' }, { status: 404 })
}

const abortController = new AbortController()
const { signal } = abortController

return new Response(new ReadableStream({
async start(controller) {
function enqueue(event: string, data: any) {
Expand Down Expand Up @@ -74,15 +77,35 @@ export async function action({ request, params }: ActionFunctionArgs) {
model: 'gpt-4o-mini',
messages: messages as ChatCompletionMessageParam[],
user: user.id,
})
}, { signal })

stream.on('content', (content) => {
if (signal.aborted) {
stream.controller.abort()
return
}

enqueue('msg', { content })
})

const chatCompletion = await stream.finalChatCompletion()
const fullResponse = chatCompletion.choices[0]?.message?.content || ''

let generatedTitle = ''

if (isNewConversation) {
const newTitle = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
...messages as ChatCompletionMessageParam[],
{ role: 'assistant', content: fullResponse },
{ role: 'system', content: `Please give me a title for this conversation, like chatgpt does, without any symbol` },
],
})

generatedTitle = newTitle.choices[0]?.message.content?.trim() || conversation.title
}

const [assistantMessage] = await Promise.all([
prisma.message.create({
data: {
Expand All @@ -93,20 +116,9 @@ export async function action({ request, params }: ActionFunctionArgs) {
}),
(async () => {
if (isNewConversation) {
const generatedTitle = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
...messages as ChatCompletionMessageParam[],
{ role: 'assistant', content: fullResponse },
{ role: 'system', content: `Please give me a title for this conversation, like chatgpt does, without any symbol` },
],
})

const title = generatedTitle.choices[0]?.message.content?.trim() || content

await prisma.conversation.update({
where: { id: conversation.id, userId: user.id, deletedAt: null },
data: { title, updatedAt: new Date() },
data: { title: generatedTitle, updatedAt: new Date() },
})
} else {
await prisma.conversation.update({
Expand All @@ -119,15 +131,24 @@ export async function action({ request, params }: ActionFunctionArgs) {

enqueue('assistant-msg', { message: assistantMessage })
} catch (error) {
logger.error({
code: 'ERROR_OPENAI_STREAM',
error,
})
enqueue('error', { message: 'An error occured' })
if (error.name === 'AbortError') {
enqueue('aborted', { message: 'Request was aborted' })
} else {
logger.error({
code: 'ERROR_OPENAI_STREAM',
error,
})
enqueue('error', { message: 'An error occured' })
}
} finally {
controller.close()
}
},

cancel() {
console.log('logdev cancel')
abortController.abort()
},
}), {
headers: {
'Content-Type': 'text/event-stream',
Expand Down
12 changes: 7 additions & 5 deletions app/routes/conversation/conversation.route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const CONVERSATION_SUGGESTIONS = [
'Summarize a long document',
]

const CONTAINER_SIZE = 820

export const meta: MetaFunction = () => {
return [
{ title: 'Chat - Remix workshop' },
Expand Down Expand Up @@ -208,7 +210,7 @@ export default function ChatRoute() {
>
{!state.messages.length
? (
<Container size="sm" className="w-full grow flex flex-col items-center justify-center">
<Container size={CONTAINER_SIZE} className="w-full grow flex flex-col items-center justify-center">
<IconBrandReact size={52} stroke={1.4} />
<div className="grid grid-cols-2 gap-4 mt-10">
{CONVERSATION_SUGGESTIONS.map((suggestion) => (
Expand All @@ -232,15 +234,15 @@ export default function ChatRoute() {
{state.messages.map((message) => {
if (message.sender === 'user') {
return (
<Container size="sm" className="w-full" key={message.id}>
<Container size={CONTAINER_SIZE} className="w-full" key={message.id}>
<div className="bg-dark-6 w-fit max-w-[70%] rounded-3xl px-5 py-2.5 text-white ml-auto">
{message.content}
</div>
</Container>
)
} else {
return (
<Container size="sm" className="w-full flex gap-3 md:gap-5 lg:gap-6" key={message.id}>
<Container size={CONTAINER_SIZE} className="w-full flex gap-3 md:gap-5 lg:gap-6" key={message.id}>
<div className="text-dark-0 rounded-full border border-dark-4 h-fit p-1.5">
<IconBrandReact size={20} stroke={1.4} />
</div>
Expand All @@ -253,7 +255,7 @@ export default function ChatRoute() {
})}

{typeof state.completion === 'string' && (
<Container size="sm" className="w-full flex gap-3 md:gap-5 lg:gap-6">
<Container size={CONTAINER_SIZE} className="w-full flex gap-3 md:gap-5 lg:gap-6">
<div className="text-dark-0 rounded-full border border-dark-4 h-fit p-1.5">
<IconBrandReact size={20} stroke={1.4} />
</div>
Expand All @@ -268,7 +270,7 @@ export default function ChatRoute() {
</ScrollArea>
)}

<Container className="w-full mt-auto" size="sm">
<Container size={CONTAINER_SIZE} className="w-full mt-auto">
<ChatInput isLoading={state.isLoading} handleSubmit={handleSubmitMessage} />

<Text className="text-xs text-center" px="md" py="8px">
Expand Down
20 changes: 16 additions & 4 deletions app/routes/layout.route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,28 @@ export default function LayoutRoute() {
<Text>Are you sure you want to delete this conversation?</Text>

<div className="mt-6 flex justify-end gap-2">
<Button color="dark.7" disabled={state.isLoadingDelete} onClick={() => setState({ deleteConversation: null })}>Cancel</Button>
<Button color="red.8" loading={state.isLoadingDelete} onClick={handleDelete}>Delete</Button>
<Button
color="dark.7"
disabled={state.isLoadingDelete}
onClick={() => setState({ deleteConversation: null })}
>
Cancel
</Button>
<Button
color="red.8"
loading={state.isLoadingDelete}
onClick={handleDelete}
>
Delete
</Button>
</div>
</Modal>

<AppShell.Header withBorder={false}>
<div className="flex h-full items-center px-[20px] justify-between sm:justify-normal gap-4">
<Box visibleFrom="sm" className={cn('flex items-center', { hidden: state.desktopOpened })}>
<Tooltip label="Open sidebar">
<ActionIcon color="dark.7" size="40px" onClick={() => setState({ desktopOpened: false })}>
<ActionIcon color="dark.7" size="40px" onClick={() => setState({ desktopOpened: true })}>
<IconLayoutSidebar size={22} />
</ActionIcon>
</Tooltip>
Expand Down Expand Up @@ -196,7 +208,7 @@ export default function LayoutRoute() {
<AppShell.Navbar p="md" pt="sm" bg="dark.8" withBorder={false}>
<div className="flex flex-col gap-1">
<Tooltip label="Close sidebar">
<ActionIcon color="dark.8" size="40px" visibleFrom="sm" onClick={() => setState({ desktopOpened: true })}>
<ActionIcon color="dark.8" size="40px" visibleFrom="sm" onClick={() => setState({ desktopOpened: false })}>
<IconLayoutSidebar size={22} />
</ActionIcon>
</Tooltip>
Expand Down
3 changes: 2 additions & 1 deletion articles.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- https://andrelandgraf.dev/blog/2023-01-07_why_you_shouldnt_use_useactiondata
- https://remix.run/docs/en/main/discussion/form-vs-fetcher
- https://reactrouter.com/dev/guides
- https://sergiodxa.com/tutorials/use-server-sent-events-with-remix
- https://sergiodxa.com/tutorials/use-server-sent-events-with-remix
- https://github.com/perezcarreno/chatgpt-remix
2 changes: 1 addition & 1 deletion postcss.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default {
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-sm': '52em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
Expand Down
3 changes: 2 additions & 1 deletion tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export default {
},
screens: {
xs: '36em', // 36em * 16px = 576px
sm: '48em', // 48em * 16px = 768px
// sm: '48em', // 48em * 16px = 768px
sm: '52em', // 52em * 16px = 832px
md: '62em', // 62em * 16px = 992px
lg: '75em', // 75em * 16px = 1200px
xl: '88em', // 88em * 16px = 1408px
Expand Down

0 comments on commit 94dc2be

Please sign in to comment.