Merge branch 'main' into alt-drizzle

This commit is contained in:
Jared Palmer 2023-06-02 13:26:58 -04:00
commit 9469d8c892
13 changed files with 140 additions and 142 deletions

View file

@ -1,7 +1,6 @@
import { auth } from "@/auth";
import { chats, db } from "@/lib/db/schema";
import { openai } from "@/lib/openai";
import { nanoid } from "@/lib/utils";
import { OpenAIStream, StreamingTextResponse } from "ai-connector";
export const runtime = "edge";

View file

@ -5,6 +5,7 @@ import { type Message } from "ai-connector";
import { ChatMessage } from "./chat-message";
import { NextChatLogo } from "@/components/ui/nextchat-logo";
import { Plus } from "lucide-react";
import { EmptyScreen } from "./empty";
export interface ChatList {
messages: Message[];
@ -15,7 +16,7 @@ export function ChatList({ messages }: ChatList) {
<div className="relative h-full dark:bg-zinc-900">
<div className="sticky top-0 border-b w-full bg-black md:hidden text-white font-semibold">
<div className="px-4 py-2 flex items-center justify-between">
<div className="flex flex-row gap-1 whitespace-nowrap items-center">
<div className="flex flex-row gap-2 whitespace-nowrap items-center">
<NextChatLogo className="h-6 w-6" />
<span className="select-none">Next.js Chatbot</span>
</div>
@ -36,7 +37,9 @@ export function ChatList({ messages }: ChatList) {
/>
))}
</div>
) : null}
) : (
<EmptyScreen />
)}
</div>
</div>
);

View file

