Spaces:
Runtime error
Runtime error
| "use client"; | |
| import React, { useEffect } from "react"; | |
| import { | |
| CheckCircledIcon, | |
| CrossCircledIcon, | |
| DotFilledIcon, | |
| HamburgerMenuIcon, | |
| InfoCircledIcon, | |
| } from "@radix-ui/react-icons"; | |
| import { Message } from "ai/react"; | |
| import { toast } from "sonner"; | |
| import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; | |
| import { | |
| Tooltip, | |
| TooltipContent, | |
| TooltipProvider, | |
| TooltipTrigger, | |
| } from "@/components/ui/tooltip"; | |
| import { encodeChat, tokenLimit } from "@/lib/token-counter"; | |
| import { basePath, useHasMounted } from "@/lib/utils"; | |
| import { Sidebar } from "../sidebar"; | |
| import { ChatOptions } from "./chat-options"; | |
| interface ChatTopbarProps { | |
| chatOptions: ChatOptions; | |
| setChatOptions: React.Dispatch<React.SetStateAction<ChatOptions>>; | |
| isLoading: boolean; | |
| chatId?: string; | |
| setChatId: React.Dispatch<React.SetStateAction<string>>; | |
| messages: Message[]; | |
| } | |
| export default function ChatTopbar({ | |
| chatOptions, | |
| setChatOptions, | |
| isLoading, | |
| chatId, | |
| setChatId, | |
| messages, | |
| }: ChatTopbarProps) { | |
| const hasMounted = useHasMounted(); | |
| const currentModel = chatOptions && chatOptions.selectedModel; | |
| const [error, setError] = React.useState<string | undefined>(undefined); | |
| const fetchData = async () => { | |
| if (!hasMounted) { | |
| return null; | |
| } | |
| try { | |
| const res = await fetch(basePath + "/api/models"); | |
| if (!res.ok) { | |
| const errorResponse = await res.json(); | |
| const errorMessage = `Connection to vLLM server failed: ${errorResponse.error} [${res.status} ${res.statusText}]`; | |
| throw new Error(errorMessage); | |
| } | |
| const data = await res.json(); | |
| // Extract the "name" field from each model object and store them in the state | |
| const modelNames = data.data.map((model: any) => model.id); | |
| // save the first and only model in the list as selectedModel in localstorage | |
| setChatOptions({ ...chatOptions, selectedModel: modelNames[0] }); | |
| } catch (error) { | |
| setChatOptions({ ...chatOptions, selectedModel: undefined }); | |
| toast.error(error as string); | |
| } | |
| }; | |
| useEffect(() => { | |
| fetchData(); | |
| }, [hasMounted]); | |
| if (!hasMounted) { | |
| return ( | |
| <div className="md:w-full flex px-4 py-6 items-center gap-1 md:justify-center"> | |
| <DotFilledIcon className="w-4 h-4 text-blue-500" /> | |
| <span className="text-xs">Booting up..</span> | |
| </div> | |
| ); | |
| } | |
| const chatTokens = messages.length > 0 ? encodeChat(messages) : 0; | |
| return ( | |
| <div className="md:w-full flex px-4 py-4 items-center justify-between md:justify-center"> | |
| <Sheet> | |
| <SheetTrigger> | |
| <div className="flex items-center gap-2"> | |
| <HamburgerMenuIcon className="md:hidden w-5 h-5" /> | |
| </div> | |
| </SheetTrigger> | |
| <SheetContent side="left"> | |
| <div> | |
| <Sidebar | |
| chatId={chatId || ""} | |
| setChatId={setChatId} | |
| isCollapsed={false} | |
| isMobile={false} | |
| chatOptions={chatOptions} | |
| setChatOptions={setChatOptions} | |
| /> | |
| </div> | |
| </SheetContent> | |
| </Sheet> | |
| <div className="flex justify-center md:justify-between gap-4 w-full"> | |
| <div className="gap-1 flex items-center"> | |
| {currentModel !== undefined && ( | |
| <> | |
| {isLoading ? ( | |
| <DotFilledIcon className="w-4 h-4 text-blue-500" /> | |
| ) : ( | |
| <TooltipProvider> | |
| <Tooltip> | |
| <TooltipTrigger> | |
| <span className="cursor-help"> | |
| <CheckCircledIcon className="w-4 h-4 text-green-500" /> | |
| </span> | |
| </TooltipTrigger> | |
| <TooltipContent | |
| sideOffset={4} | |
| className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-2 rounded-sm text-xs" | |
| > | |
| <p className="font-bold">Current Model</p> | |
| <p className="text-gray-500">{currentModel}</p> | |
| </TooltipContent> | |
| </Tooltip> | |
| </TooltipProvider> | |
| )} | |
| <span className="text-xs"> | |
| {isLoading ? "Generating.." : "Ready"} | |
| </span> | |
| </> | |
| )} | |
| {currentModel === undefined && ( | |
| <> | |
| <CrossCircledIcon className="w-4 h-4 text-red-500" /> | |
| <span className="text-xs">Connection to vLLM server failed</span> | |
| </> | |
| )} | |
| </div> | |
| <div className="flex items-end gap-2"> | |
| {chatTokens > tokenLimit && ( | |
| <TooltipProvider> | |
| <Tooltip> | |
| <TooltipTrigger> | |
| <span> | |
| <InfoCircledIcon className="w-4 h-4 text-blue-500" /> | |
| </span> | |
| </TooltipTrigger> | |
| <TooltipContent | |
| sideOffset={4} | |
| className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 rounded-sm text-xs" | |
| > | |
| <p className="text-gray-500"> | |
| Token limit exceeded. Truncating middle messages. | |
| </p> | |
| </TooltipContent> | |
| </Tooltip> | |
| </TooltipProvider> | |
| )} | |
| {messages.length > 0 && ( | |
| <span className="text-xs text-gray-500"> | |
| {chatTokens} / {tokenLimit} token{chatTokens > 1 ? "s" : ""} | |
| </span> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |