server auth stuff, prooompt engineering
This commit is contained in:
@@ -8,7 +8,7 @@ export default function AssistantModalPage() {
|
|||||||
const { data: session, error, isLoading } = trpc.chat.getSession.useQuery();
|
const { data: session, error, isLoading } = trpc.chat.getSession.useQuery();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
&& <ChatModal sessionId={session?.id} />
|
<ChatModal sessionId={session?.id} />
|
||||||
{error && <div>{error.message}</div>}
|
{error && <div>{error.message}</div>}
|
||||||
{isLoading && <Skeleton />}
|
{isLoading && <Skeleton />}
|
||||||
</>
|
</>
|
||||||
|
|||||||
8
src/app/actions/currentTime.ts
Normal file
8
src/app/actions/currentTime.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default function currentTime() {
|
||||||
|
let now = Date.now();
|
||||||
|
console.log(now);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
time: now
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
'use server'
|
'use server'
|
||||||
import { clerkClient } from '@clerk/nextjs/server'
|
import { clerkClient, auth } from '@clerk/nextjs/server'
|
||||||
import { google } from 'googleapis'
|
import { google } from 'googleapis'
|
||||||
import { env } from '~/env'
|
import { env } from '~/env'
|
||||||
|
|
||||||
@@ -10,7 +10,6 @@ export async function scheduleMeeting({
|
|||||||
durationMinutes,
|
durationMinutes,
|
||||||
attendeeEmail,
|
attendeeEmail,
|
||||||
attendeeName,
|
attendeeName,
|
||||||
userId,
|
|
||||||
}: {
|
}: {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
@@ -18,11 +17,11 @@ export async function scheduleMeeting({
|
|||||||
durationMinutes: number
|
durationMinutes: number
|
||||||
attendeeEmail?: string
|
attendeeEmail?: string
|
||||||
attendeeName?: string
|
attendeeName?: string
|
||||||
userId: string
|
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const clerk = await clerkClient()
|
const clerk = await clerkClient()
|
||||||
|
const userAuth = await auth()
|
||||||
|
const user = await clerk.users.getUser(userAuth.userId?userAuth.userId:"")
|
||||||
// Get admin's Google OAuth token to create the event on Gregor's calendar
|
// Get admin's Google OAuth token to create the event on Gregor's calendar
|
||||||
const adminTokenResponse = await clerk.users.getUserOauthAccessToken(
|
const adminTokenResponse = await clerk.users.getUserOauthAccessToken(
|
||||||
env.ADMIN_USER_CLERK_ID,
|
env.ADMIN_USER_CLERK_ID,
|
||||||
@@ -37,16 +36,7 @@ export async function scheduleMeeting({
|
|||||||
// Try to resolve visitor's Google email for the invite
|
// Try to resolve visitor's Google email for the invite
|
||||||
let visitorEmail: string | undefined = attendeeEmail
|
let visitorEmail: string | undefined = attendeeEmail
|
||||||
if (!visitorEmail) {
|
if (!visitorEmail) {
|
||||||
try {
|
visitorEmail = user?.emailAddresses.at(0)?.emailAddress ?? undefined
|
||||||
const visitorTokenResponse = await clerk.users.getUserOauthAccessToken(userId, 'oauth_google')
|
|
||||||
if (visitorTokenResponse.data[0]) {
|
|
||||||
const user = await clerk.users.getUser(userId)
|
|
||||||
const googleAccount = user.externalAccounts.find((a) => a.provider === 'google')
|
|
||||||
visitorEmail = googleAccount?.emailAddress ?? undefined
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Visitor not signed in with Google — no invite
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const oAuth2Client = new google.auth.OAuth2()
|
const oAuth2Client = new google.auth.OAuth2()
|
||||||
@@ -71,6 +61,7 @@ export async function scheduleMeeting({
|
|||||||
end: { dateTime: endTime.toISOString(), timeZone: 'UTC' },
|
end: { dateTime: endTime.toISOString(), timeZone: 'UTC' },
|
||||||
attendees,
|
attendees,
|
||||||
},
|
},
|
||||||
|
sendNotifications: true
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { db } from '~/server/db'
|
|||||||
import { chatSession, chatMessage } from '~/server/dbschema/schema'
|
import { chatSession, chatMessage } from '~/server/dbschema/schema'
|
||||||
import { servTrpc } from '~/app/_trpc/ServerClient'
|
import { servTrpc } from '~/app/_trpc/ServerClient'
|
||||||
import { scheduleMeeting } from '~/app/actions/scheduleMeeting'
|
import { scheduleMeeting } from '~/app/actions/scheduleMeeting'
|
||||||
|
import currentTime from '~/app/actions/currentTime';
|
||||||
|
|
||||||
const openai = createOpenAI({ apiKey: env.OPENAI_API_KEY })
|
const openai = createOpenAI({ apiKey: env.OPENAI_API_KEY })
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ export async function POST(req: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = streamText({
|
const result = streamText({
|
||||||
model: openai('gpt-4o'),
|
model: openai('gpt-5-mini'),
|
||||||
system: systemPrompt,
|
system: systemPrompt,
|
||||||
messages: await convertToModelMessages(messages),
|
messages: await convertToModelMessages(messages),
|
||||||
tools: {
|
tools: {
|
||||||
@@ -64,22 +65,22 @@ export async function POST(req: Request) {
|
|||||||
.int()
|
.int()
|
||||||
.min(15)
|
.min(15)
|
||||||
.max(120)
|
.max(120)
|
||||||
.describe('Duration of the meeting in minutes'),
|
.describe('Duration of the meeting in minutes, if none provided ask if 20 minutes is ok'),
|
||||||
attendeeEmail: z
|
attendeeEmail: z
|
||||||
.string()
|
.string()
|
||||||
.email()
|
.email()
|
||||||
.optional()
|
.optional()
|
||||||
.describe('Email of the visitor to invite (if provided)'),
|
.describe('Optional Email of the visitor to invite (if provided)'),
|
||||||
attendeeName: z.string().optional().describe('Name of the visitor'),
|
attendeeName: z.string().optional().describe('Name of the visitor'),
|
||||||
}),
|
}),
|
||||||
execute: async (input) => scheduleMeeting({ ...input, userId }),
|
execute: async (input) => scheduleMeeting({ ...input }),
|
||||||
}),
|
}),
|
||||||
getCurrentUnixTime: tool({
|
getCurrentUnixTime: tool({
|
||||||
description: 'Get the current unix time to reference for meeting dates',
|
description: 'Get the current unix time to reference for meeting dates',
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
none: z.string().optional().describe("no inputs are needed")
|
none: z.string().optional().describe("no inputs are needed")
|
||||||
}),
|
}),
|
||||||
execute: async () => { return {success: true, currentTime: Date.now()} }
|
execute: async () => currentTime()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
stopWhen: stepCountIs(5),
|
stopWhen: stepCountIs(5),
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default function ChatInterface({ sessionId }: ChatInterfaceProps) {
|
|||||||
})
|
})
|
||||||
const handleSend = () => {
|
const handleSend = () => {
|
||||||
const text = input.trim()
|
const text = input.trim()
|
||||||
if (!text || status != 'ready') return
|
if (!text || status != 'ready' || sessionId == undefined) return
|
||||||
setInput('')
|
setInput('')
|
||||||
sendMessage({ text })
|
sendMessage({ text })
|
||||||
addMessage({
|
addMessage({
|
||||||
@@ -140,7 +140,7 @@ export default function ChatInterface({ sessionId }: ChatInterfaceProps) {
|
|||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSend}
|
onClick={handleSend}
|
||||||
disabled={status != "ready" || !input.trim()}
|
disabled={status != "ready" || !input.trim() || sessionId == undefined}
|
||||||
>
|
>
|
||||||
Send
|
Send
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { auth } from '@clerk/nextjs/server'
|
|
||||||
import { publicProcedure, router } from "../trpc";
|
import { publicProcedure, router } from "../trpc";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { db } from '~/server/db'
|
import { db } from '~/server/db'
|
||||||
@@ -7,27 +6,29 @@ chatSession, systemSettings } from "../dbschema/schema";
|
|||||||
import { isAdmin } from '~/app/actions';
|
import { isAdmin } from '~/app/actions';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { clerkClient, auth } from '@clerk/nextjs/server'
|
||||||
export const chatRouter = router({
|
export const chatRouter = router({
|
||||||
getSession: publicProcedure.query(async () => {
|
getSession: publicProcedure.query(async () => {
|
||||||
|
const clerk = await clerkClient()
|
||||||
const { userId } = await auth();
|
const { userId } = await auth();
|
||||||
if (userId == null) {
|
const user = await clerk.users.getUser(userId?userId:"")
|
||||||
|
if (user == undefined) {
|
||||||
throw new TRPCError({ message: "chat is only available to signed in users", code: 'UNAUTHORIZED' });
|
throw new TRPCError({ message: "chat is only available to signed in users", code: 'UNAUTHORIZED' });
|
||||||
}
|
}
|
||||||
let session = await db.query.chatSession.findFirst({
|
let session = await db.query.chatSession.findFirst({
|
||||||
where(fields, operators) {
|
where(fields, operators) {
|
||||||
return operators.eq(fields.userId, userId)
|
return operators.eq(fields.userId, user.id)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (session !== undefined) {
|
if (session !== undefined) {
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
let newSession = await db.insert(chatSession).values({ userId: userId }).returning().execute().then((r) => r.at(0));
|
let newSession = await db.insert(chatSession).values({ userId: user.id}).returning().execute().then((r) => r.at(0)); if (newSession == undefined) {
|
||||||
if (newSession == undefined) {
|
|
||||||
throw new TRPCError({ message: "failed to create session", code: "INTERNAL_SERVER_ERROR" });
|
throw new TRPCError({ message: "failed to create session", code: "INTERNAL_SERVER_ERROR" });
|
||||||
}
|
}
|
||||||
session = await db.query.chatSession.findFirst({
|
session = await db.query.chatSession.findFirst({
|
||||||
where(fields, operators) {
|
where(fields, operators) {
|
||||||
return operators.eq(fields.userId, userId)
|
return operators.eq(fields.userId, user.id)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (session == undefined) {
|
if (session == undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user