Spaces:
Running
Running
MingruiZhang
commited on
Commit
•
76fdff4
1
Parent(s):
2189691
check in
Browse files- .env.example +20 -0
- .eslintrc.json +26 -0
- .gitignore +38 -0
- app/(chat)/chat/[id]/page.tsx +47 -0
- app/(chat)/layout.tsx +16 -0
- app/(chat)/page.tsx +8 -0
- app/api/auth/[...nextauth]/route.ts +2 -0
- app/globals.css +78 -0
- app/share/[id]/page.tsx +48 -0
- app/sign-in/page.tsx +17 -0
- yarn.lock +0 -0
.env.example
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# You must first activate a Billing Account here: https://platform.openai.com/account/billing/overview
|
2 |
+
# Then get your OpenAI API Key here: https://platform.openai.com/account/api-keys
|
3 |
+
OPENAI_API_KEY=XXXXXXXX
|
4 |
+
|
5 |
+
# Generate a random secret: https://generate-secret.vercel.app/32 or `openssl rand -base64 32`
|
6 |
+
AUTH_SECRET=XXXXXXXX
|
7 |
+
# Create a GitHub OAuth app here: https://github.com/settings/applications/new
|
8 |
+
# For info on authorization callback URL visit here: https://authjs.dev/reference/core/providers_github#callback-url
|
9 |
+
AUTH_GITHUB_ID=XXXXXXXX
|
10 |
+
AUTH_GITHUB_SECRET=XXXXXXXX
|
11 |
+
# Support OAuth login on preview deployments, see: https://authjs.dev/guides/basics/deployment#securing-a-preview-deployment
|
12 |
+
# Set the following only when deployed. In this example, we can reuse the same OAuth app, but if you are storing users, we recommend using a different OAuth app for development/production so that you don't mix your test and production user base.
|
13 |
+
# AUTH_REDIRECT_PROXY_URL=https://YOURAPP.vercel.app/api/auth
|
14 |
+
|
15 |
+
# Instructions to create kv database here: https://vercel.com/docs/storage/vercel-kv/quickstart and
|
16 |
+
KV_URL=XXXXXXXX
|
17 |
+
KV_REST_API_URL=XXXXXXXX
|
18 |
+
KV_REST_API_TOKEN=XXXXXXXX
|
19 |
+
KV_REST_API_READ_ONLY_TOKEN=XXXXXXXX
|
20 |
+
|
.eslintrc.json
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "https://json.schemastore.org/eslintrc",
|
3 |
+
"root": true,
|
4 |
+
"extends": [
|
5 |
+
"next/core-web-vitals",
|
6 |
+
"prettier",
|
7 |
+
"plugin:tailwindcss/recommended"
|
8 |
+
],
|
9 |
+
"plugins": ["tailwindcss"],
|
10 |
+
"rules": {
|
11 |
+
"tailwindcss/no-custom-classname": "off",
|
12 |
+
"tailwindcss/classnames-order": "off"
|
13 |
+
},
|
14 |
+
"settings": {
|
15 |
+
"tailwindcss": {
|
16 |
+
"callees": ["cn", "cva"],
|
17 |
+
"config": "tailwind.config.js"
|
18 |
+
}
|
19 |
+
},
|
20 |
+
"overrides": [
|
21 |
+
{
|
22 |
+
"files": ["*.ts", "*.tsx"],
|
23 |
+
"parser": "@typescript-eslint/parser"
|
24 |
+
}
|
25 |
+
]
|
26 |
+
}
|
.gitignore
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
2 |
+
|
3 |
+
# dependencies
|
4 |
+
node_modules
|
5 |
+
.pnp
|
6 |
+
.pnp.js
|
7 |
+
|
8 |
+
# testing
|
9 |
+
coverage
|
10 |
+
|
11 |
+
# next.js
|
12 |
+
.next/
|
13 |
+
out/
|
14 |
+
build
|
15 |
+
|
16 |
+
# misc
|
17 |
+
.DS_Store
|
18 |
+
*.pem
|
19 |
+
|
20 |
+
# debug
|
21 |
+
npm-debug.log*
|
22 |
+
yarn-debug.log*
|
23 |
+
yarn-error.log*
|
24 |
+
.pnpm-debug.log*
|
25 |
+
|
26 |
+
# local env files
|
27 |
+
.env.local
|
28 |
+
.env.development.local
|
29 |
+
.env.test.local
|
30 |
+
.env.production.local
|
31 |
+
|
32 |
+
# turbo
|
33 |
+
.turbo
|
34 |
+
|
35 |
+
.env
|
36 |
+
.vercel
|
37 |
+
.vscode
|
38 |
+
.env*.local
|
app/(chat)/chat/[id]/page.tsx
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { type Metadata } from 'next'
|
2 |
+
import { notFound, redirect } from 'next/navigation'
|
3 |
+
|
4 |
+
import { auth } from '@/auth'
|
5 |
+
import { getChat } from '@/app/actions'
|
6 |
+
import { Chat } from '@/components/chat'
|
7 |
+
|
8 |
+
export interface ChatPageProps {
|
9 |
+
params: {
|
10 |
+
id: string
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
export async function generateMetadata({
|
15 |
+
params
|
16 |
+
}: ChatPageProps): Promise<Metadata> {
|
17 |
+
const session = await auth()
|
18 |
+
|
19 |
+
if (!session?.user) {
|
20 |
+
return {}
|
21 |
+
}
|
22 |
+
|
23 |
+
const chat = await getChat(params.id, session.user.id)
|
24 |
+
return {
|
25 |
+
title: chat?.title.toString().slice(0, 50) ?? 'Chat'
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
export default async function ChatPage({ params }: ChatPageProps) {
|
30 |
+
const session = await auth()
|
31 |
+
|
32 |
+
if (!session?.user) {
|
33 |
+
redirect(`/sign-in?next=/chat/${params.id}`)
|
34 |
+
}
|
35 |
+
|
36 |
+
const chat = await getChat(params.id, session.user.id)
|
37 |
+
|
38 |
+
if (!chat) {
|
39 |
+
notFound()
|
40 |
+
}
|
41 |
+
|
42 |
+
if (chat?.userId !== session?.user?.id) {
|
43 |
+
notFound()
|
44 |
+
}
|
45 |
+
|
46 |
+
return <Chat id={chat.id} initialMessages={chat.messages} />
|
47 |
+
}
|
app/(chat)/layout.tsx
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { SidebarDesktop } from '@/components/sidebar-desktop'
|
2 |
+
|
3 |
+
interface ChatLayoutProps {
|
4 |
+
children: React.ReactNode
|
5 |
+
}
|
6 |
+
|
7 |
+
export default async function ChatLayout({ children }: ChatLayoutProps) {
|
8 |
+
return (
|
9 |
+
<div className="relative flex h-[calc(100vh_-_theme(spacing.16))] overflow-hidden">
|
10 |
+
<SidebarDesktop />
|
11 |
+
<div className="group w-full overflow-auto pl-0 animate-in duration-300 ease-in-out peer-[[data-state=open]]:lg:pl-[250px] peer-[[data-state=open]]:xl:pl-[300px]">
|
12 |
+
{children}
|
13 |
+
</div>
|
14 |
+
</div>
|
15 |
+
)
|
16 |
+
}
|
app/(chat)/page.tsx
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { nanoid } from '@/lib/utils'
|
2 |
+
import { Chat } from '@/components/chat'
|
3 |
+
|
4 |
+
export default function IndexPage() {
|
5 |
+
const id = nanoid()
|
6 |
+
|
7 |
+
return <Chat id={id} />
|
8 |
+
}
|
app/api/auth/[...nextauth]/route.ts
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
export { GET, POST } from '@/auth'
|
2 |
+
export const runtime = 'edge'
|
app/globals.css
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
@layer base {
|
6 |
+
:root {
|
7 |
+
--background: 0 0% 100%;
|
8 |
+
--foreground: 240 10% 3.9%;
|
9 |
+
|
10 |
+
--muted: 240 4.8% 95.9%;
|
11 |
+
--muted-foreground: 240 3.8% 46.1%;
|
12 |
+
|
13 |
+
--popover: 0 0% 100%;
|
14 |
+
--popover-foreground: 240 10% 3.9%;
|
15 |
+
|
16 |
+
--card: 0 0% 100%;
|
17 |
+
--card-foreground: 240 10% 3.9%;
|
18 |
+
|
19 |
+
--border: 240 5.9% 90%;
|
20 |
+
--input: 240 5.9% 90%;
|
21 |
+
|
22 |
+
--primary: 240 5.9% 10%;
|
23 |
+
--primary-foreground: 0 0% 98%;
|
24 |
+
|
25 |
+
--secondary: 240 4.8% 95.9%;
|
26 |
+
--secondary-foreground: 240 5.9% 10%;
|
27 |
+
|
28 |
+
--accent: 240 4.8% 95.9%;
|
29 |
+
--accent-foreground: ;
|
30 |
+
|
31 |
+
--destructive: 0 84.2% 60.2%;
|
32 |
+
--destructive-foreground: 0 0% 98%;
|
33 |
+
|
34 |
+
--ring: 240 5% 64.9%;
|
35 |
+
|
36 |
+
--radius: 0.5rem;
|
37 |
+
}
|
38 |
+
|
39 |
+
.dark {
|
40 |
+
--background: 240 10% 3.9%;
|
41 |
+
--foreground: 0 0% 98%;
|
42 |
+
|
43 |
+
--muted: 240 3.7% 15.9%;
|
44 |
+
--muted-foreground: 240 5% 64.9%;
|
45 |
+
|
46 |
+
--popover: 240 10% 3.9%;
|
47 |
+
--popover-foreground: 0 0% 98%;
|
48 |
+
|
49 |
+
--card: 240 10% 3.9%;
|
50 |
+
--card-foreground: 0 0% 98%;
|
51 |
+
|
52 |
+
--border: 240 3.7% 15.9%;
|
53 |
+
--input: 240 3.7% 15.9%;
|
54 |
+
|
55 |
+
--primary: 0 0% 98%;
|
56 |
+
--primary-foreground: 240 5.9% 10%;
|
57 |
+
|
58 |
+
--secondary: 240 3.7% 15.9%;
|
59 |
+
--secondary-foreground: 0 0% 98%;
|
60 |
+
|
61 |
+
--accent: 240 3.7% 15.9%;
|
62 |
+
--accent-foreground: ;
|
63 |
+
|
64 |
+
--destructive: 0 62.8% 30.6%;
|
65 |
+
--destructive-foreground: 0 85.7% 97.3%;
|
66 |
+
|
67 |
+
--ring: 240 3.7% 15.9%;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
@layer base {
|
72 |
+
* {
|
73 |
+
@apply border-border;
|
74 |
+
}
|
75 |
+
body {
|
76 |
+
@apply bg-background text-foreground;
|
77 |
+
}
|
78 |
+
}
|
app/share/[id]/page.tsx
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// import { type Metadata } from 'next'
|
2 |
+
// import { notFound } from 'next/navigation'
|
3 |
+
|
4 |
+
// import { formatDate } from '@/lib/utils'
|
5 |
+
// import { getSharedChat } from '@/app/actions'
|
6 |
+
// import { ChatList } from '@/components/chat-list'
|
7 |
+
|
8 |
+
// interface SharePageProps {
|
9 |
+
// params: {
|
10 |
+
// id: string
|
11 |
+
// }
|
12 |
+
// }
|
13 |
+
|
14 |
+
// export async function generateMetadata({
|
15 |
+
// params
|
16 |
+
// }: SharePageProps): Promise<Metadata> {
|
17 |
+
// const chat = await getSharedChat(params.id)
|
18 |
+
|
19 |
+
// return {
|
20 |
+
// title: chat?.title.slice(0, 50) ?? 'Chat'
|
21 |
+
// }
|
22 |
+
// }
|
23 |
+
|
24 |
+
// export default async function SharePage({ params }: SharePageProps) {
|
25 |
+
// const chat = await getSharedChat(params.id)
|
26 |
+
|
27 |
+
// if (!chat || !chat?.sharePath) {
|
28 |
+
// notFound()
|
29 |
+
// }
|
30 |
+
|
31 |
+
// return (
|
32 |
+
// <>
|
33 |
+
// <div className="flex-1 space-y-6">
|
34 |
+
// <div className="px-4 py-6 border-b bg-background md:px-6 md:py-8">
|
35 |
+
// <div className="max-w-2xl mx-auto md:px-6">
|
36 |
+
// <div className="space-y-1 md:-mx-8">
|
37 |
+
// <h1 className="text-2xl font-bold">{chat.title}</h1>
|
38 |
+
// <div className="text-sm text-muted-foreground">
|
39 |
+
// {formatDate(chat.createdAt)} · {chat.messages.length} messages
|
40 |
+
// </div>
|
41 |
+
// </div>
|
42 |
+
// </div>
|
43 |
+
// </div>
|
44 |
+
// <ChatList messages={chat.messages} />
|
45 |
+
// </div>
|
46 |
+
// </>
|
47 |
+
// )
|
48 |
+
// }
|
app/sign-in/page.tsx
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { auth } from '@/auth'
|
2 |
+
import { LoginButton } from '@/components/login-button'
|
3 |
+
import { redirect } from 'next/navigation'
|
4 |
+
|
5 |
+
export default async function SignInPage() {
|
6 |
+
const session = await auth()
|
7 |
+
// redirect to home if user is already logged in
|
8 |
+
if (session?.user) {
|
9 |
+
redirect('/')
|
10 |
+
}
|
11 |
+
|
12 |
+
return (
|
13 |
+
<div className="flex h-[calc(100vh-theme(spacing.16))] items-center justify-center py-10">
|
14 |
+
<LoginButton />
|
15 |
+
</div>
|
16 |
+
)
|
17 |
+
}
|
yarn.lock
ADDED
The diff for this file is too large to render.
See raw diff
|
|