diff --git a/apps/ai/next.config.js b/apps/ai/next.config.js index 2a1040b258..747ded2324 100644 --- a/apps/ai/next.config.js +++ b/apps/ai/next.config.js @@ -5,6 +5,15 @@ plugins.push(withBundleAnalyzer({ enabled: process.env.ANALYZE === "true" })); /** @type {import("next").NextConfig} */ const nextConfig = { + async redirects() { + return [ + { + source: "/", + destination: "https://cal.com/ai", + permanent: true, + }, + ]; + }, i18n: { defaultLocale: "en", locales: ["en"], diff --git a/apps/ai/package.json b/apps/ai/package.json index 6a5de24ec4..5c338be474 100644 --- a/apps/ai/package.json +++ b/apps/ai/package.json @@ -1,6 +1,6 @@ { "name": "@calcom/ai", - "version": "0.1.0", + "version": "1.0.1", "private": true, "author": "Cal.com Inc.", "dependencies": { diff --git a/apps/ai/src/app/api/receive/route.ts b/apps/ai/src/app/api/receive/route.ts index e398bd7006..b66b639bb5 100644 --- a/apps/ai/src/app/api/receive/route.ts +++ b/apps/ai/src/app/api/receive/route.ts @@ -45,6 +45,7 @@ export const POST = async (request: NextRequest) => { select: { email: true, id: true, + timeZone: true, credentials: { select: { appId: true, @@ -55,15 +56,17 @@ export const POST = async (request: NextRequest) => { where: { email: envelope.from }, }); - if (!signature || !user?.email || !user?.id) { + // User is not a cal.com user or is using an unverified email. + if (!signature || !user) { await sendEmail({ + html: `Thanks for your interest in Cal AI! To get started, Make sure you have a cal.com account with this email address.`, subject: `Re: ${body.subject}`, - text: "Sorry, you are not authorized to use this service. Please verify your email address and try again.", - to: user?.email || "", + text: `Thanks for your interest in Cal AI! To get started, Make sure you have a cal.com account with this email address. You can sign up for an account at: https://cal.com/signup`, + to: envelope.from, from: aiEmail, }); - return new NextResponse(); + return new NextResponse("ok"); } const credential = user.credentials.find((c) => c.appId === env.APP_ID)?.key; @@ -93,8 +96,8 @@ export const POST = async (request: NextRequest) => { fetchAvailability({ apiKey, userId: user.id, - dateFrom: now, - dateTo: now, + dateFrom: now(user.timeZone), + dateTo: now(user.timeZone), }), ]); @@ -120,7 +123,7 @@ export const POST = async (request: NextRequest) => { return new NextResponse("Error fetching event types. Please try again.", { status: 400 }); } - const { timeZone, workingHours } = availability; + const { workingHours } = availability; const appHost = getHostFromHeaders(request.headers); @@ -135,7 +138,7 @@ export const POST = async (request: NextRequest) => { user: { email: user.email, eventTypes, - timeZone, + timeZone: user.timeZone, workingHours, }, }), diff --git a/apps/ai/src/tools/createBookingIfAvailable.ts b/apps/ai/src/tools/createBookingIfAvailable.ts index 4e95a7f743..976758b0ea 100644 --- a/apps/ai/src/tools/createBookingIfAvailable.ts +++ b/apps/ai/src/tools/createBookingIfAvailable.ts @@ -52,9 +52,8 @@ const createBooking = async ({ method: "POST", }); - if (response.status === 401) { - throw new Error("Unauthorized"); - } + // Let GPT handle this. This will happen when wrong event type id is used. + // if (response.status === 401) throw new Error("Unauthorized"); const data = await response.json(); diff --git a/apps/ai/src/tools/deleteBooking.ts b/apps/ai/src/tools/deleteBooking.ts index 6fbb590e3c..bcaa3f56cf 100644 --- a/apps/ai/src/tools/deleteBooking.ts +++ b/apps/ai/src/tools/deleteBooking.ts @@ -31,7 +31,8 @@ const cancelBooking = async ({ method: "DELETE", }); - if (response.status === 401) throw new Error("Unauthorized"); + // Let GPT handle this. This will happen when wrong booking id is used. + // if (response.status === 401) throw new Error("Unauthorized"); const data = await response.json(); diff --git a/apps/ai/src/tools/getAvailability.ts b/apps/ai/src/tools/getAvailability.ts index fc56c54982..bd0ebf8788 100644 --- a/apps/ai/src/tools/getAvailability.ts +++ b/apps/ai/src/tools/getAvailability.ts @@ -35,9 +35,7 @@ export const fetchAvailability = async ({ const response = await fetch(url); - if (response.status === 401) { - throw new Error("Unauthorized"); - } + if (response.status === 401) throw new Error("Unauthorized"); const data = await response.json(); diff --git a/apps/ai/src/tools/updateBooking.ts b/apps/ai/src/tools/updateBooking.ts index 658760c567..4aa03044b1 100644 --- a/apps/ai/src/tools/updateBooking.ts +++ b/apps/ai/src/tools/updateBooking.ts @@ -41,7 +41,8 @@ const editBooking = async ({ method: "PATCH", }); - if (response.status === 401) throw new Error("Unauthorized"); + // Let GPT handle this. This will happen when wrong booking id is used. + // if (response.status === 401) throw new Error("Unauthorized"); const data = await response.json(); diff --git a/apps/ai/src/utils/agent.ts b/apps/ai/src/utils/agent.ts index c3389ca6ad..c6ec0dd0ba 100644 --- a/apps/ai/src/utils/agent.ts +++ b/apps/ai/src/utils/agent.ts @@ -44,7 +44,7 @@ const agent = async (input: string, user: User, apiKey: string, userId: number) Sometimes, tools return errors. In this case, try to handle the error intelligently or ask the user for more information. Tools will always handle times in UTC, but times sent to the user should be formatted per that user's timezone. - Current UTC time is: ${now} + The current time in the user's timezone is: ${now(user.timeZone)} The user's time zone is: ${user.timeZone} The user's event types are: ${user.eventTypes .map((e: EventType) => `ID: ${e.id}, Title: ${e.title}, Length: ${e.length}`) diff --git a/apps/ai/src/utils/now.ts b/apps/ai/src/utils/now.ts index a1d76cdce6..fc77993ca0 100644 --- a/apps/ai/src/utils/now.ts +++ b/apps/ai/src/utils/now.ts @@ -1 +1,5 @@ -export default new Date().toISOString(); +export default function now(timeZone: string) { + return new Date().toLocaleString("en-US", { + timeZone, + }); +} diff --git a/apps/web/components/getting-started/steps-views/UserProfile.tsx b/apps/web/components/getting-started/steps-views/UserProfile.tsx index d1b1fa1d65..aae5e10f7d 100644 --- a/apps/web/components/getting-started/steps-views/UserProfile.tsx +++ b/apps/web/components/getting-started/steps-views/UserProfile.tsx @@ -98,14 +98,7 @@ const UserProfile = () => { return (