diff --git a/apps/api/app/v1/[[...route]]/health.ts b/apps/api/app/v1/[[...route]]/health.ts index 9a23dd3..6c24021 100644 --- a/apps/api/app/v1/[[...route]]/health.ts +++ b/apps/api/app/v1/[[...route]]/health.ts @@ -1,5 +1,6 @@ import { Hono } from "hono"; -const app = new Hono().get("/", (c) => { +const app = new Hono() +.get("/", (c) => { return c.json({ message: "i am alive", status: 200, diff --git a/apps/api/app/v1/[[...route]]/route.ts b/apps/api/app/v1/[[...route]]/route.ts index 2d59189..024bedc 100644 --- a/apps/api/app/v1/[[...route]]/route.ts +++ b/apps/api/app/v1/[[...route]]/route.ts @@ -21,6 +21,7 @@ const allowedOrigins = [ "http://localhost:3004", "https://www.plura.pro", "https://app.plura.pro", + "https://status.plura.pro", ]; app.use( @@ -52,3 +53,5 @@ const DELETE = handle(app); const OPTIONS = handle(app); export { GET, PATCH, POST, DELETE, OPTIONS }; + + diff --git a/apps/api/app/v1/[[...route]]/session.ts b/apps/api/app/v1/[[...route]]/session.ts index 3472b80..e5a71b7 100644 --- a/apps/api/app/v1/[[...route]]/session.ts +++ b/apps/api/app/v1/[[...route]]/session.ts @@ -4,7 +4,7 @@ import { auth } from "@repo/auth"; const app = new Hono() .get("/", async (c) => { const session = await auth.api.getSession({ headers: c.req.raw.headers }); - + if (!session) return c.json({ message: "no session found" }, 401); return c.json({ diff --git a/apps/api/app/v1/[[...route]]/user.ts b/apps/api/app/v1/[[...route]]/user.ts index 6cb3f66..926b0f5 100644 --- a/apps/api/app/v1/[[...route]]/user.ts +++ b/apps/api/app/v1/[[...route]]/user.ts @@ -3,7 +3,7 @@ import { prisma } from "@repo/db"; import { auth } from "@repo/auth"; const app = new Hono() - .get("/self", async (c) => { + .get("/self", async (c) => { const currentUser = await auth.api.getSession({ headers: c.req.raw.headers, }); @@ -23,6 +23,7 @@ const app = new Hono() id: currentUser.user.id, }, }); + return c.json( { user, diff --git a/apps/api/package.json b/apps/api/package.json index fd7e61b..7327e3d 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,8 +4,8 @@ "dev": "next dev -p 3001 --turbopack", "prebuild": "turbo --filter=@repo/db db:generate", "build": "next build", - "start": "next start -p 5555", - "preview": "next build && next start -p 5555", + "start": "next start -p 3001", + "preview": "next build && next start -p 3001", "lint": "next lint", "lint:fix": "next lint --fix", "test": "vitest --run", diff --git a/apps/app/actions/action.tsx b/apps/app/actions/action.tsx new file mode 100644 index 0000000..758e24f --- /dev/null +++ b/apps/app/actions/action.tsx @@ -0,0 +1,156 @@ +"use server"; +import { ReactNode } from "react"; +import { createStreamableValue, getMutableAIState, streamUI } from "ai/rsc"; +import { togetherai } from "@ai-sdk/togetherai"; +import { AI } from "@/lib/ai"; +import { BotMessage } from "@/components/custom/onboarding/message"; +import BeatLoader from "@/components/custom/onboarding/BeatLoader"; +import { getSession } from "./session"; +import { z } from "zod"; +import { Button } from "@/components/ui/button"; +import Proceed from "@/components/custom/onboarding/proceed"; +import WorkspaceForm from "@/components/custom/onboarding/workspace-form"; +import {sleep } from "@/lib/utils"; +import { CoreMessage, generateId,ToolInvocation } from "ai"; +export type ServerMessage = { + id?: number; + name?: "proceed" | "workspace" ; + role: "user" | "assistant"; + content: string; +}; + +export type ClientMessage = { + id: number; + role: "user" | "assistant"; + display: ReactNode; + toolInvocations?: ToolInvocation[] +}; + +export const sendMessage = async ( + message: string +): Promise => { + const history = getMutableAIState(); + console.log(history.get().length) + console.log("ai",history.get()) + + history.update([...history.get(), { role: "user", content: message }]); + + const response = await streamUI({ + model: togetherai("meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"), + system: ` + You are an onboarding assitand and you are helping users to onboard them to Plura AI. + -any question not related to the onbaording should not be answered by you + -if someone asks any message that is not related to the onboarding then you should respond with the exact same text "wlecome to Plura" + -if the message comes as "should we continue" then call proceed tool + The workflow is as follows: + -User sends "yes" or "no" to proceed + -If the user sends "yes" then the workflow is as follows: + -then you call the workspace tool + - If the user sends "no", respond with exactly: "please create a workspace to continue your onboarding" Do not call any tools for "no" + - Only trigger the proceed tool when asking: "should we continue?" + -If the user sends any message after workspace tool is called then you should respond with the same text:"Please create a workspace to continue" + -dont call any tools if the user doesnt creates a workspace + -If the message comes as workspace {workspaceName} created then respond with the exact same text "your first workspace has been created with name: {workspaceName} created" and dont call any tools + `, + messages: [{ role: "user", content: message }, ...history.get()], + temperature: 0, + initial: ( + + + + ), + text: async function ({ content, done }) { + await sleep(1000); + if (done) { + history.done([...history.get(), { role: "assistant", content }]); + } + return {content}; + }, + tools: { + workspace: { + description: + "when the user responds with yes then render the workspace form", + parameters: z.object({}), + generate: async function* ({}) { + yield ( + + + + ); + console.log("before"); + history.done([ + ...history.get(), + { role: "assistant", content: "workspace form rendered" }, + ]); + console.log("history", history.get()); + console.log("after"); + + return ( + + + + ); + }, + }, + proceed: { + description: `should we continue option that contains yes and no options`, + parameters: z.object({}), + generate: async function* ({}) { + yield ( + + + + ); + + history.done([ + ...history.get(), + { role: "assistant", content: "should be continue rendered" }, + ]); + + return ( + + + + ); + }, + }, + }, + }); + + return { + id: Date.now(), + role: "assistant" as const, + display: response.value, + }; +}; + export const sendAiGreeting = async ():Promise => { + const session= await getSession() + const {name,email} = session!.user + const contentString = `Hi ${name}, welcome to Plura AI!.Your email is ${email}.I am going to help you with oboarding your acccount` + const history = getMutableAIState(); + console.log("greeting history", history.get()) + const value = await streamUI({ + model: togetherai("meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"), + system: ` always reply the exact same text exactly as it is: ${contentString} + `, + messages: history.get(), + initial: ( + + + + ), + text: async function ({ content, done }) { + await sleep(1000); + if (done) { + history.done([...history.get(), { role: "assistant", content }]); + } + return {content}; + }, + }); + + return [{ + id: Date.now(), + role: "assistant" as const, + display: value.value, + }] + } diff --git a/apps/app/actions/session.ts b/apps/app/actions/session.ts new file mode 100644 index 0000000..ce37587 --- /dev/null +++ b/apps/app/actions/session.ts @@ -0,0 +1,17 @@ +"use server" +import { betterFetch } from "@better-fetch/fetch"; +import { Session } from "@repo/auth"; +import { headers } from "next/headers"; + +export const getSession = async () => { + + const response = await betterFetch("http://localhost:3001/api/auth/get-session", + { + baseURL: "http://localhost:3002", + headers: { + cookie: (await headers()).get("cookie") || "", + }, + }); + return response.data + +} \ No newline at end of file diff --git a/apps/app/app/(onboarding)/onboarding/layout.tsx b/apps/app/app/(onboarding)/onboarding/layout.tsx new file mode 100644 index 0000000..d1eacb5 --- /dev/null +++ b/apps/app/app/(onboarding)/onboarding/layout.tsx @@ -0,0 +1,5 @@ +import { AI } from "@/lib/ai"; + +export default function OnboardingLayout({children}: {children: React.ReactNode}) { + return {children}; +} \ No newline at end of file diff --git a/apps/app/app/(onboarding)/onboarding/page.tsx b/apps/app/app/(onboarding)/onboarding/page.tsx new file mode 100644 index 0000000..8805568 --- /dev/null +++ b/apps/app/app/(onboarding)/onboarding/page.tsx @@ -0,0 +1,6 @@ +import Chatbox from "@/components/custom/onboarding/chatbox"; + +export default function Onboarding() { + + return +} \ No newline at end of file diff --git a/apps/app/app/(routes)/layout.tsx b/apps/app/app/(routes)/layout.tsx new file mode 100644 index 0000000..e3fdd33 --- /dev/null +++ b/apps/app/app/(routes)/layout.tsx @@ -0,0 +1,20 @@ +import Infobar from "@/components/custom/infobar/infobar"; +import ProgressBar from "@/components/custom/progress.bar"; +import { AppSidebar } from "@/components/custom/sidebar/sidebar"; +import { SidebarProvider } from "@/components/ui/sidebar"; +import { cookies } from "next/headers"; +async function RouteLayout({children}: {children: React.ReactNode}) { + const cookieStore = await cookies(); + const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true"; + return ( + + +
+ + + {children} +
+
+ ); +} +export default RouteLayout; diff --git a/apps/app/app/layout.tsx b/apps/app/app/layout.tsx index c1d8ddb..2aca746 100644 --- a/apps/app/app/layout.tsx +++ b/apps/app/app/layout.tsx @@ -2,13 +2,9 @@ import type { Metadata } from "next"; import { GeistSans } from "geist/font/sans"; import "./globals.css"; import { ThemeProvider } from "@/hooks/theme-provider"; -import { SidebarProvider } from "@/components/ui/sidebar"; -import { AppSidebar } from "@/components/custom/sidebar/sidebar"; -import { cookies } from "next/headers"; -import Infobar from "@/components/custom/infobar/infobar"; -import ProgressBar from "@/components/custom/progress.bar"; import { PosthogProvider } from "@/hooks/posthog"; - +import { AI } from "@/lib/ai"; +import { Toaster } from "sonner"; export const metadata: Metadata = { title: "Plura", description: "Generated by create next app", @@ -19,8 +15,6 @@ async function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const cookieStore = await cookies(); - const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true"; return ( @@ -34,14 +28,8 @@ async function RootLayout({ enableSystem disableTransitionOnChange > - - -
- - - {children} -
-
+ + {children} diff --git a/apps/app/components/custom/onboarding/BeatLoader.tsx b/apps/app/components/custom/onboarding/BeatLoader.tsx new file mode 100644 index 0000000..f43132d --- /dev/null +++ b/apps/app/components/custom/onboarding/BeatLoader.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { motion } from "motion/react"; + +export default function BeatLoader() { + return ( +
+ {[0, 1, 2].map((index) => ( + + ))} +
+ ); +} diff --git a/apps/app/components/custom/onboarding/ChatInput.tsx b/apps/app/components/custom/onboarding/ChatInput.tsx new file mode 100644 index 0000000..39ce968 --- /dev/null +++ b/apps/app/components/custom/onboarding/ChatInput.tsx @@ -0,0 +1,34 @@ +import { Textarea } from "@/components/ui/textarea"; +import {ArrowUp} from "lucide-react"; + +export function ChatInput() { + return ( +
+
+
+
+