parent
7faa5f1c9f
commit
a68eb2a011
41 changed files with 2350 additions and 800 deletions
8
app/(chat)/actions.ts
Normal file
8
app/(chat)/actions.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
'use server';
|
||||
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export async function saveModel(model: string) {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set('model', model);
|
||||
}
|
||||
|
|
@ -1,38 +1,47 @@
|
|||
import { convertToCoreMessages, Message, streamText } from "ai";
|
||||
import { z } from "zod";
|
||||
import { convertToCoreMessages, Message, streamText } from 'ai';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { customModel } from "@/ai";
|
||||
import { auth } from "@/app/(auth)/auth";
|
||||
import { deleteChatById, getChatById, saveChat } from "@/db/queries";
|
||||
import { customModel } from '@/ai';
|
||||
import { auth } from '@/app/(auth)/auth';
|
||||
import { deleteChatById, getChatById, saveChat } from '@/db/queries';
|
||||
import { Model, models } from '@/lib/model';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { id, messages }: { id: string; messages: Array<Message> } =
|
||||
const {
|
||||
id,
|
||||
messages,
|
||||
model,
|
||||
}: { id: string; messages: Array<Message>; model: Model['name'] } =
|
||||
await request.json();
|
||||
|
||||
const session = await auth();
|
||||
|
||||
if (!session) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
if (!models.find((m) => m.name === model)) {
|
||||
return new Response('Model not found', { status: 404 });
|
||||
}
|
||||
|
||||
const coreMessages = convertToCoreMessages(messages);
|
||||
|
||||
const result = await streamText({
|
||||
model: customModel,
|
||||
model: customModel(model),
|
||||
system:
|
||||
"you are a friendly assistant! keep your responses concise and helpful.",
|
||||
'you are a friendly assistant! keep your responses concise and helpful.',
|
||||
messages: coreMessages,
|
||||
maxSteps: 5,
|
||||
tools: {
|
||||
getWeather: {
|
||||
description: "Get the current weather at a location",
|
||||
description: 'Get the current weather at a location',
|
||||
parameters: z.object({
|
||||
latitude: z.number(),
|
||||
longitude: z.number(),
|
||||
}),
|
||||
execute: async ({ latitude, longitude }) => {
|
||||
const response = await fetch(
|
||||
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&hourly=temperature_2m&daily=sunrise,sunset&timezone=auto`,
|
||||
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&hourly=temperature_2m&daily=sunrise,sunset&timezone=auto`
|
||||
);
|
||||
|
||||
const weatherData = await response.json();
|
||||
|
|
@ -49,13 +58,13 @@ export async function POST(request: Request) {
|
|||
userId: session.user.id,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to save chat");
|
||||
console.error('Failed to save chat');
|
||||
}
|
||||
}
|
||||
},
|
||||
experimental_telemetry: {
|
||||
isEnabled: true,
|
||||
functionId: "stream-text",
|
||||
functionId: 'stream-text',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -64,30 +73,30 @@ export async function POST(request: Request) {
|
|||
|
||||
export async function DELETE(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return new Response("Not Found", { status: 404 });
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const session = await auth();
|
||||
|
||||
if (!session || !session.user) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
const chat = await getChatById({ id });
|
||||
|
||||
if (chat.userId !== session.user.id) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
await deleteChatById({ id });
|
||||
|
||||
return new Response("Chat deleted", { status: 200 });
|
||||
return new Response('Chat deleted', { status: 200 });
|
||||
} catch (error) {
|
||||
return new Response("An error occurred while processing your request", {
|
||||
return new Response('An error occurred while processing your request', {
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { CoreMessage } from "ai";
|
||||
import { notFound } from "next/navigation";
|
||||
import { CoreMessage } from 'ai';
|
||||
import { cookies } from 'next/headers';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { auth } from "@/app/(auth)/auth";
|
||||
import { Chat as PreviewChat } from "@/components/custom/chat";
|
||||
import { getChatById } from "@/db/queries";
|
||||
import { Chat } from "@/db/schema";
|
||||
import { convertToUIMessages, generateUUID } from "@/lib/utils";
|
||||
import { auth } from '@/app/(auth)/auth';
|
||||
import { Chat as PreviewChat } from '@/components/custom/chat';
|
||||
import { getChatById } from '@/db/queries';
|
||||
import { Chat } from '@/db/schema';
|
||||
import { DEFAULT_MODEL_NAME, models } from '@/lib/model';
|
||||
import { convertToUIMessages } from '@/lib/utils';
|
||||
|
||||
export default async function Page(props: { params: Promise<any> }) {
|
||||
const params = await props.params;
|
||||
|
|
@ -32,5 +34,16 @@ export default async function Page(props: { params: Promise<any> }) {
|
|||
return notFound();
|
||||
}
|
||||
|
||||
return <PreviewChat id={chat.id} initialMessages={chat.messages} />;
|
||||
const cookieStore = await cookies();
|
||||
const value = cookieStore.get('model')?.value;
|
||||
const selectedModelName =
|
||||
models.find((m) => m.name === value)?.name || DEFAULT_MODEL_NAME;
|
||||
|
||||
return (
|
||||
<PreviewChat
|
||||
id={chat.id}
|
||||
initialMessages={chat.messages}
|
||||
selectedModelName={selectedModelName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
22
app/(chat)/layout.tsx
Normal file
22
app/(chat)/layout.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { cookies } from 'next/headers';
|
||||
|
||||
import { AppSidebar } from '@/components/custom/app-sidebar';
|
||||
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
|
||||
|
||||
import { auth } from '../(auth)/auth';
|
||||
|
||||
export default async function Layout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [session, cookieStore] = await Promise.all([auth(), cookies()]);
|
||||
const isCollapsed = cookieStore.get('sidebar:state')?.value !== 'true';
|
||||
|
||||
return (
|
||||
<SidebarProvider defaultOpen={!isCollapsed}>
|
||||
<AppSidebar user={session?.user} />
|
||||
<SidebarInset>{children}</SidebarInset>
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,23 @@
|
|||
import { Chat } from "@/components/custom/chat";
|
||||
import { generateUUID } from "@/lib/utils";
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
import { Chat } from '@/components/custom/chat';
|
||||
import { DEFAULT_MODEL_NAME, models } from '@/lib/model';
|
||||
import { generateUUID } from '@/lib/utils';
|
||||
|
||||
export default async function Page() {
|
||||
const id = generateUUID();
|
||||
return <Chat key={id} id={id} initialMessages={[]} />;
|
||||
|
||||
const cookieStore = await cookies();
|
||||
const value = cookieStore.get('model')?.value;
|
||||
const selectedModelName =
|
||||
models.find((m) => m.name === value)?.name || DEFAULT_MODEL_NAME;
|
||||
|
||||
return (
|
||||
<Chat
|
||||
key={id}
|
||||
id={id}
|
||||
initialMessages={[]}
|
||||
selectedModelName={selectedModelName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@
|
|||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
--sidebar-background: 0 0% 98%;
|
||||
--sidebar-foreground: 240 10% 3.9%;
|
||||
--sidebar-primary: 240 5.9% 10%;
|
||||
--sidebar-primary-foreground: 0 0% 98%;
|
||||
--sidebar-accent: 240 5.9% 94%;
|
||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||
--sidebar-border: 220 13% 91%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
|
|
@ -75,6 +83,14 @@
|
|||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 224.3 76.3% 48%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,17 +104,17 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "geist";
|
||||
font-family: 'geist';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url(/fonts/geist.woff2) format("woff2");
|
||||
src: url(/fonts/geist.woff2) format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "geist-mono";
|
||||
font-family: 'geist-mono';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url(/fonts/geist-mono.woff2) format("woff2");
|
||||
src: url(/fonts/geist-mono.woff2) format('woff2');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +123,7 @@
|
|||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
*[class^="text-"] {
|
||||
*[class^='text-'] {
|
||||
color: transparent;
|
||||
@apply rounded-md bg-foreground/20 select-none animate-pulse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Metadata } from 'next';
|
||||
import { Toaster } from 'sonner';
|
||||
|
||||
import { Navbar } from '@/components/custom/navbar';
|
||||
import { ThemeProvider } from '@/components/custom/theme-provider';
|
||||
|
||||
import './globals.css';
|
||||
|
|
@ -65,7 +64,6 @@ export default async function RootLayout({
|
|||
disableTransitionOnChange
|
||||
>
|
||||
<Toaster position="top-center" />
|
||||
<Navbar />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue