diff --git a/app/api/chat/init/route.ts b/app/api/chat/init/route.ts new file mode 100644 index 0000000..060c87a --- /dev/null +++ b/app/api/chat/init/route.ts @@ -0,0 +1,30 @@ +import { NextRequest, NextResponse } from "next/server" +import { initialChatMessage } from "@/utils/chat" + +import { createPrisma } from "@/lib/prisma" + +export async function POST(request: Request) { + const body = await request.json() + const { childId, childContext } = body + + const credentials = { + supabaseDatabaseUrl: process.env.DATABASE_URL, + } + + const childInitialContextMessage = [ + { + name: initialChatMessage.name, + text: `${initialChatMessage.text} ${childContext}`, + }, + ] + const prisma = createPrisma({ url: credentials.supabaseDatabaseUrl }) + const data = await prisma.chatHistory.create({ + data: { + childId: childId, + messages: childInitialContextMessage, + }, + }) + + return NextResponse.json({ data }) +} + diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 2952780..6f77b97 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -1,9 +1,12 @@ +import { NextRequest, NextResponse } from "next/server" +import { Prisma } from "@prisma/client" + import { getChain } from "@/lib/langchain/chain" import { ModelHandler } from "@/lib/langchain/model" import { getPineconeStore } from "@/lib/langchain/vectorstores/pinecone" -import { NextRequest, NextResponse } from "next/server" +import { createPrisma } from "@/lib/prisma" -export const runtime = "edge" +// export const runtime = "edge" export async function POST(request: NextRequest) { const body = await request.json() @@ -17,7 +20,7 @@ export async function POST(request: NextRequest) { supabaseUrl: process.env.SUPABASE_URL, supabaseBucket: process.env.SUPABASE_BUCKET, supabaseDatabaseUrl: process.env.DATABASE_URL, - supabaseDirectUrl: process.env.DIRECT_URL + supabaseDirectUrl: process.env.DIRECT_URL, } if ( !credentials || @@ -28,7 +31,22 @@ export async function POST(request: NextRequest) { return NextResponse.redirect("/credentials") } - const { prompt, messages: history } = body + const { prompt, chatId } = body + + //Get history from supabase against child id + const prisma = createPrisma({ url: credentials.supabaseDatabaseUrl }) + const historyFromDB = await prisma.chatHistory.findFirst({ + where: { + id: chatId, + }, + }) + + //Construct an array of message history to send it to model + let messageHistory = [] + const chatMessages = historyFromDB.messages as Prisma.JsonArray + chatMessages.map((message) => { + messageHistory.push(message) + }) // OpenAI recommends replacing newlines with spaces for best results const sanitizedQuestion = `${prompt.trim().replaceAll("\n", " ")}` @@ -41,7 +59,37 @@ export async function POST(request: NextRequest) { const modelHandler = new ModelHandler(writer) const model = modelHandler.getModel(credentials.openaiApiKey) - const response = getChain(model, vectorStore, sanitizedQuestion, history) + const response = getChain( + model, + vectorStore, + sanitizedQuestion, + messageHistory + ) + + // Push current prompt to message history array + messageHistory.push({ + name: "human", + text: prompt, + }) + + //Resolve the promise returned by langchain + Promise.resolve(response).then(async (res) => { + //Push response to message history array + messageHistory.push({ + name: "ai", + text: res.text, + }) + + //Update message history array in table against chatId + await prisma.chatHistory.update({ + where: { + id: chatId, + }, + data: { + messages: messageHistory, + }, + }) + }) return new NextResponse(stream.readable, { headers: { diff --git a/prisma/migrations/20231002122742_added_chat_history_table/migration.sql b/prisma/migrations/20231002122742_added_chat_history_table/migration.sql new file mode 100644 index 0000000..952a602 --- /dev/null +++ b/prisma/migrations/20231002122742_added_chat_history_table/migration.sql @@ -0,0 +1,20 @@ +-- CreateTable +CREATE TABLE "Documents" ( + "id" TEXT NOT NULL, + "name" TEXT, + "url" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Documents_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ChatHistory" ( + "id" TEXT NOT NULL, + "childId" TEXT, + "messages" JSONB NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "ChatHistory_pkey" PRIMARY KEY ("id") +); diff --git a/prisma/migrations/20231002132845_added_title_column_in_chathistory_table/migration.sql b/prisma/migrations/20231002132845_added_title_column_in_chathistory_table/migration.sql new file mode 100644 index 0000000..6c37b0f --- /dev/null +++ b/prisma/migrations/20231002132845_added_title_column_in_chathistory_table/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `title` to the `ChatHistory` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "ChatHistory" ADD COLUMN "title" TEXT NOT NULL; diff --git a/prisma/migrations/20231002133243_updated_chathistory_table/migration.sql b/prisma/migrations/20231002133243_updated_chathistory_table/migration.sql new file mode 100644 index 0000000..a64cc60 --- /dev/null +++ b/prisma/migrations/20231002133243_updated_chathistory_table/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - Made the column `childId` on table `ChatHistory` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "ChatHistory" ALTER COLUMN "childId" SET NOT NULL, +ALTER COLUMN "title" DROP NOT NULL; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d7b1204..c5cab1d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,4 +16,13 @@ model Documents { name String? url String created_at DateTime @default(now()) +} + +model ChatHistory { + id String @id @default(cuid()) + childId String + title String? + messages Json + created_at DateTime @default(now()) + updated_at DateTime @default(now()) } \ No newline at end of file diff --git a/utils/chat.ts b/utils/chat.ts new file mode 100644 index 0000000..a72bcb4 --- /dev/null +++ b/utils/chat.ts @@ -0,0 +1,4 @@ +export const initialChatMessage = { + name: "system", + text: "Act as an expert. Reply to questions about given data. Self reflect on your answers. Following is some of my child's information and you need to answer all my questions considering this context, ", +}