@ -1,9 +1,9 @@
"use client";
import { useRouter } from "next/navigation";
import { ChatList } from "./chat-list";
import { Prompt } from "./prompt";
import { useChat, type Message } from "ai-connector";
import { ChatList } from "./chat-list";
export interface ChatProps {
// create?: (input: string) => Chat | undefined;

56
app/empty.tsx Normal file
View file

@ -0,0 +1,56 @@
import { cn } from "@/lib/utils";
import { ExternalLink } from "./external-link";
import { fontMessage } from "@/lib/fonts";
function ExampleBubble({ children }: { children?: React.ReactNode }) {
return (
<div
className={cn(
"flex-1 flex items-start justify-between p-4 rounded-lg relative bg-zinc-100 text-sm font-medium transition-all cursor-pointer select-none hover:drop-shadow-[0_1px_1px_rgba(0,0,0,0.08)] hover:shadow-[0rem_0rem_0rem_0.0625rem_rgba(0,0,0,.02),0rem_0.125rem_0.25rem_rgba(0,0,0,.08),0rem_0.45rem_1rem_rgba(0,0,0,.06)] hover:bg-white group duration-300",
fontMessage.className
)}
style={{}}
>
<div
className="bg-zinc-100 w-9 h-6 absolute left-0 top-full -mt-[1px] scale-75 origin-top-left group-hover:bg-white transition-all duration-300"
style={{
clipPath:
'path("M31.1838 0C24.9593 10.7604 13.3251 18 0 18C9.94113 18 18 9.94113 18 0H31.1838Z")',
}}
></div>
<p>{children}</p>
</div>
);
}
export function EmptyScreen() {
return (
<div
className={cn(
"w-full h-full flex items-center justify-center pt-4 pb-8 pr-0 lg:pr-[260px]"
)}
>
<div className="p-8 rounded-lg flex flex-col items-center justify-center gap-8 max-w-2xl">
<div className="flex items-center justify-center gap-6">
<div className="text-zinc-500 font-medium">
<p>Welcome to Next.js Chatbot!</p>
<p className="mt-2">
This is an open source AI chatbot app built with{" "}
<ExternalLink href="https://nextjs.org">Next.js</ExternalLink> and{" "}
<ExternalLink href="https://vercel.com/storage/postgres">
Vercel Postgres
</ExternalLink>
. You can start a conversation here or try the following examples:
</p>
</div>
</div>
<div className="grid gap-x-4 gap-y-6 grid-cols-2 w-full">
<ExampleBubble>Explain technical concepts</ExampleBubble>
<ExampleBubble>Summarize article</ExampleBubble>
<ExampleBubble>Get assistance</ExampleBubble>
<ExampleBubble>Draft an email</ExampleBubble>
</div>
</div>
</div>
);
}

29
app/external-link.tsx Normal file
View file

@ -0,0 +1,29 @@
export function ExternalLink({
href,
children,
}: {
href: string;
children: React.ReactNode;
}) {
return (
<a
href={href}
target="_blank"
className="inline-flex gap-1 hover:underline flex-1 justify-center leading-4"
>
<span>{children}</span>
<svg
aria-hidden="true"
height="7"
viewBox="0 0 6 6"
width="7"
className="opacity-70"
>
<path
d="M1.25215 5.54731L0.622742 4.9179L3.78169 1.75597H1.3834L1.38936 0.890915H5.27615V4.78069H4.40513L4.41109 2.38538L1.25215 5.54731Z"
fill="currentColor"
></path>
</svg>
</a>
);
}

BIN
app/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -32,7 +32,7 @@ export function Prompt({
await onSubmit(input);
}}
ref={formRef}
className="stretch flex w-full flex-row gap-3 md:max-w-2xl lg:max-w-xl xl:max-w-3xl mx-auto px-4 lg:pl-16"
className="stretch flex w-full flex-row gap-3 md:max-w-2xl lg:max-w-xl xl:max-w-3xl mx-auto px-4"
>
<div className="relative flex h-full flex-1 flex-row-reverse items-stretch md:flex-col">
<div>

View file

@ -9,6 +9,7 @@ import { Plus } from "lucide-react";
import { unstable_cache } from "next/cache";
import Link from "next/link";
import { SidebarItem } from "./sidebar-item";
import { ExternalLink } from "./external-link";
export interface SidebarProps {
session?: Session;
@ -22,7 +23,7 @@ export function Sidebar({ session, newChat }: SidebarProps) {
<div className="scrollbar-trigger relative h-full w-full flex-1 items-start">
<aside className="flex h-full w-full flex-col p-2 shadow-lg ring-1 ring-zinc-900/10 dark:ring-zinc-200/10 relative z-10">
<div className="flex flex-row gap-1 items-center justify-between text-base font-semibold tracking-tight antialiased bg-black text-white px-4 py-4 -m-2 mb-2">
<div className="flex flex-row gap-1 whitespace-nowrap items-center">
<div className="flex flex-row gap-2 whitespace-nowrap items-center">
<NextChatLogo className="h-6 w-6" />
<span className="select-none">Next.js Chatbot</span>
</div>
@ -49,6 +50,33 @@ export function Sidebar({ session, newChat }: SidebarProps) {
<SidebarList session={session} />
</div>
</div>
<div>
<div className="flex gap-4 items-center justify-center text-sm font-medium leading-4 whitespace-nowrap">
<a
href="https://github.com/vercel/nextjs-ai-chatbot/"
target="_blank"
className="inline-flex gap-2 px-3 py-2 items-center border border-zinc-300 rounded-md hover:border-zinc-600 transition-colors"
>
<svg
aria-label="Vercel logomark"
height="13"
role="img"
className="w-auto overflow-hidden"
viewBox="0 0 74 64"
>
<path
d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z"
fill="var(--geist-foreground)"
></path>
</svg>
<span>Deploy</span>
</a>
<ExternalLink href="https://github.com/vercel/nextjs-ai-chatbot/">
View on GitHub
</ExternalLink>
</div>
</div>
</aside>
</div>
</div>

View file

@ -2,19 +2,10 @@ import NextAuth from "@auth/nextjs";
import GitHub from "@auth/nextjs/providers/github";
import { NextResponse } from "next/server";
import { PgAdapter } from "./lib/db";
export const {
handlers: { GET, POST },
auth,
CSRF_experimental,
} = NextAuth({
// adapter: PgAdapter(db, {
// accounts,
// users,
// sessions,
// verificationTokens,
// }),
// @ts-ignore
providers: [GitHub],
session: { strategy: "jwt" },

View file

@ -1,6 +1,8 @@
import { useId } from "react";
export function NextChatLogo(props: JSX.IntrinsicElements["svg"]) {
export function NextChatLogo(
props: JSX.IntrinsicElements["svg"] & { inverted?: boolean }
) {
const id = useId();
return (
<svg
@ -20,8 +22,12 @@ export function NextChatLogo(props: JSX.IntrinsicElements["svg"]) {
y2="14.2667"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="black" />
<stop offset={1} stopColor="black" stopOpacity={0} />
<stop stopColor={props.inverted ? "white" : "black"} />
<stop
offset={1}
stopColor={props.inverted ? "white" : "black"}
stopOpacity={0}
/>
</linearGradient>
<linearGradient
id={`gradient-${id}-2`}
@ -31,14 +37,18 @@ export function NextChatLogo(props: JSX.IntrinsicElements["svg"]) {
y2="9.50002"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="black" />
<stop offset={1} stopColor="black" stopOpacity={0} />
<stop stopColor={props.inverted ? "white" : "black"} />
<stop
offset={1}
stopColor={props.inverted ? "white" : "black"}
stopOpacity={0}
/>
</linearGradient>
</defs>
<path
d="M1 16L2.58314 11.2506C1.83084 9.74642 1.63835 8.02363 2.04013 6.39052C2.4419 4.75741 3.41171 3.32057 4.776 2.33712C6.1403 1.35367 7.81003 0.887808 9.4864 1.02289C11.1628 1.15798 12.7364 1.8852 13.9256 3.07442C15.1148 4.26363 15.842 5.83723 15.9771 7.5136C16.1122 9.18997 15.6463 10.8597 14.6629 12.224C13.6794 13.5883 12.2426 14.5581 10.6095 14.9599C8.97637 15.3616 7.25358 15.1692 5.74942 14.4169L1 16Z"
fill="white"
stroke="white"
fill={props.inverted ? "black" : "white"}
stroke={props.inverted ? "black" : "white"}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
@ -52,10 +62,10 @@ export function NextChatLogo(props: JSX.IntrinsicElements["svg"]) {
width={16}
height={16}
>
<circle cx={9} cy={8} r={8} fill="white" />
<circle cx={9} cy={8} r={8} fill={props.inverted ? "black" : "white"} />
</mask>
<g mask="url(#mask0_91_2047)">
<circle cx={9} cy={8} r={8} fill="white" />
<circle cx={9} cy={8} r={8} fill={props.inverted ? "black" : "white"} />
<path
d="M14.2896 14.0018L7.146 4.8H5.80005V11.1973H6.87681V6.16743L13.4444 14.6529C13.7407 14.4545 14.0231 14.2369 14.2896 14.0018Z"
fill={`url(#gradient-${id}-1)`}

View file

@ -20,8 +20,6 @@
"dependencies": {
"@auth/core": "0.0.0-manual.527fff6c",
"@auth/nextjs": "0.0.0-manual.030e8328",
"@next-auth/prisma-adapter": "1.0.6",
"@prisma/client": "^4.14.0",
"@radix-ui/react-dropdown-menu": "^2.0.4",
"@vercel/analytics": "^1.0.0",
"@vercel/kv": "^0.2.1",
@ -77,7 +75,6 @@
"eslint-plugin-tailwindcss": "^3.8.0",
"postcss": "^8.4.21",
"prettier": "^2.7.1",
"prisma": "^4.14.0",
"tailwindcss": "^3.3.1",
"ts-node": "^10.9.1",
"typescript": "^4.9.3"

115
pnpm-lock.yaml generated
View file

@ -10,12 +10,6 @@ dependencies:
'@auth/nextjs':
specifier: 0.0.0-manual.030e8328
version: 0.0.0-manual.030e8328(next@13.4.5-canary.3)(react@18.2.0)
'@next-auth/prisma-adapter':
specifier: 1.0.6
version: 1.0.6(@prisma/client@4.14.0)(next-auth@4.22.1)
'@prisma/client':
specifier: ^4.14.0
version: 4.14.0(prisma@4.14.0)
'@radix-ui/react-dropdown-menu':
specifier: ^2.0.4
version: 2.0.4(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
@ -177,9 +171,6 @@ devDependencies:
prettier:
specifier: ^2.7.1
version: 2.8.8
prisma:
specifier: ^4.14.0
version: 4.14.0
tailwindcss:
specifier: ^3.3.1
version: 3.3.2(ts-node@10.9.1)
@ -592,16 +583,6 @@ packages:
'@types/pg': 8.6.6
dev: false
/@next-auth/prisma-adapter@1.0.6(@prisma/client@4.14.0)(next-auth@4.22.1):
resolution: {integrity: sha512-Z7agwfSZEeEcqKqrnisBun7VndRPshd6vyDsoRU68MXbkui8storkHgvN2hnNDrqr/hSCF9aRn56a1qpihaB4A==}
peerDependencies:
'@prisma/client': '>=2.26.0 || >=3'
next-auth: ^4
dependencies:
'@prisma/client': 4.14.0(prisma@4.14.0)
next-auth: 4.22.1(next@13.4.5-canary.3)(react-dom@18.2.0)(react@18.2.0)
dev: false
/@next/env@13.4.5-canary.3:
resolution: {integrity: sha512-2TrPvCIs8R9DpFpEDmGUOpWkVqbpb4+sGQMcZVP4zDYYg893p0nAbNbBxL996oBl+/vLTzcLIDceP5peHsGPzg==}
dev: false
@ -727,28 +708,6 @@ packages:
tslib: 2.5.0
dev: true
/@prisma/client@4.14.0(prisma@4.14.0):
resolution: {integrity: sha512-MK/XaA2sFdfaOa7I9MjNKz6dxeIEdeZlnpNRoF2w3JuRLlFJLkpp6cD3yaqw2nUUhbrn3Iqe3ZpVV+VuGGil7Q==}
engines: {node: '>=14.17'}
requiresBuild: true
peerDependencies:
prisma: '*'
peerDependenciesMeta:
prisma:
optional: true
dependencies:
'@prisma/engines-version': 4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c
prisma: 4.14.0
dev: false
/@prisma/engines-version@4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c:
resolution: {integrity: sha512-3jum8/YSudeSN0zGW5qkpz+wAN2V/NYCQ+BPjvHYDfWatLWlQkqy99toX0GysDeaUoBIJg1vaz2yKqiA3CFcQw==}
dev: false
/@prisma/engines@4.14.0:
resolution: {integrity: sha512-PDNlhP/1vyTgmNyiucGqGCdXIp7HIkkvKO50si3y3PcceeHvqtiKPaH1iJdz63jCWMVMbj2MElSxXPOeBvEVIQ==}
requiresBuild: true
/@radix-ui/primitive@1.0.0:
resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==}
dependencies:
@ -4049,31 +4008,6 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
/next-auth@4.22.1(next@13.4.5-canary.3)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-NTR3f6W7/AWXKw8GSsgSyQcDW6jkslZLH8AiZa5PQ09w1kR8uHtR9rez/E9gAq/o17+p0JYHE8QjF3RoniiObA==}
peerDependencies:
next: ^12.2.5 || ^13
nodemailer: ^6.6.5
react: ^17.0.2 || ^18
react-dom: ^17.0.2 || ^18
peerDependenciesMeta:
nodemailer:
optional: true
dependencies:
'@babel/runtime': 7.21.5
'@panva/hkdf': 1.1.1
cookie: 0.5.0
jose: 4.14.4
next: 13.4.5-canary.3(@babel/core@7.21.8)(react-dom@18.2.0)(react@18.2.0)
oauth: 0.9.15
openid-client: 5.4.2
preact: 10.14.1
preact-render-to-string: 5.2.6(preact@10.14.1)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
uuid: 8.3.2
dev: false
/next-themes@0.2.1(next@13.4.5-canary.3)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
peerDependencies:
@ -4179,19 +4113,10 @@ packages:
resolution: {integrity: sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==}
dev: false
/oauth@0.9.15:
resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
dev: false
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
/object-hash@2.2.0:
resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
engines: {node: '>= 6'}
dev: false
/object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
@ -4257,11 +4182,6 @@ packages:
es-abstract: 1.21.2
dev: true
/oidc-token-hash@5.0.3:
resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==}
engines: {node: ^10.13.0 || >=12.0.0}
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@ -4296,15 +4216,6 @@ packages:
engines: {node: '>=12'}
dev: false
/openid-client@5.4.2:
resolution: {integrity: sha512-lIhsdPvJ2RneBm3nGBBhQchpe3Uka//xf7WPHTIglery8gnckvW7Bd9IaQzekzXJvWthCMyi/xVEyGW0RFPytw==}
dependencies:
jose: 4.14.4
lru-cache: 6.0.0
object-hash: 2.2.0
oidc-token-hash: 5.0.3
dev: false
/optionator@0.9.1:
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
engines: {node: '>= 0.8.0'}
@ -4523,23 +4434,10 @@ packages:
pretty-format: 3.8.0
dev: false
/preact-render-to-string@5.2.6(preact@10.14.1):
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
peerDependencies:
preact: '>=10'
dependencies:
preact: 10.14.1
pretty-format: 3.8.0
dev: false
/preact@10.11.3:
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
dev: false
/preact@10.14.1:
resolution: {integrity: sha512-4XDSnUisk3YFBb3p9WeKeH1mKoxdFUsaXcvxs9wlpYR1wax/TWJVqhwmIWbByX0h7jMEJH6Zc5J6jqc58FKaNQ==}
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -4555,14 +4453,6 @@ packages:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
dev: false
/prisma@4.14.0:
resolution: {integrity: sha512-+5dMl1uxMQb4RepndY6AwR9xi1cDcaGFICu+ws6/Nmgt93mFPNj8tYxSfTdmfg+rkNrUId9rk/Ac2vTgLe/oXA==}
engines: {node: '>=14.17'}
hasBin: true
requiresBuild: true
dependencies:
'@prisma/engines': 4.14.0
/prismjs@1.27.0:
resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==}
engines: {node: '>=6'}
@ -5448,11 +5338,6 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
/uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
dev: false
/uuid@9.0.0:
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
hasBin: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB