diff --git a/src/app/chats/[id]/page.tsx b/src/app/chats/[id]/page.tsx index bceca47..a0a0124 100644 --- a/src/app/chats/[id]/page.tsx +++ b/src/app/chats/[id]/page.tsx @@ -2,95 +2,14 @@ import React from "react"; -import { ChatRequestOptions } from "ai"; -import { useChat } from "ai/react"; -import { toast } from "sonner"; -import useLocalStorageState from "use-local-storage-state"; - -import { ChatLayout } from "@/components/chat/chat-layout"; -import { ChatOptions } from "@/components/chat/chat-options"; -import { basePath } from "@/lib/utils"; +import ChatPage from "@/components/chat/chat-page"; export default function Page({ params }: { params: { id: string } }) { - const { - messages, - input, - handleInputChange, - handleSubmit, - isLoading, - error, - stop, - setMessages, - } = useChat({ - api: basePath + "/api/chat", - onError: (error) => { - toast.error("Something went wrong: " + error); - }, - }); const [chatId, setChatId] = React.useState(""); - const [chatOptions, setChatOptions] = useLocalStorageState( - "chatOptions", - { - defaultValue: { - selectedModel: "", - systemPrompt: "", - temperature: 0.9, - }, - } - ); - React.useEffect(() => { if (params.id) { - const item = localStorage.getItem(`chat_${params.id}`); - if (item) { - setMessages(JSON.parse(item)); - } + setChatId(params.id); } - }, [setMessages, params.id]); - - const onSubmit = (e: React.FormEvent) => { - e.preventDefault(); - - setMessages([...messages]); - - // Prepare the options object with additional body data, to pass the model. - const requestOptions: ChatRequestOptions = { - options: { - body: { - chatOptions: chatOptions, - }, - }, - }; - - // Call the handleSubmit function with the options - handleSubmit(e, requestOptions); - }; - - // When starting a new chat, append the messages to the local storage - React.useEffect(() => { - if (!isLoading && !error && messages.length > 0) { - localStorage.setItem(`chat_${params.id}`, JSON.stringify(messages)); - // Trigger the storage event to update the sidebar component - window.dispatchEvent(new Event("storage")); - } - }, [messages, chatId, isLoading, error, params.id]); - - return ( -
- -
- ); + }, [params.id]); + return ; } diff --git a/src/app/new/page.tsx b/src/app/new/page.tsx deleted file mode 100644 index d235894..0000000 --- a/src/app/new/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from 'next/navigation' - -export default async function NewPage() { - redirect('/') -} diff --git a/src/app/page.tsx b/src/app/page.tsx index ae00ccf..1da3b6c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,94 +1,9 @@ "use client"; import React from "react"; - -import { ChatRequestOptions } from "ai"; -import { useChat } from "ai/react"; -import { toast } from "sonner"; -import useLocalStorageState from "use-local-storage-state"; -import { v4 as uuidv4 } from "uuid"; - -import { ChatLayout } from "@/components/chat/chat-layout"; -import { ChatOptions } from "@/components/chat/chat-options"; -import { basePath } from "@/lib/utils"; +import ChatPage from "@/components/chat/chat-page"; export default function Home() { - const { - messages, - input, - handleInputChange, - handleSubmit, - isLoading, - error, - stop, - setMessages, - } = useChat({ - api: basePath + "/api/chat", - onError: (error) => { - toast.error("Something went wrong: " + error); - }, - }); const [chatId, setChatId] = React.useState(""); - const [chatOptions, setChatOptions] = useLocalStorageState( - "chatOptions", - { - defaultValue: { - selectedModel: "", - systemPrompt: "", - temperature: 0.9, - }, - } - ); - - React.useEffect(() => { - if (!isLoading && !error && chatId && messages.length > 0) { - // Save messages to local storage - localStorage.setItem(`chat_${chatId}`, JSON.stringify(messages)); - // Trigger the storage event to update the sidebar component - window.dispatchEvent(new Event("storage")); - } - }, [messages, chatId, isLoading, error]); - - const onSubmit = (e: React.FormEvent) => { - e.preventDefault(); - - if (messages.length === 0) { - // Generate a random id for the chat - const id = uuidv4(); - setChatId(id); - } - - setMessages([...messages]); - - // Prepare the options object with additional body data, to pass the model. - const requestOptions: ChatRequestOptions = { - options: { - body: { - chatOptions: chatOptions, - }, - }, - }; - - // Call the handleSubmit function with the options - handleSubmit(e, requestOptions); - }; - - return ( -
- -
- ); + return ; } diff --git a/src/components/chat/chat-bottombar.tsx b/src/components/chat/chat-bottombar.tsx index c1b0083..9bcd766 100644 --- a/src/components/chat/chat-bottombar.tsx +++ b/src/components/chat/chat-bottombar.tsx @@ -3,23 +3,29 @@ import React from "react"; import { PaperPlaneIcon, StopIcon } from "@radix-ui/react-icons"; +import { ChatRequestOptions } from "ai"; import TextareaAutosize from "react-textarea-autosize"; import { Button } from "../ui/button"; -import { ChatProps } from "./chat"; -interface ChatBottombarProps extends ChatProps { +interface ChatBottombarProps { selectedModel: string | undefined; + input: string; + handleInputChange: (e: React.ChangeEvent) => void; + handleSubmit: ( + e: React.FormEvent, + chatRequestOptions?: ChatRequestOptions + ) => void; + isLoading: boolean; + stop: () => void; } export default function ChatBottombar({ selectedModel, - messages, input, handleInputChange, handleSubmit, isLoading, - error, stop, }: ChatBottombarProps) { const inputRef = React.useRef(null); diff --git a/src/components/chat/chat-layout.tsx b/src/components/chat/chat-layout.tsx index b4caa9f..70bdadf 100644 --- a/src/components/chat/chat-layout.tsx +++ b/src/components/chat/chat-layout.tsx @@ -32,6 +32,7 @@ export function ChatLayout({ error, stop, chatId, + setChatId, chatOptions, setChatOptions, }: MergedProps) { @@ -91,9 +92,9 @@ export function ChatLayout({ > @@ -101,6 +102,7 @@ export function ChatLayout({ (null); const scrollToBottom = () => { diff --git a/src/components/chat/chat-page.tsx b/src/components/chat/chat-page.tsx new file mode 100644 index 0000000..9016514 --- /dev/null +++ b/src/components/chat/chat-page.tsx @@ -0,0 +1,109 @@ +"use client"; + +import React from "react"; + +import { ChatRequestOptions } from "ai"; +import { useChat } from "ai/react"; +import { toast } from "sonner"; +import useLocalStorageState from "use-local-storage-state"; +import { v4 as uuidv4 } from "uuid"; + +import { ChatLayout } from "@/components/chat/chat-layout"; +import { ChatOptions } from "@/components/chat/chat-options"; +import { basePath } from "@/lib/utils"; + +interface ChatPageProps { + chatId: string; + setChatId: React.Dispatch>; +} +export default function ChatPage({ chatId, setChatId }: ChatPageProps) { + const { + messages, + input, + handleInputChange, + handleSubmit, + isLoading, + error, + stop, + setMessages, + } = useChat({ + api: basePath + "/api/chat", + onError: (error) => { + toast.error("Something went wrong: " + error); + }, + }); + const [chatOptions, setChatOptions] = useLocalStorageState( + "chatOptions", + { + defaultValue: { + selectedModel: "", + systemPrompt: "", + temperature: 0.9, + }, + } + ); + + React.useEffect(() => { + if (chatId) { + const item = localStorage.getItem(`chat_${chatId}`); + if (item) { + setMessages(JSON.parse(item)); + } + } else { + setMessages([]); + } + }, [setMessages, chatId]); + + React.useEffect(() => { + if (!isLoading && !error && chatId && messages.length > 0) { + // Save messages to local storage + localStorage.setItem(`chat_${chatId}`, JSON.stringify(messages)); + // Trigger the storage event to update the sidebar component + window.dispatchEvent(new Event("storage")); + } + }, [messages, chatId, isLoading, error]); + + const onSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (messages.length === 0) { + // Generate a random id for the chat + const id = uuidv4(); + setChatId(id); + } + + setMessages([...messages]); + + // Prepare the options object with additional body data, to pass the model. + const requestOptions: ChatRequestOptions = { + options: { + body: { + chatOptions: chatOptions, + }, + }, + }; + + // Call the handleSubmit function with the options + handleSubmit(e, requestOptions); + }; + + return ( +
+ +
+ ); +} diff --git a/src/components/chat/chat-topbar.tsx b/src/components/chat/chat-topbar.tsx index 902177a..ab14d4d 100644 --- a/src/components/chat/chat-topbar.tsx +++ b/src/components/chat/chat-topbar.tsx @@ -27,6 +27,7 @@ interface ChatTopbarProps { setChatOptions: React.Dispatch>; isLoading: boolean; chatId?: string; + setChatId: React.Dispatch>; messages: Message[]; } @@ -35,6 +36,7 @@ export default function ChatTopbar({ setChatOptions, isLoading, chatId, + setChatId, messages, }: ChatTopbarProps) { const hasMounted = useHasMounted(); @@ -94,9 +96,9 @@ export default function ChatTopbar({ diff --git a/src/components/chat/chat.tsx b/src/components/chat/chat.tsx index d7fd46e..b16b13a 100644 --- a/src/components/chat/chat.tsx +++ b/src/components/chat/chat.tsx @@ -10,6 +10,7 @@ import ChatTopbar from "./chat-topbar"; export interface ChatProps { chatId?: string; + setChatId: React.Dispatch>; messages: Message[]; input: string; handleInputChange: (e: React.ChangeEvent) => void; @@ -38,6 +39,7 @@ export default function Chat({ chatOptions, setChatOptions, chatId, + setChatId, }: ChatProps & ChatTopbarProps) { return (
@@ -46,27 +48,21 @@ export default function Chat({ setChatOptions={setChatOptions} isLoading={isLoading} chatId={chatId} + setChatId={setChatId} messages={messages} />
diff --git a/src/components/sidebar-tabs.tsx b/src/components/sidebar-tabs.tsx index 3e85a3a..3e17b01 100644 --- a/src/components/sidebar-tabs.tsx +++ b/src/components/sidebar-tabs.tsx @@ -28,7 +28,7 @@ interface Chats { interface SidebarTabsProps { isLoading: boolean; localChats: Chats; - selectedChatId: string | null; + selectedChatId: string; chatOptions: ChatOptions; setChatOptions: React.Dispatch>; handleDeleteChat: (chatId: string) => void; diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx index 9539d2d..9de530f 100644 --- a/src/components/sidebar.tsx +++ b/src/components/sidebar.tsx @@ -4,19 +4,19 @@ import { useEffect, useState } from "react"; import { Pencil2Icon } from "@radix-ui/react-icons"; import { Message } from "ai/react"; import Image from "next/image"; -import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import OllamaLogo from "../../public/ollama.png"; import { ChatOptions } from "./chat/chat-options"; import SidebarTabs from "./sidebar-tabs"; - +import { RedirectType, redirect } from "next/navigation"; +import Link from "next/link"; interface SidebarProps { isCollapsed: boolean; - messages: Message[]; onClick?: () => void; isMobile: boolean; chatId: string; + setChatId: React.Dispatch>; chatOptions: ChatOptions; setChatOptions: React.Dispatch>; } @@ -26,23 +26,17 @@ interface Chats { } export function Sidebar({ - messages, isCollapsed, isMobile, chatId, + setChatId, chatOptions, setChatOptions, }: SidebarProps) { const [localChats, setLocalChats] = useState({}); - const router = useRouter(); - const [selectedChatId, setSselectedChatId] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { - if (chatId) { - setSselectedChatId(chatId); - } - setLocalChats(getLocalstorageChats()); const handleStorageChange = () => { setLocalChats(getLocalstorageChats()); @@ -118,7 +112,6 @@ export function Sidebar({ const groupedChats = groupChatsByDate(chatObjects); return groupedChats; - // return chatObjects; }; const handleDeleteChat = (chatId: string) => { @@ -132,12 +125,10 @@ export function Sidebar({ className="relative justify-between group lg:bg- accent/20 lg:dark:bg-card/35 flex flex-col h-full gap-4 data-[collapsed=true]:p-0" >
- +