Move to clerk
This commit is contained in:
parent
cd340320b7
commit
567b0ac313
18 changed files with 550 additions and 178 deletions
|
|
@ -4,6 +4,7 @@ import { revalidatePath } from 'next/cache'
|
|||
import { kv } from '@vercel/kv'
|
||||
|
||||
import { type Chat } from '@/lib/types'
|
||||
import { currentUser } from '@clerk/nextjs'
|
||||
|
||||
export async function getChats(userId?: string | null) {
|
||||
if (!userId) {
|
||||
|
|
@ -40,24 +41,19 @@ export async function getChat(id: string, userId: string) {
|
|||
return chat
|
||||
}
|
||||
|
||||
export async function removeChat({
|
||||
id,
|
||||
path,
|
||||
userId
|
||||
}: {
|
||||
id: string
|
||||
userId: string
|
||||
path: string
|
||||
}) {
|
||||
// @todo next-auth@v5 doesn't work in server actions yet
|
||||
// const session = await auth();
|
||||
export async function removeChat({ id, path }: { id: string; path: string }) {
|
||||
const user = await currentUser()
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const uid = await kv.hget<string>(`chat:${id}`, 'userId')
|
||||
if (uid !== userId) {
|
||||
if (uid !== user.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
await kv.del(`chat:${id}`)
|
||||
await kv.zrem(`user:chat:${userId}`, `chat:${id}`)
|
||||
await kv.zrem(`user:chat:${user.id}`, `chat:${id}`)
|
||||
|
||||
revalidatePath('/')
|
||||
revalidatePath('/chat/[id]')
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
export { GET, POST } from '@/auth'
|
||||
// export const runtime = 'edge'
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import { auth } from '@/auth'
|
||||
import { kv } from '@vercel/kv'
|
||||
import { OpenAIStream, StreamingTextResponse } from 'ai-connector'
|
||||
import { Configuration, OpenAIApi } from 'openai-edge'
|
||||
|
||||
import { nanoid } from '@/lib/utils'
|
||||
import { currentUser } from '@clerk/nextjs'
|
||||
|
||||
// export const runtime = 'edge'
|
||||
export const runtime = 'edge'
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
|
|
@ -17,13 +17,15 @@ if (!process.env.OPENAI_API_KEY) {
|
|||
throw new Error('Missing env var from OpenAI')
|
||||
}
|
||||
|
||||
export const POST = auth(async function POST(req: Request) {
|
||||
export async function POST(req: Request) {
|
||||
const user = await currentUser()
|
||||
if (user == null) {
|
||||
return new Response('Unauthorized', { status: 401 })
|
||||
}
|
||||
|
||||
const json = await req.json()
|
||||
// @ts-ignore
|
||||
const messages = json.messages.map((m: any) => ({
|
||||
content: m.content,
|
||||
role: m.role
|
||||
}))
|
||||
const { messages } = json
|
||||
|
||||
const res = await openai.createChatCompletion({
|
||||
model: 'gpt-3.5-turbo',
|
||||
messages,
|
||||
|
|
@ -35,14 +37,10 @@ export const POST = auth(async function POST(req: Request) {
|
|||
stream: true
|
||||
})
|
||||
|
||||
const stream = await OpenAIStream(res, {
|
||||
const stream = OpenAIStream(res, {
|
||||
async onCompletion(completion) {
|
||||
// @ts-ignore
|
||||
if (req.auth?.user?.email == null) {
|
||||
return
|
||||
}
|
||||
const title = json.messages[0].content.substring(0, 100)
|
||||
const userId = (req as any).auth?.user?.email
|
||||
const userId = user.id
|
||||
const id = json.id ?? nanoid()
|
||||
const createdAt = Date.now()
|
||||
const payload = {
|
||||
|
|
@ -67,4 +65,4 @@ export const POST = auth(async function POST(req: Request) {
|
|||
})
|
||||
|
||||
return new StreamingTextResponse(stream)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { type Metadata } from 'next'
|
||||
import { auth } from '@/auth'
|
||||
|
||||
import { Chat } from '@/components/chat'
|
||||
import { getChat } from '@/app/actions'
|
||||
import { Header } from '@/components/header'
|
||||
import { auth } from '@clerk/nextjs'
|
||||
|
||||
// export const runtime = 'edge'
|
||||
export const preferredRegion = 'home'
|
||||
|
|
@ -16,16 +17,24 @@ export interface ChatPageProps {
|
|||
export async function generateMetadata({
|
||||
params
|
||||
}: ChatPageProps): Promise<Metadata> {
|
||||
const session = await auth()
|
||||
const chat = await getChat(params.id, session?.user?.email ?? '')
|
||||
const { user } = await auth()
|
||||
const chat = await getChat(params.id, user?.id ?? '')
|
||||
return {
|
||||
title: chat?.title.slice(0, 50) ?? 'Chat'
|
||||
}
|
||||
}
|
||||
|
||||
export default async function ChatPage({ params }: ChatPageProps) {
|
||||
const session = await auth()
|
||||
const chat = await getChat(params.id, session?.user?.email ?? '')
|
||||
const { user } = await auth()
|
||||
const chat = await getChat(params.id, user?.id ?? '')
|
||||
|
||||
return <Chat id={chat.id} initialMessages={chat.messages} />
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
{/* @ts-ignore */}
|
||||
<Header />
|
||||
<main className="flex-1 bg-muted/50">
|
||||
<Chat id={chat.id} initialMessages={chat.messages} />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { cn } from '@/lib/utils'
|
|||
import { Header } from '@/components/header'
|
||||
import { TailwindIndicator } from '@/components/tailwind-indicator'
|
||||
import { ThemeProvider } from '@/components/theme-provider'
|
||||
import { ClerkProvider } from '@clerk/nextjs'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
|
|
@ -30,24 +31,22 @@ interface RootLayoutProps {
|
|||
|
||||
export default function RootLayout({ children }: RootLayoutProps) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body
|
||||
className={cn(
|
||||
'font-sans antialiased',
|
||||
fontSans.variable,
|
||||
fontMono.variable
|
||||
)}
|
||||
>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<div className="flex min-h-screen flex-col">
|
||||
{/* @ts-ignore */}
|
||||
<Header />
|
||||
<main className="flex-1 bg-muted/50">{children}</main>
|
||||
</div>
|
||||
<TailwindIndicator />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
<ClerkProvider>
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head />
|
||||
<body
|
||||
className={cn(
|
||||
'font-sans antialiased',
|
||||
fontSans.variable,
|
||||
fontMono.variable
|
||||
)}
|
||||
>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
{children}
|
||||
<TailwindIndicator />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
</ClerkProvider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
11
app/page.tsx
11
app/page.tsx
|
|
@ -1,8 +1,17 @@
|
|||
import { Chat } from '@/components/chat'
|
||||
import { Header } from '@/components/header'
|
||||
|
||||
// export const runtime = 'edge'
|
||||
export const preferredRegion = 'home'
|
||||
|
||||
export default async function IndexPage() {
|
||||
return <Chat />
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
{/* @ts-ignore */}
|
||||
<Header />
|
||||
<main className="flex-1 bg-muted/50">
|
||||
<Chat />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
11
app/sign-in/[[...sign-in]]/page.tsx
Normal file
11
app/sign-in/[[...sign-in]]/page.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { SignIn } from '@clerk/nextjs'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full min-h-screen">
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<SignIn />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
11
app/sign-up/[[...sign-up]]/page.tsx
Normal file
11
app/sign-up/[[...sign-up]]/page.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { SignUp } from '@clerk/nextjs'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full min-h-screen">
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<SignUp />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue