Skip to content

Commit

Permalink
feat: update choice model part Update npm dependencies for @radix-ui/…
Browse files Browse the repository at this point in the history
…react-scroll-area and @radix-ui/react-separator
  • Loading branch information
Sma1lboy committed Nov 2, 2024
1 parent 8285ab9 commit 48bb045
Show file tree
Hide file tree
Showing 7 changed files with 10,411 additions and 8,210 deletions.
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@types/dom-speech-recognition": "^0.0.4",
Expand Down
58 changes: 28 additions & 30 deletions frontend/src/app/hooks/useChatStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@ import { useMutation, useSubscription } from '@apollo/client';
import { CHAT_STREAM, CREATE_CHAT, TRIGGER_CHAT } from '@/graphql/request';
import { Message } from '@/components/types';
import { toast } from 'sonner';
import { useRouter } from 'next/navigation';

// Define stream states to manage chat flow
enum StreamStatus {
IDLE = 'IDLE',
STREAMING = 'STREAMING',
DONE = 'DONE',
}

// GraphQL input types
interface ChatInput {
chatId: string;
message: string;
Expand Down Expand Up @@ -41,11 +38,11 @@ export function useChatStream({
setMessages,
selectedModel,
}: UseChatStreamProps) {
const router = useRouter();
const [loadingSubmit, setLoadingSubmit] = useState(false);
const [streamStatus, setStreamStatus] = useState<StreamStatus>(
StreamStatus.IDLE
);
const [currentChatId, setCurrentChatId] = useState<string>(chatId);

const [subscription, setSubscription] = useState<SubscriptionState>({
enabled: false,
Expand All @@ -65,7 +62,8 @@ export function useChatStream({
const [createChat] = useMutation(CREATE_CHAT, {
onCompleted: async (data) => {
const newChatId = data.createChat.id;
router.push(`/${newChatId}`);
window.history.replaceState({}, '', `/${newChatId}`);
setCurrentChatId(newChatId);
await startChatStream(newChatId, input);
},
onError: () => {
Expand Down Expand Up @@ -128,10 +126,10 @@ export function useChatStream({
},
});

const startChatStream = async (currentChatId: string, message: string) => {
const startChatStream = async (targetChatId: string, message: string) => {
try {
const input: ChatInput = {
chatId: currentChatId,
chatId: targetChatId,
message,
model: selectedModel,
};
Expand All @@ -151,26 +149,6 @@ export function useChatStream({
}
};

const finishChatResponse = useCallback(() => {
setLoadingSubmit(false);
setSubscription({
enabled: false,
variables: null,
});
if (streamStatus === StreamStatus.DONE) {
setStreamStatus(StreamStatus.IDLE);
}
}, [streamStatus]);

// Handle input change
const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput(e.target.value);
},
[setInput]
);

// Handle form submission
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

Expand All @@ -181,15 +159,16 @@ export function useChatStream({

setLoadingSubmit(true);

const messageId = currentChatId || 'temp-id';
const newMessage: Message = {
id: chatId || 'temp-id',
id: messageId,
role: 'user',
content: content,
createdAt: new Date().toISOString(),
};
setMessages((prev) => [...prev, newMessage]);

if (!chatId) {
if (!currentChatId) {
try {
await createChat({
variables: {
Expand All @@ -203,10 +182,28 @@ export function useChatStream({
return;
}
} else {
await startChatStream(chatId, content);
await startChatStream(currentChatId, content);
}
};

const finishChatResponse = useCallback(() => {
setLoadingSubmit(false);
setSubscription({
enabled: false,
variables: null,
});
if (streamStatus === StreamStatus.DONE) {
setStreamStatus(StreamStatus.IDLE);
}
}, [streamStatus]);

const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput(e.target.value);
},
[setInput]
);

const stop = useCallback(() => {
if (streamStatus === StreamStatus.STREAMING) {
setSubscription({
Expand All @@ -225,5 +222,6 @@ export function useChatStream({
handleInputChange,
stop,
isStreaming: streamStatus === StreamStatus.STREAMING,
currentChatId,
};
}
71 changes: 50 additions & 21 deletions frontend/src/components/chat/chat-topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import React from 'react';
import { CaretSortIcon } from '@radix-ui/react-icons';
import { Button } from '../ui/button';
import { useModels } from '@/app/hooks/useModels';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';

export default function ChatTopbar() {
const [open, setOpen] = React.useState(false);
Expand Down Expand Up @@ -43,27 +46,53 @@ export default function ChatTopbar() {
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[300px] p-1">
{modelsLoading ? (
<Button variant="ghost" disabled className="w-full">
Loading models...
</Button>
) : models.length > 0 ? (
models.map((model) => (
<Button
key={model}
variant="ghost"
className="w-full"
onClick={() => handleModelChange(model)}
>
{model}
</Button>
))
) : (
<Button variant="ghost" disabled className="w-full">
No models available
</Button>
)}
<PopoverContent
className="w-[300px] p-0 overflow-hidden"
align="center"
side="bottom"
sideOffset={4}
>
<div className="px-3 py-2 border-b">
<h4 className="font-medium text-sm">Select Model</h4>
<p className="text-xs text-muted-foreground">
Choose a model for your chat
</p>
</div>
<ScrollArea className="h-[320px]">
{modelsLoading ? (
<div className="px-3 py-2">
<Button variant="ghost" disabled className="w-full">
Loading models...
</Button>
</div>
) : models.length > 0 ? (
<div className="flex flex-col">
{models.map((model, index) => (
<div key={model}>
<Button
variant="ghost"
className={cn(
'w-full justify-start font-normal rounded-none px-3 py-2 h-auto',
selectedModel === model && 'bg-accent'
)}
onClick={() => handleModelChange(model)}
>
{model}
</Button>
{index < models.length - 1 && (
<Separator className="mx-3" />
)}
</div>
))}
</div>
) : (
<div className="px-3 py-2">
<Button variant="ghost" disabled className="w-full">
No models available
</Button>
</div>
)}
</ScrollArea>
</PopoverContent>
</Popover>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use client';

import { Button } from '@/components/ui/button';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
Expand Down Expand Up @@ -36,8 +35,9 @@ function Sidebar({
const router = useRouter();

const handleNewChat = useCallback(() => {
router.push('/');
}, [router]);
//force reload to reset the chat state
window.location.href = '/';
}, []);

if (loading) return <SidebarSkeleton />;
if (error) {
Expand Down
48 changes: 48 additions & 0 deletions frontend/src/components/ui/scroll-area.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client"

import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"

import { cn } from "@/lib/utils"

const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName

const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName

export { ScrollArea, ScrollBar }
31 changes: 31 additions & 0 deletions frontend/src/components/ui/separator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client';

import * as React from 'react';
import * as SeparatorPrimitive from '@radix-ui/react-separator';

import { cn } from '@/lib/utils';

const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = 'horizontal', decorative = true, ...props },
ref
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
'shrink-0 bg-border',
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
className
)}
{...props}
/>
)
);
Separator.displayName = SeparatorPrimitive.Root.displayName;

export { Separator };
Loading

0 comments on commit 48bb045

Please sign in to comment.