chat-indic-ui / src /components /chat /chat-topbar.tsx
sam2ai's picture
Synced repo using 'sync_with_huggingface' Github Action
0971cc4 verified
"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>
);
}