展示 NextJS + AI Copilot 集成的完整应用开发流程,包括架构设计和工程实践。前端程序员的参考案例。
读完本文,你将学会如何:
通过使用 Cal.com 构建一个日程安排应用,将 AI Copilot 集成到你的 Next.js 应用中。
通过使用 Cal.com 构建一个日程安排应用,将 AI Copilot 集成到你的 Next.js 应用中。
开发和管理自定义日程安排器,改善整个应用中的用户体验。
开发和管理自定义日程安排器,改善整个应用中的用户体验。
此外,你还将拥有一个很酷的项目,可以放进自己的作品集中展示!
AI Copilot 是一种应用内 AI 助手,可以帮助用户解答问题,并在应用内部执行操作。它将 LLM 的智能直接引入你的应用。
以下是 AI Copilot 的一些潜在使用场景:
ChatBot:应用中的上下文感知型消息交互功能,可以帮助用户解答疑问,并在应用内执行一些特定操作。
AI Autocomplete:智能输入控件,可在用户输入消息时根据上下文提供相关建议。
CoAgents:能够直接与你的应用及用户协同工作的人工智能助手,可以自主执行复杂任务。
CopilotKit 是领先、最可靠且最易用的开源框架,可用于构建应用内 AI Copilot。只需几分钟,你就能让一个完全自定义的 AI Copilot 在应用中运行起来。
查看 CopilotKit ⭐️
要跟随本教程进行操作,你需要具备以下条件:
掌握 Next.js 和 Typescript。
你的计算机上已安装 NPM 和 Node.js。
拥有 CopilotKit 账户。CopilotKit 是一个开源 Copilot 框架,可用于构建自定义 AI 聊天机器人、应用内 AI 智能体和文本区域。
拥有 Cal.com 账户。如果还没有,请按照本指南创建一个。
以下是本教程将要构建的应用演示:
Next.js 是创建可扩展、高性能 Web 应用时使用最广泛的框架之一。它以 React 的核心功能为基础,提供服务端渲染、静态站点生成和更简单的路由接口,有助于构建速度快、适合生产环境且具备良好 SEO 表现的网站。
为了让我们能够专注于学习如何将 Cal.com 和 Copilot 集成到你的 Next.js 房间预订应用中,我已经为该应用创建好了组件和 UI 界面。运行以下命令克隆并启动应用:
git clone https://github.com/icode247/copilot-booking-app
&& cd copilot-booking-app && npm install && npm run dev
现在来定义这些路由。在这些路由中,我们将向 Cal.com APU 发起 API 请求,以创建新预订或取消预订。在你的 API 文件夹中,新建 bookings/route.ts 文件并添加以下代码:
import { NextRequest, NextResponse } from 'next/server';
import axios from 'axios';
export async function POST(request: NextRequest) {
const { room, start, end, time, email } = await request.json();
try {
const [startDate] = start.split("T");
const startDateTime = new Date(`${startDate}T${time}:00`);
const formattedStart = startDateTime.toISOString();
const endDateTime = new Date(startDateTime);
endDateTime.setHours(endDateTime.getHours() + 1);
const formattedEnd = endDateTime.toISOString();
// Step 1: Create event-type
const eventTypePayload = {
length: 60,
slug: `booking-${Date.now()}-${room.toLowerCase().replace(/\s+/g, "-")}`,
title: `Booking for ${room}`,
description: `Booking for ${room} from ${formattedStart} to ${formattedEnd}`,
locations: [{ type: "inPerson", address: room }],
disableGuests: false,
slotInterval: 0,
minimumBookingNotice: 0,
beforeEventBuffer: 0,
afterEventBuffer: 0,
};
const eventTypeResponse = await axios.post(
`${CALCOM_API_BASE_URL}/event-types`,
eventTypePayload,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_CALCOM_API_KEY}`,
},
}
);
const eventTypeId = eventTypeResponse.data.data.id;
// Step 2: Create booking
const bookingPayload = {
end: formattedEnd,
start: formattedStart,
eventTypeId,
eventTypeSlug: eventTypePayload.slug,
timeZone: "Africa/Lagos",
user: [email],
language: "en",
bookingUid: `booking-${Date.now()}`,
metadata: {},
responses: {
name: email.split("@")[0],
email,
guests: [],
notes: `Booking for ${room} from ${formattedStart} to ${formattedEnd}`,
},
};
const bookingResponse = await axios.post(
`${process.env.CALCOM_API_BASE_URL}/bookings`,
bookingPayload,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_CALCOM_API_KEY}`,
},
}
);
return NextResponse.json({ booking: bookingResponse.data }, { status: 201 });
} catch (error) {
console.error("Error response status:", error.response?.status);
return NextResponse.json(
{
error: "Failed to create booking",
details: error.response?.data || error.message,
},
{ status: 500 }
);
}
}
上述代码会根据预订详情在 Cal.com 中创建一个事件类型,其中包含房间和时间信息。然后,它会使用新创建的事件类型 ID,继续在 Cal.com 上创建实际预订。代码负责处理日期格式、构造两次 API 调用所需的请求负载,并使用 axios 向 Cal.com API 发送请求。
新建 cancel/route.ts 文件并添加以下代码:
import { NextRequest, NextResponse } from "next/server";
import axios from "axios";
export async function POST(
request: NextRequest,
{ params }: { params: { id: string } }
) {
try {
const body = await request.json();
const bookingId = params.id;
const cancelledBookingResponse = await axios.post(
`${process.env.CALCOM_API_BASE_URL}/bookings/${bookingId}/cancel`,
body,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_CALCOM_API_KEY}`,
},
}
);
return NextResponse.json(
{ booking: cancelledBookingResponse.data },
{ status: 201 }
);
} catch (error) {
console.error("Error cancelling booking:", error);
return NextResponse.json(
{ error: "Failed to cancel booking" },
{ status: 500 }
);
}
}
上述代码使用 Cal.com API 实现了一个用于取消预订的 API 路由处理程序。
现在更新你的 app/page.tsx 文件,以使用我们创建的 RoomBookingProvider:
// app/page.tsx
'use client';
import Layout from "@/components/Layout";
import RoomBookingCard from "@/components/RoomBookingCard";
import { RoomBookingProvider } from "@/lib/hooks/use-room-booking";
export default function Home() {
return (
<RoomBookingProvider>
<Layout>
<RoomBookingCard />
</Layout>
</RoomBookingProvider>
);
}
然后,更新你的 RoomBookingCard.tsx 文件,使用 useRoomBooking Hook,让用户能够预订房间。
// components/RoomBookingCard.tsx
"use client";
import { FC, useEffect, useState } from "react";
import RoomList from "./RoomList";
import Notification from "./Notification";
import BookingForm from "./BookingForm";
import { useRoomBooking } from "@/lib/hooks/use-room-booking";
const RoomBookingCard: FC = () => {
const [selectedRoom, setSelectedRoom] = useState<string | null>(null);
const [notification, setNotification] = useState<string | null>(null);
const [rooms, setRooms] = useState([]);
const { addBooking } = useRoomBooking();
useEffect(() => {
async function fetchRooms() {
const response = await fetch("/api/rooms");
const data = await response.json();
setRooms(data);
}
fetchRooms();
}, []);
const handleRoomSelect = (room: string) => {
setSelectedRoom(room);
};
const handleBookingConfirm = async (
sdate: string,
time: string,
edate: string,
email: string
) => {
try {
if (selectedRoom) {
await addBooking(selectedRoom, sdate, time, edate, email);
setNotification("Booking confirmed!");
setSelectedRoom(null);
}
} catch (error) {
setNotification(error.message);
}
};
return (
<div>
{notification && (
<Notification
message={notification}
onClose={() => setNotification(null)}
/>
)}
{selectedRoom ? (
<BookingForm room={selectedRoom} onConfirm={handleBookingConfirm} />
) : (
<RoomList rooms={rooms} onSelectRoom={handleRoomSelect} />
)}
</div>
);
};
export default RoomBookingCard;
现在,你可以选择任意房间、输入详细信息并完成预订。
现在让我们通过集成 CopilotKit 来为应用添加 AI 副驾驶功能。首先,访问 OpenAI 开发者平台并创建一个新的密钥。
Copilotkit 提供两种集成选项:
在本教程中,我们将使用 Copilot Cloud。点击这里免费获取你的 Copilot Cloud API 密钥,然后用你的实际 OpenAI 密钥替换 <your-public-api-key> 来生成 Copilot 公钥。
将你的 API 密钥安全地添加到 .env.local 文件中:
PUBLIC_API_KEY=<your-public-api-key>
更新你的 app/page.tsx 文件,在应用中包装 <CopilotKit> 提供者:
// app/page.tsx
"use client";
import Layout from "@/components/Layout";
import RoomBookingCard from "@/components/RoomBookingCard";
import { RoomBookingProvider } from "@/lib/hooks/use-room-booking";
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotPopup } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";
export default function Home() {
return (
<CopilotKit publicApiKey={process.env.PUBLIC_API_KEY}>
<RoomBookingProvider>
<Layout>
<RoomBookingCard />
</Layout>
</RoomBookingProvider>
<CopilotPopup />
</CopilotKit>
);
}
在上述代码中,我们从 @copilotkit/react-ui 导入了 <CopilotPopup /> 组件和 <CopilotKit> 提供者,同时导入了该包的可选内置样式来增强 UI。
现在你会在页面的右下角看到聊天弹窗。
为了让 Copilot 提供正确的答案并执行任务,我们需要使用 useCopilotReadable 钩子让它了解我们应用的状态。更新你的 lib/hooks/use-room-booking.tsx 文件,为 Copilot 提供预订和房间的状态:
// ...
import { useCopilotReadable } from "@copilotkit/react-core";
// ...
export function RoomBookingProvider({ children }: { children: ReactNode }) {
// ...
const [rooms, setRooms] = useState([]);
// ...
useCopilotReadable({
description: "The state of the booking list",
value: JSON.stringify(bookings),
});
useCopilotReadable({
description: "The state of the rooms list",
value: JSON.stringify(rooms),
});
//...
}
现在你可以通过询问有多少个预订来测试 Copilot。
让我们启用 Copilot 执行更多任务,例如创建预订、取消预订以及获取有关可用房间的信息。为此,我们将使用 Copilot 的 useCopilotAction 钩子。该钩子允许你为 Copilot 提供可执行的操作。
更新你的 lib/hooks/use-room-booking.tsx 文件并添加以下操作:
// ...
export function RoomBookingProvider({ children }: { children: ReactNode }) {
// ...
useCopilotAction({
name: "addBooking",
description: "Adds a booking to the list",
parameters: [
{
name: "room",
type: "string",
description: "The room to be booked",
required: true,
},
{
name: "date",
type: "string",
description: "The date of the booking",
required: true,
},
{
name: "time",
type: "string",
description: "The time of the booking",
required: true,
},
{
name: "end",
type: "string",
description: "The checkout time for booking",
required: true,
},
{
name: "email",
type: "string",
description: "Email address of the user booking the room",
required: true,
},
],
handler: async ({ room, date, time, end, email }) => {
await addBooking(room, date, time, end, email);
},
});
useCopilotAction({
name: "cancelBooking",
description: "Cancels a booking from the list",
parameters: [
{ name: "room", type: "string", description: "The room of the booking to be cancelled", required: true },
{ name: "date", type: "string", description: "The date of the booking to be cancelled", required: true },
{ name: "reason", type: "string", description: "The reason for cancellation", required: true },
],
handler: async ({ room, date, reason }) => {
await cancelBooking(room, date, reason);
},
});
useCopilotAction({
name: "fetchAvailableRooms",
description: "Fetches available rooms for a given date",
parameters: [
{
name: "date",
type: "string",
description: "The date to check room availability",
required: true,
},
],
handler: async ({ date }) => {
const availableRooms = await fetchAvailableRooms(date);
setRooms(availableRooms);
},
});
useCopilotAction({
name: "setBookingStatus",
description: "Sets the status of a booking",
parameters: [
{
name: "id",
type: "number",
description: "The ID of the booking",
required: true,
},
{
name: "status",
type: "string",
description: "The status of the booking",
enum: Object.values(BookingStatus),
required: true,
},
],
handler: ({ id, status }) => {
setBookingStatus(id, status);
},
});
//...
}
在上述代码片段中,我们使用 useCopilotAction 钩子创建了多个操作:addBooking、cancelBooking、fetchAvailableRooms 和 setBookingStatus。每个操作都接受一个包含以下属性的对象。
name 代表操作的名称。
description 指操作的描述。这非常重要,因为它能让我们的 Copilot 选择正确的操作。
parameters 是操作接受的参数集合,是一个数组。它符合 JSON Schema 格式。
handler 是一个简单的函数,在操作执行时会被调用。
现在你可以使用 Copilot 执行高级任务,如查看可用房间列表、预订和取消预订。欢迎与 Copilot 聊天来执行其他操作。
很好,现在你已经拥有了一个 AI 驱动的日程安排应用,可以添加到你的作品集中。
CopilotKit 是一个创新且便捷的工具,用于为你的产品添加 AI 能力。无论是创建语音交互系统还是为复杂流程部署自动化,其灵活性都能满足任何想要将 AI 融入其工作的软件开发者的需求。
如果你正在开发强调 AI 功能的产品,或者在寻找为现有应用添加 AI 的方式,那么你一定应该考虑使用 CopilotKit。界面简洁易用,配置快速,这意味着更少的开发时间和更高的全局效率。
你对 CopilotKit 这样的工具的好奇心帮助你紧跟快速变化的软件行业。
加入 CopilotKit 的开发者社区,和我们一起构建!
别忘了检查我们的 GitHub,并通过给我们一个星标来表达你的支持 ⭐️
如需更多操作,你可以考虑屏蔽此人和/或举报滥用行为