forked from vercel/ai-chatbot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a047762
Showing
56 changed files
with
6,808 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# editorconfig.org | ||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
end_of_line = lf | ||
indent_size = 2 | ||
indent_style = space | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
dist/* | ||
.cache | ||
public | ||
node_modules | ||
*.esm.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/eslintrc", | ||
"root": true, | ||
"extends": ["next/core-web-vitals", "prettier"], | ||
"rules": { | ||
"@next/next/no-html-link-for-pages": "off", | ||
"react/jsx-key": "off" | ||
}, | ||
"settings": { | ||
"next": { | ||
"rootDir": ["./"] | ||
} | ||
}, | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"parser": "@typescript-eslint/parser" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
node_modules | ||
.pnp | ||
.pnp.js | ||
|
||
# testing | ||
coverage | ||
|
||
# next.js | ||
.next/ | ||
out/ | ||
build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# local env files | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
|
||
# turbo | ||
.turbo | ||
|
||
.contentlayer | ||
.env | ||
.vercel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
cache | ||
.cache | ||
package.json | ||
package-lock.json | ||
public | ||
CHANGELOG.md | ||
.yarn | ||
dist | ||
node_modules | ||
.next | ||
build | ||
.contentlayer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"typescript.tsdk": "../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib", | ||
"typescript.enablePromptUseWorkspaceTsdk": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Chat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"use server"; | ||
|
||
import { getServerSession } from "next-auth"; | ||
import { prisma } from "@/lib/prisma"; | ||
import { revalidatePath } from "next/cache"; | ||
import { authOptions } from "@/app/api/auth/[...nextauth]/route"; | ||
|
||
export async function removeChat({ id, path }: { id: string; path: string }) { | ||
const session = await getServerSession(authOptions); | ||
const userId = session?.user?.email; | ||
if (!userId || !id) { | ||
throw new Error("Unauthorized"); | ||
} | ||
|
||
await prisma.chat.delete({ | ||
where: { | ||
id, | ||
// TODO: Add scoping | ||
// userId, | ||
}, | ||
}); | ||
|
||
revalidatePath("/"); | ||
revalidatePath("/chat/[id]"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import NextAuth, { NextAuthOptions } from "next-auth"; | ||
import { PrismaAdapter } from "@next-auth/prisma-adapter"; | ||
import { prisma } from "@/lib/prisma"; | ||
import GoogleProvider from "next-auth/providers/google"; | ||
|
||
export const authOptions: NextAuthOptions = { | ||
adapter: PrismaAdapter(prisma), | ||
providers: [ | ||
GoogleProvider({ | ||
clientId: process.env.GOOGLE_CLIENT_ID as string, | ||
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, | ||
}), | ||
], | ||
}; | ||
|
||
const handler = NextAuth(authOptions); | ||
|
||
export { handler as GET, handler as POST }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { OpenAIStream, openai } from "@/lib/openai"; | ||
import { getServerSession } from "next-auth"; | ||
|
||
export const runtime = "edge"; | ||
|
||
export async function POST(req: Request) { | ||
const json = await req.json(); | ||
const session = await getServerSession(); | ||
|
||
const res = await openai.createChatCompletion({ | ||
model: "gpt-3.5-turbo", | ||
messages: json.messages, | ||
temperature: 0.7, | ||
top_p: 1, | ||
frequency_penalty: 1, | ||
max_tokens: 500, | ||
n: 1, | ||
stream: true, | ||
}); | ||
|
||
const stream = await OpenAIStream(res); | ||
|
||
return new Response(stream, { | ||
status: 200, | ||
headers: { "Content-Type": "text/event-stream" }, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
"use client"; | ||
|
||
import { type Message } from "@prisma/client"; | ||
|
||
import { ChatMessage } from "./chat-message"; | ||
|
||
export interface ChatList { | ||
messages: Message[]; | ||
} | ||
|
||
export function ChatList({ messages }: ChatList) { | ||
return ( | ||
<div className="relative h-full dark:bg-zinc-900"> | ||
<div className="h-full w-full overflow-auto"> | ||
{messages.length > 0 ? ( | ||
<div className="group w-full text-zinc-900 dark:text-white divide-y dark:divide-zinc-800"> | ||
{messages.map((message) => ( | ||
<ChatMessage | ||
key={message.id || message.content} | ||
message={message} | ||
/> | ||
))} | ||
</div> | ||
) : null} | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { type Message } from "@prisma/client"; | ||
import CodeBlock from "./codeblock"; | ||
import { MemoizedReactMarkdown } from "./markdown"; | ||
import remarkGfm from "remark-gfm"; | ||
import remarkMath from "remark-math"; | ||
import { cn } from "@/lib/utils"; | ||
import { fontMessage } from "@/lib/fonts"; | ||
export interface ChatMessageProps { | ||
message: Message; | ||
} | ||
|
||
export function ChatMessage(props: ChatMessageProps) { | ||
return ( | ||
<div | ||
className={cn( | ||
{ | ||
"bg-zinc-50": props.message.role === "assistant", | ||
}, | ||
"pr-0 lg:pr-[260px]", | ||
fontMessage.className | ||
)} | ||
> | ||
<div className="m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-xl xl:max-w-3xl"> | ||
<div className="flex w-full gap-4 items-start"> | ||
{props.message.role === "user" ? ( | ||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gradient-to-r from-cyan-500 to-blue-500 p-2 select-none"> | ||
<div | ||
className="font-medium uppercase text-zinc-100" | ||
style={{ fontSize: 6 }} | ||
> | ||
User | ||
</div> | ||
</div> | ||
) : ( | ||
<div className="flex h-8 w-8 shrink-0 items-center justify-center select-none bg-zinc-300 rounded-full"> | ||
<IconOpenAI className="h-5 w-5" /> | ||
</div> | ||
)} | ||
<MemoizedReactMarkdown | ||
className="prose prose-stone prose-base prose-pre:rounded-md w-full flex-1 leading-6 prose-p:leading-[1.8rem] prose-pre:bg-[#282c34] max-w-full" | ||
remarkPlugins={[remarkGfm, remarkMath]} | ||
components={{ | ||
code({ node, inline, className, children, ...props }) { | ||
if (children.length) { | ||
if (children[0] == "▍") { | ||
return ( | ||
<span className="mt-1 animate-pulse cursor-default"> | ||
▍ | ||
</span> | ||
); | ||
} | ||
|
||
children[0] = (children[0] as string).replace("`▍`", "▍"); | ||
} | ||
|
||
const match = /language-(\w+)/.exec(className || ""); | ||
|
||
return !inline ? ( | ||
<CodeBlock | ||
key={Math.random()} | ||
language={(match && match[1]) || ""} | ||
value={String(children).replace(/\n$/, "")} | ||
{...props} | ||
/> | ||
) : ( | ||
<code className={className} {...props}> | ||
{children} | ||
</code> | ||
); | ||
}, | ||
table({ children }) { | ||
return ( | ||
<table className="border-collapse border border-black px-3 py-1 "> | ||
{children} | ||
</table> | ||
); | ||
}, | ||
th({ children }) { | ||
return ( | ||
<th className="break-words border border-black bg-gray-500 px-3 py-1 text-white "> | ||
{children} | ||
</th> | ||
); | ||
}, | ||
td({ children }) { | ||
return ( | ||
<td className="break-words border border-black px-3 py-1"> | ||
{children} | ||
</td> | ||
); | ||
}, | ||
}} | ||
> | ||
{props.message.content} | ||
</MemoizedReactMarkdown> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
ChatMessage.displayName = "ChatMessage"; | ||
|
||
export function IconOpenAI(props: JSX.IntrinsicElements["svg"]) { | ||
return ( | ||
<svg | ||
fill="#000000" | ||
width="800px" | ||
height="800px" | ||
viewBox="0 0 24 24" | ||
role="img" | ||
xmlns="http://www.w3.org/2000/svg" | ||
{...props} | ||
> | ||
<title>OpenAI icon</title> | ||
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" /> | ||
</svg> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
"use client"; | ||
|
||
import { type Message } from "@prisma/client"; | ||
import { useRouter } from "next/navigation"; | ||
import { ChatList } from "./chat-list"; | ||
import { Prompt } from "./prompt"; | ||
import { usePrompt } from "./use-prompt"; | ||
|
||
export interface ChatProps { | ||
// create?: (input: string) => Chat | undefined; | ||
messages?: Message[]; | ||
id?: string; | ||
} | ||
|
||
export function Chat({ | ||
id: _id, | ||
// create, | ||
messages, | ||
}: ChatProps) { | ||
const router = useRouter(); | ||
|
||
const { isLoading, messageList, appendUserMessage, reloadLastMessage } = | ||
usePrompt({ | ||
messages, | ||
_id, | ||
// onCreate: (id: string) => { | ||
// router.push(`/chat/${id}`); | ||
// }, | ||
}); | ||
|
||
return ( | ||
<main className="transition-width relative min-h-full w-full flex-1 overflow-y-auto flex flex-col"> | ||
<div className="flex-1"> | ||
<ChatList messages={messageList} /> | ||
</div> | ||
<div className="sticky light-gradient dark:bg-gradient-to-b dark:from-zinc-900 dark:to-zinc-950 bottom-0 left-0 w-full border-t bg-white dark:bg-black md:border-t-0 py-4 md:border-transparent md:!bg-transparent md:dark:border-transparent pr-0 lg:pr-[260px] flex dark:border-transparent items-center justify-center"> | ||
<Prompt | ||
onSubmit={appendUserMessage} | ||
onRefresh={messageList.length ? reloadLastMessage : undefined} | ||
isLoading={isLoading} | ||
/> | ||
</div> | ||
</main> | ||
); | ||
} | ||
|
||
Chat.displayName = "Chat"; |
Oops, something went wrong.