课程调整
背景
- 课程前端主体内容已经完成,剩下的是一些偏后台和运维的内容
- 我们将通过实战课程来逐渐覆盖还没有涉及的技术栈
- 课程纯 AI 和操作性的内容会逐渐剪辑,通过免费分享的方式上线,主要同步到 Youtube(https://www.youtube.com/playlist?list=PL9uKO-yHg5lkdagg9cD6356dC38QYjoz2)
变更
- 打算提升每节课的信息密度
- 降低每周课程更新的频次
- 课程会增加更多有意思的与时俱进的内容
- 课程的生命周期会增长
本课计划
- 本地启动项目
- 使用 Cursor 解读代码
项目分析
-
替换 API 为 DeepSeek、豆包各模型
- 工具库:https://sdk.vercel.ai/
- 代码路径:lib/ai/models.ts
- 模型的选择:https://sdk.vercel.ai/docs/foundations/providers-and-models
-
基础知识快速 Go Through
- Next.js
- React.js
- React Server Components
- NextAuth.js 认证系统
- PostgreSQL 和 Mysql
- Drizzle ORM
- WebSocket
- AI SDK
- 了解 AI SDK 的 Provider 接口
- 学习不同 AI 服务商的 API 集成方式
- 了解流式响应处理
-
第三方服务
- NextAuth.js:https://next-auth.js.org/
- Google/GitHub 登录
- Neon 的多环境配置和切换
- Vercel Blob 的配置
- NextAuth.js:https://next-auth.js.org/
-
UI 组件库
- Radix UI:基础组件库
- Tailwind CSS:样式系统
- Framer Motion:动画效果
- shadcn/ui:UI 组件集合
-
AI Chat 技术栈分析
让我帮你分析这个基于 Next.js 的 AI 聊天项目。
1. 核心功能
- AI 聊天功能
- 支持多种 AI 模型切换 (OpenAI、Anthropic、Fireworks 等)
- 实时流式对话响应
- 支持代码、文本、图片等多种内容类型
- 聊天历史记录保存
- 用户系统
- 基于 NextAuth.js 的邮箱密码登录
- 用户会话管理
- 聊天记录与用户关联
- Artifacts 工作区
# Artifacts Artifacts is a special user interface mode that allows you to have a workspace like interface along with the chat interface. This is similar to [ChatGPT's Canvas](<https://openai.com/index/introducing-canvas>) and [Claude's Artifacts](<https://www.anthropic.com/news/artifacts>). The template already ships with the following artifacts: - **Text Artifact**: A artifact that allows you to work with text content like drafting essays and emails. - **Code Artifact**: A artifact that allows you to write and execute code (Python). - **Image Artifact**: A artifact that allows you to work with images like editing, annotating, and processing images. - **Sheet Artifact**: A artifact that allows you to work with tabular data like creating, editing, and analyzing data.- 文本编辑器
- 代码编辑器(支持 Python)
- 图片生成和编辑
- 表格数据处理
- UI/UX 特性
- 响应式设计
- 深色/浅色主题切换
- 可折叠侧边栏
- Toast 通知系统
2. 二次开发建议
- 技术栈学习
- Next.js App Router 和 React Server Components
- TypeScript
- NextAuth.js 认证系统
- Drizzle ORM
- Tailwind CSS
- AI SDK
- 替换 Model Provider
import { openai } from '@ai-sdk/openai'; import { fireworks } from '@ai-sdk/fireworks'; import { customProvider, extractReasoningMiddleware, wrapLanguageModel, } from 'ai'; export const DEFAULT_CHAT_MODEL: string = 'chat-model-small'; export const myProvider = customProvider({ languageModels: { 'chat-model-small': openai('gpt-4o-mini'), 'chat-model-large': openai('gpt-4o'), 'chat-model-reasoning': wrapLanguageModel({ model: fireworks('accounts/fireworks/models/deepseek-r1'), middleware: extractReasoningMiddleware({ tagName: 'think' }), }), 'title-model': openai('gpt-4-turbo'), 'artifact-model': openai('gpt-4o-mini'), }, imageModels: { 'small-model': openai.image('dall-e-2'), 'large-model': openai.image('dall-e-3'), }, });- 了解 AI SDK 的 Provider 接口
- 学习不同 AI 服务商的 API 集成方式
- 了解流式响应处理
- 扩展登录方式
import { compare } from 'bcrypt-ts'; import NextAuth, { type User, type Session } from 'next-auth'; import Credentials from 'next-auth/providers/credentials'; import { getUser } from '@/lib/db/queries'; import { authConfig } from './auth.config'; interface ExtendedSession extends Session { user: User; } export const { handlers: { GET, POST }, auth, signIn, signOut, } = NextAuth({ ...authConfig, providers: [ Credentials({ credentials: {}, async authorize({ email, password }: any) { const users = await getUser(email); if (users.length === 0) return null; // biome-ignore lint: Forbidden non-null assertion. const passwordsMatch = await compare(password, users[0].password!); if (!passwordsMatch) return null; return users[0] as any; }, }), ], callbacks: { async jwt({ token, user }) { if (user) { token.id = user.id; } return token; }, async session({ session, token, }: { session: ExtendedSession; token: any; }) { if (session.user) { session.user.id = token.id as string; } return session; }, }, });- 学习 NextAuth.js 的 Provider 配置
- OAuth 集成(Google、GitHub 等)
- 了解 JWT 和 Session 管理
- 用户权限管理
- 设计权限模型和数据库 Schema
- 了解 Next.js 中间件机制
import NextAuth from 'next-auth'; import { authConfig } from '@/app/(auth)/auth.config'; export default NextAuth(authConfig).auth; export const config = { matcher: ['/', '/:id', '/api/:path*', '/login', '/register'], };- 实现 RBAC (基于角色的访问控制)
- API 路由权限控制
- 数据库扩展
import type { InferSelectModel } from 'drizzle-orm'; import { pgTable, varchar, timestamp, json, uuid, text, primaryKey, foreignKey, boolean, } from 'drizzle-orm/pg-core'; export const user = pgTable('User', { id: uuid('id').primaryKey().notNull().defaultRandom(), email: varchar('email', { length: 64 }).notNull(), password: varchar('password', { length: 64 }), }); export type User = InferSelectModel<typeof user>;- Drizzle ORM 的高级用法
- 数据库关系设计
- 数据迁移管理
从 Vue/Nuxt 转到 React/Next.js,主要需要注意:
- React 的组件生命周期和 Hooks 概念
- Next.js 的服务端渲染方式与 Nuxt 的区别
- React 的状态管理方案(Context, Redux 等)
- TypeScript 在 React 项目中的应用
这个项目是一个很好的学习资源,建议你先熟悉基础架构,然后逐步进行功能扩展。
-
AI Chat 功能模块分析
让我帮你分析这个项目的主要功能模块:
1. 核心聊天功能
- Chat 组件:负责主要的聊天界面和交互
export function Chat({ id, initialMessages, selectedChatModel, selectedVisibilityType, isReadonly, }: { id: string; initialMessages: Array<Message>; selectedChatModel: string; selectedVisibilityType: VisibilityType; isReadonly: boolean; }) { const { mutate } = useSWRConfig(); const { messages, setMessages, handleSubmit, input, setInput, append, isLoading, stop, reload, } = useChat({ id, body: { id, selectedChatModel: selectedChatModel }, initialMessages, experimental_throttle: 100, sendExtraMessageFields: true, generateId: generateUUID, onFinish: () => { mutate('/api/history'); }, onError: (error) => { toast.error('An error occured, please try again!'); }, }); const { data: votes } = useSWR<Array<Vote>>( `/api/vote?chatId=${id}`, fetcher, ); const [attachments, setAttachments] = useState<Array<Attachment>>([]); const isArtifactVisible = useArtifactSelector((state) => state.isVisible); return ( <> <div className="flex flex-col min-w-0 h-dvh bg-background"> <ChatHeader chatId={id} selectedModelId={selectedChatModel} selectedVisibilityType={selectedVisibilityType} isReadonly={isReadonly} /> <Messages chatId={id} isLoading={isLoading} votes={votes} messages={messages} setMessages={setMessages} reload={reload} isReadonly={isReadonly} isArtifactVisible={isArtifactVisible} /> <form className="flex mx-auto px-4 bg-background pb-4 md:pb-6 gap-2 w-full md:max-w-3xl"> {!isReadonly && ( <MultimodalInput chatId={id} input={input} setInput={setInput} handleSubmit={handleSubmit} isLoading={isLoading} stop={stop} attachments={attachments} setAttachments={setAttachments} messages={messages} setMessages={setMessages} append={append} /> )} </form> </div> <Artifact chatId={id} input={input} setInput={setInput} handleSubmit={handleSubmit} isLoading={isLoading} stop={stop} attachments={attachments} setAttachments={setAttachments} append={append} messages={messages} setMessages={setMessages} reload={reload} votes={votes} isReadonly={isReadonly} /> </> ); }- AI 模型集成:支持多个 AI 提供商的语言和图像模型
export const myProvider = customProvider({ languageModels: { 'chat-model-small': openai('gpt-4o-mini'), 'chat-model-large': openai('gpt-4o'), 'chat-model-reasoning': wrapLanguageModel({ model: fireworks('accounts/fireworks/models/deepseek-r1'), middleware: extractReasoningMiddleware({ tagName: 'think' }), }), 'title-model': openai('gpt-4-turbo'), 'artifact-model': openai('gpt-4o-mini'), }, imageModels: { 'small-model': openai.image('dall-e-2'), 'large-model': openai.image('dall-e-3'), }, });2. Artifacts 工作区系统
这是一个独特的功能,提供了类似 ChatGPT 的 Canvas 功能,包含四种主要类型:
- 文本编辑器 (Text Artifact)
export const textDocumentHandler = createDocumentHandler<'text'>({ kind: 'text', onCreateDocument: async ({ title, dataStream }) => { let draftContent = ''; const { fullStream } = streamText({ model: myProvider.languageModel('artifact-model'), system: 'Write about the given topic. Markdown is supported. Use headings wherever appropriate.', experimental_transform: smoothStream({ chunking: 'word' }), prompt: title, }); for await (const delta of fullStream) { const { type } = delta; if (type === 'text-delta') { const { textDelta } = delta; draftContent += textDelta; dataStream.writeData({ type: 'text-delta', content: textDelta, }); } } return draftContent; }, onUpdateDocument: async ({ document, description, dataStream }) => { let draftContent = ''; const { fullStream } = streamText({ model: myProvider.languageModel('artifact-model'), system: updateDocumentPrompt(document.content, 'text'), experimental_transform: smoothStream({ chunking: 'word' }), prompt: description, experimental_providerMetadata: { openai: { prediction: { type: 'content', content: document.content, }, }, }, }); for await (const delta of fullStream) { const { type } = delta; if (type === 'text-delta') { const { textDelta } = delta; draftContent += textDelta; dataStream.writeData({ type: 'text-delta', content: textDelta, }); } } return draftContent; }, });- 代码编辑器 (Code Artifact)
- 支持 Python 代码编写和执行
- 使用 CodeMirror 作为编辑器
- 图像生成器 (Image Artifact)
export const imageDocumentHandler = createDocumentHandler<'image'>({ kind: 'image', onCreateDocument: async ({ title, dataStream }) => { let draftContent = ''; const { image } = await experimental_generateImage({ model: myProvider.imageModel('small-model'), prompt: title, n: 1, }); draftContent = image.base64; dataStream.writeData({ type: 'image-delta', content: image.base64, }); return draftContent; }, onUpdateDocument: async ({ description, dataStream }) => { let draftContent = ''; const { image } = await experimental_generateImage({ model: myProvider.imageModel('small-model'), prompt: description, n: 1, }); draftContent = image.base64; dataStream.writeData({ type: 'image-delta', content: image.base64, }); return draftContent; }, });- 表格处理器 (Sheet Artifact)
- 使用 react-data-grid 处理表格数据
3. 认证系统
基于 NextAuth.js 的认证系统,目前支持:
- 邮箱密码登录
- 会话管理
- 访问控制
4. 数据持久化
使用 Vercel 的存储解决方案:
- Vercel Postgres:存储聊天历史和用户数据
- Vercel Blob:文件存储
- Drizzle ORM:数据库操作
5. UI 组件系统
- Radix UI:基础组件库
- Tailwind CSS:样式系统
- Framer Motion:动画效果
- shadcn/ui:UI 组件集合
6. 开发工具链
"dev": "next dev --turbo", "build": "tsx lib/db/migrate && next build", "start": "next start", "lint": "next lint && biome lint --write --unsafe", "lint:fix": "next lint --fix && biome lint --write --unsafe", "format": "biome format --write", "db:generate": "drizzle-kit generate", "db:migrate": "npx tsx lib/db/migrate.ts", "db:studio": "drizzle-kit studio", "db:push": "drizzle-kit push", "db:pull": "drizzle-kit pull", "db:check": "drizzle-kit check", "db:up": "drizzle-kit up" },包含完整的开发工具链:
- TypeScript 支持
- ESLint + Biome 代码检查
- 数据库迁移工具
- 开发服务器配置
7. 实时数据流处理
- 支持流式响应
- 实时内容更新
- WebSocket 通信
8. 文档版本控制
const [mode, setMode] = useState<'edit' | 'diff'>('edit'); const [document, setDocument] = useState<Document | null>(null); const [currentVersionIndex, setCurrentVersionIndex] = useState(-1);- 支持文档版本历史
- Diff 视图比较
- 版本回滚功能
这个项目的架构设计非常现代化,使用了最新的 Next.js 15 和 React 19 RC 版本,采用了 App Router 和 React Server Components。整体来看,它是一个功能完整的 AI 辅助创作平台,而不仅仅是一个简单的聊天机器人。
在这个项目中,实际上并没有直接使用传统的 WebSocket,而是使用了更现代的流式响应技术。主要通过以下几个关键技术实现实时通信:
1. AI SDK 的流式响应
return createDataStreamResponse({ execute: (dataStream) => { const result = streamText({ model: myProvider.languageModel(selectedChatModel), system: systemPrompt({ selectedChatModel }), messages, maxSteps: 5, experimental_transform: smoothStream({ chunking: 'word' }), experimental_generateMessageId: generateUUID, tools: { getWeather, createDocument: createDocument({ session, dataStream }), updateDocument: updateDocument({ session, dataStream }), requestSuggestions: requestSuggestions({ session, dataStream, }), }, // ... 其他配置 }); result.mergeIntoDataStream(dataStream, { sendReasoning: true, }); } });这里使用了 Vercel 的 AI SDK 提供的流式响应功能,基于:
- Server-Sent Events (SSE)
- ReadableStream API
- Web Streams API
2. 客户端实时数据处理
const { messages, setMessages, handleSubmit, input, setInput, append, isLoading, stop, reload, } = useChat({ id, body: { id, selectedChatModel: selectedChatModel }, initialMessages, experimental_throttle: 100, sendExtraMessageFields: true, generateId: generateUUID, onFinish: () => { mutate('/api/history'); }, onError: (error) => { toast.error('An error occured, please try again!'); }, });使用了 AI SDK 提供的
useChatHook,它内部实现了:- 自动处理流式响应
- 消息状态管理
- 错误处理
- 重试机制
3. DataStream 处理系统
export type DataStreamDelta = | { type: 'text-delta'; content: string; } | { type: 'image-delta'; content: string; } | { type: 'code-delta'; content: string; } | { type: 'sheet-delta'; content: string; }; export function DataStreamHandler({ id }: { id: string }) { useEffect(() => { const eventSource = new EventSource(`/api/chat/stream?id=${id}`); eventSource.onmessage = (event) => { const data = JSON.parse(event.data); // 处理流式数据 }; eventSource.onerror = (error) => { console.error('EventSource failed:', error); eventSource.close(); }; return () => { eventSource.close(); }; }, [id]); }项目实现了自定义的 DataStream 处理系统:
- 使用 EventSource API
- 支持多种数据类型的实时流
- 错误处理和重连机制
4. Artifacts 实时更新
export const textDocumentHandler = createDocumentHandler<'text'>({ onCreateDocument: async ({ title, dataStream }) => { let draftContent = ''; const { fullStream } = streamText({ model: myProvider.languageModel('artifact-model'), experimental_transform: smoothStream({ chunking: 'word' }), prompt: title, }); for await (const delta of fullStream) { if (type === 'text-delta') { dataStream.writeData({ type: 'text-delta', content: textDelta, }); } } // ... } });Artifacts 系统使用了:
- 自定义的流式数据处理
- 实时内容更新机制
- 状态同步系统
5. SWR 用于数据同步
const { data: votes } = useSWR<Array<Vote>>( `/api/vote?chatId=${id}`, fetcher, );使用 SWR 进行:
- 数据缓存
- 自动重新验证
- 实时数据同步
技术栈总结
- 基础设施:
- Server-Sent Events (SSE)
- ReadableStream API
- Web Streams API
- EventSource API
- 框架支持:
- Next.js App Router
- React Server Components
- Edge Runtime
- 数据处理:
- AI SDK 的流式处理
- SWR 的数据同步
- 自定义 DataStream 系统
- 状态管理:
- React Hooks
- SWR Cache
- 客户端状态管理
这种架构相比传统 WebSocket 有几个优势:
- 更适合单向的流式数据传输
- 更好的错误处理和重连机制
- 与 Edge Functions 更好的集成
- 更低的服务器资源消耗
不过如果你需要双向实时通信,可以考虑添加 Socket.io 或 WebSocket 支持。
后续规划
- 替换 API 模型为我们想要的模型,这个优先进行,因为可以马上用到
- Go Through 所有涉及到的新的知识点
- 增加新的登录/注册方式
- 增加用户权限的管理功能
- 后台管理界面
- 用户权限控制
- 扩展新的功能(后续逐渐探索)
课后作业
- 拉取项目源码,本地启动,并配置成功
- 大模型的 API(可选)
- Neon 和 Vercel Blob 的配置
课程讨论与答疑
提问默认仅你和管理员可见;管理员精选后会作为公开讨论展示。