Try to hack auth

This commit is contained in:
Jared Palmer 2023-06-02 11:15:04 -04:00
parent d88eae7230
commit 030b23985d
19 changed files with 330 additions and 673 deletions

43
app/api/chat/route.ts Normal file
View file

@ -0,0 +1,43 @@
import { auth } from "@/auth";
import { chats, db } from "@/lib/db/schema";
import { openai } from "@/lib/openai";
import { OpenAIStream, StreamingTextResponse } from "ai-connector";
export const runtime = "edge";
export const POST = auth(async function POST(req: Request) {
const json = await req.json();
// @ts-ignore
console.log(req.auth); // todo fix types
const res = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: json.messages.map((m: any) => ({
content: m.content,
role: m.role,
})),
temperature: 0.7,
top_p: 1,
frequency_penalty: 1,
max_tokens: 500,
n: 1,
stream: true,
});
const stream = await OpenAIStream(res, {
async onCompletion(completion) {
// @ts-ignore
if (req.auth?.user?.email == null) {
return;
}
const title = json.messages[0].content.substring(0, 20);
await db.insert(chats).values({
id: crypto.randomUUID(),
title,
userId: (req as any).auth?.user?.email,
});
},
});
return new StreamingTextResponse(stream);
});

View file

@ -1,45 +0,0 @@
import { auth } from "@/auth";
import { OpenAIStream, openai } from "@/lib/openai";
import { prisma } from "@/lib/prisma";
export const POST = auth(async function POST(req: Request) {
const json = await req.json();
// @ts-ignore
console.log(req.auth); // todo fix types
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);
let fullResponse = "";
const decoder = new TextDecoder();
const saveToPrisma = new TransformStream({
transform: async (chunk, controller) => {
controller.enqueue(chunk);
fullResponse += decoder.decode(chunk);
},
flush: async () => {
await prisma.chat.upsert({
where: {
id: json.id,
},
create: json,
update: json,
});
},
});
return new Response(stream.pipeThrough(saveToPrisma), {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
});

View file

@ -1,6 +1,6 @@
"use client";
import { type Message } from "@prisma/client";
import { type Message } from "ai-connector";
import { ChatMessage } from "./chat-message";
import { NextChatLogo } from "@/components/ui/nextchat-logo";

View file

@ -4,39 +4,43 @@ 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";
import { useChat } from "ai-connector";
export interface ChatProps {
// create?: (input: string) => Chat | undefined;
messages?: Message[];
initialMessages?: Message[];
id?: string;
}
export function Chat({
id,
// create,
messages,
initialMessages,
}: ChatProps) {
const router = useRouter();
const { isLoading, messageList, appendUserMessage, reloadLastMessage } =
usePrompt({
messages,
id,
// onCreate: (id: string) => {
// router.push(`/chat/${id}`);
// },
});
const { isLoading, messages, reload, append } = useChat({
initialMessages: initialMessages as any[],
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} />
<ChatList messages={messages} />
</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}
onSubmit={(value) => {
append({
content: value,
role: "user",
});
}}
onRefresh={messages.length ? reload : undefined}
isLoading={isLoading}
/>
</div>

View file

@ -46,7 +46,7 @@ export default async function ChatPage({ params }: ChatPageProps) {
<div className="relative flex h-full w-full overflow-hidden">
<Sidebar session={session} />
<div className="flex h-full min-w-0 flex-1 flex-col">
<Chat id={chat.id} messages={chat.messages} />
<Chat id={chat.id} initialMessages={chat.messages} />
</div>
</div>
);

View file

@ -8,6 +8,7 @@ import { Plus } from "lucide-react";
import Link from "next/link";
import { unstable_cache } from "next/cache";
import { SidebarItem } from "./sidebar-item";
import { db } from "@/lib/db/schema";
export interface SidebarProps {
session?: Session;
@ -60,16 +61,7 @@ Sidebar.displayName = "Sidebar";
async function SidebarList({ session }: { session?: Session }) {
const chats = await (
await unstable_cache(
() =>
prisma.chat.findMany({
where: {
// This is for debugging, need to add scope to the query later
// userId: session?.user.id,
},
orderBy: {
updatedAt: "desc",
},
}),
() => db.query.chats.findMany({}),
// @ts-ignore
[session?.user?.id || ""],
{

View file

@ -1,130 +0,0 @@
import { useState, useCallback, useRef, useEffect } from "react";
import { type Message } from "@prisma/client";
import { nanoid } from "@/lib/utils";
export function usePrompt({
messages = [],
id,
}: {
messages?: Message[];
id: string | undefined;
}) {
const [isLoading, setIsLoading] = useState(false);
const [messageList, setMessageList] = useState(messages);
const isLoadingRef = useRef(isLoading);
const messageListRef = useRef(messageList);
useEffect(() => {
isLoadingRef.current = isLoading;
}, [isLoading]);
useEffect(() => {
messageListRef.current = messageList;
}, [messageList]);
const appendUserMessage = useCallback(
async (content: string | Message) => {
// Prevent multiple requests at once
if (isLoadingRef.current) return;
const userMsg =
typeof content === "string"
? ({ id: nanoid(10), role: "user", content } as Message)
: content;
const assMsg = {
id: nanoid(10),
role: "assistant",
content: "",
} as Message;
const messageListSnapshot = messageListRef.current;
// Reset output
setIsLoading(true);
try {
// Set user input immediately
setMessageList([...messageListSnapshot, userMsg]);
// If streaming, we need to use fetchEventSource directly
const response = await fetch(`/api/generate`, {
method: "POST",
body: JSON.stringify({
id: id || nanoid(10),
messages: [...messageListSnapshot, userMsg].map((m) => ({
role: m.role,
content: m.content,
})),
}),
headers: { "Content-Type": "application/json" },
});
// This data is a ReadableStream
const data = response.body;
if (!data) {
return;
}
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
let accumulatedValue = ""; // Variable to accumulate chunks
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
accumulatedValue += chunkValue; // Accumulate the chunk value
// Check if the accumulated value contains the delimiter
const delimiter = "\n";
const chunks = accumulatedValue.split(delimiter);
// Process all chunks except the last one (which may be incomplete)
while (chunks.length > 1) {
const chunkToDispatch = chunks.shift(); // Get the first chunk
if (chunkToDispatch && chunkToDispatch.length > 0) {
const chunk = JSON.parse(chunkToDispatch);
assMsg.content += chunk;
setMessageList([...messageListSnapshot, userMsg, assMsg]);
}
}
// The last chunk may be incomplete, so keep it in the accumulated value
accumulatedValue = chunks[0];
}
// Process any remaining accumulated value after the loop is done
if (accumulatedValue.length > 0) {
assMsg.content += accumulatedValue;
setMessageList([...messageListSnapshot, userMsg, assMsg]);
}
} finally {
setIsLoading(false);
}
},
[id]
);
const reloadLastMessage = useCallback(async () => {
// Prevent multiple requests at once
if (isLoadingRef.current) return;
const userMsg = messageListRef.current.at(-2);
const assMsg = messageListRef.current.at(-1);
// Both should exist.
if (!userMsg || !assMsg) return;
messageListRef.current = messageListRef.current.slice(0, -2);
setMessageList(messageListRef.current);
await appendUserMessage(userMsg);
}, [appendUserMessage]);
return {
messageList,
appendUserMessage,
reloadLastMessage,
isLoading,
};
}