1332 lines
28 KiB
Markdown
1332 lines
28 KiB
Markdown
# AI Chatbot 开发文档
|
||
|
||
## 目录
|
||
|
||
- [项目概述](#项目概述)
|
||
- [技术栈](#技术栈)
|
||
- [项目结构](#项目结构)
|
||
- [环境配置](#环境配置)
|
||
- [核心功能模块](#核心功能模块)
|
||
- [数据库设计](#数据库设计)
|
||
- [API 路由](#api-路由)
|
||
- [认证系统](#认证系统)
|
||
- [AI 集成](#ai-集成)
|
||
- [Artifact 系统](#artifact-系统)
|
||
- [开发指南](#开发指南)
|
||
- [部署指南](#部署指南)
|
||
- [系统设置和管理员功能](#系统设置和管理员功能)
|
||
- [常见问题](#常见问题)
|
||
|
||
---
|
||
|
||
## 项目概述
|
||
|
||
这是一个基于 Next.js 16 和 AI SDK 构建的现代化 AI 聊天机器人应用。项目提供了完整的聊天功能、用户认证、消息持久化、以及多种 AI 工具集成(文档创建、代码编辑、表格处理等)。
|
||
|
||
### 主要特性
|
||
|
||
- ✅ Next.js App Router 架构
|
||
- ✅ React Server Components (RSCs) 和 Server Actions
|
||
- ✅ AI SDK 统一 API,支持多种模型提供商
|
||
- ✅ 完整的用户认证系统(支持注册用户和访客模式)
|
||
- ✅ 消息历史持久化
|
||
- ✅ 多种 Artifact 类型(文本、代码、表格、图片)
|
||
- ✅ 实时流式响应
|
||
- ✅ 可恢复的流式传输(需要 Redis)
|
||
- ✅ 消息投票功能
|
||
- ✅ 文档建议系统
|
||
- ✅ 响应式 UI(基于 shadcn/ui)
|
||
|
||
---
|
||
|
||
## 技术栈
|
||
|
||
### 核心框架
|
||
|
||
- **Next.js 16.0.5** - React 框架,使用 App Router
|
||
- **React 19.0.0-rc** - UI 库
|
||
- **TypeScript 5.6.3** - 类型安全
|
||
|
||
### AI 相关
|
||
|
||
- **AI SDK 5.0.26** - Vercel AI SDK,统一 AI 模型接口
|
||
- **@ai-sdk/gateway** - Vercel AI Gateway,统一访问多个 AI 模型
|
||
- **@ai-sdk/react** - React hooks for AI
|
||
- **tokenlens** - Token 使用量统计和分析
|
||
|
||
### 数据库
|
||
|
||
- **Drizzle ORM 0.34.0** - 类型安全的 ORM
|
||
- **PostgreSQL** - 主数据库(通过 Neon Serverless Postgres)
|
||
- **Redis 5.0.0** - 可恢复流式传输(可选)
|
||
|
||
### 认证
|
||
|
||
- **NextAuth 5.0.0-beta.25** - 认证框架
|
||
- **bcrypt-ts** - 密码加密
|
||
|
||
### UI 组件
|
||
|
||
- **shadcn/ui** - UI 组件库
|
||
- **Radix UI** - 无障碍组件原语
|
||
- **Tailwind CSS 4.1.13** - 样式框架
|
||
- **Framer Motion** - 动画库
|
||
|
||
### 编辑器
|
||
|
||
- **CodeMirror 6** - 代码编辑器
|
||
- **ProseMirror** - 富文本编辑器
|
||
- **react-data-grid** - 表格编辑器
|
||
|
||
### 工具库
|
||
|
||
- **Zod** - 模式验证
|
||
- **date-fns** - 日期处理
|
||
- **SWR** - 数据获取和缓存
|
||
- **nanoid** - ID 生成
|
||
|
||
### 开发工具
|
||
|
||
- **Biome** - 代码格式化和 linting
|
||
- **Playwright** - E2E 测试
|
||
- **Drizzle Kit** - 数据库迁移工具
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
ai-chatbot-main/
|
||
├── app/ # Next.js App Router 目录
|
||
│ ├── (auth)/ # 认证相关路由组
|
||
│ │ ├── actions.ts # Server Actions
|
||
│ │ ├── auth.ts # NextAuth 配置
|
||
│ │ ├── auth.config.ts # 认证配置
|
||
│ │ ├── login/ # 登录页面
|
||
│ │ └── register/ # 注册页面
|
||
│ ├── (chat)/ # 聊天相关路由组
|
||
│ │ ├── actions.ts # Server Actions
|
||
│ │ ├── api/ # API 路由
|
||
│ │ │ ├── chat/ # 聊天 API
|
||
│ │ │ ├── document/ # 文档 API
|
||
│ │ │ ├── files/ # 文件 API
|
||
│ │ │ ├── history/ # 历史记录 API
|
||
│ │ │ ├── suggestions/ # 建议 API
|
||
│ │ │ └── vote/ # 投票 API
|
||
│ │ ├── chat/[id]/ # 聊天详情页
|
||
│ │ ├── layout.tsx # 聊天布局
|
||
│ │ └── page.tsx # 聊天首页
|
||
│ ├── layout.tsx # 根布局
|
||
│ └── globals.css # 全局样式
|
||
├── artifacts/ # Artifact 实现
|
||
│ ├── code/ # 代码 Artifact
|
||
│ ├── image/ # 图片 Artifact
|
||
│ ├── sheet/ # 表格 Artifact
|
||
│ └── text/ # 文本 Artifact
|
||
├── components/ # React 组件
|
||
│ ├── elements/ # 消息元素组件
|
||
│ ├── ui/ # shadcn/ui 组件
|
||
│ ├── artifact.tsx # Artifact 容器
|
||
│ ├── chat.tsx # 聊天主组件
|
||
│ ├── messages.tsx # 消息列表
|
||
│ └── ...
|
||
├── hooks/ # React Hooks
|
||
│ ├── use-artifact.ts # Artifact 管理
|
||
│ ├── use-chat-visibility.ts # 聊天可见性
|
||
│ ├── use-messages.tsx # 消息管理
|
||
│ └── ...
|
||
├── lib/ # 工具库
|
||
│ ├── ai/ # AI 相关
|
||
│ │ ├── models.ts # 模型定义
|
||
│ │ ├── providers.ts # 模型提供商
|
||
│ │ ├── prompts.ts # 提示词模板
|
||
│ │ ├── entitlements.ts # 用户权限
|
||
│ │ └── tools/ # AI 工具
|
||
│ ├── db/ # 数据库
|
||
│ │ ├── schema.ts # 数据库模式
|
||
│ │ ├── queries.ts # 数据库查询
|
||
│ │ ├── migrations/ # 数据库迁移
|
||
│ │ └── utils.ts # 数据库工具
|
||
│ ├── artifacts/ # Artifact 服务端逻辑
|
||
│ ├── editor/ # 编辑器配置
|
||
│ ├── errors.ts # 错误处理
|
||
│ ├── types.ts # 类型定义
|
||
│ └── utils.ts # 工具函数
|
||
├── tests/ # 测试文件
|
||
│ ├── e2e/ # E2E 测试
|
||
│ ├── pages/ # 页面对象模型
|
||
│ └── routes/ # API 路由测试
|
||
├── public/ # 静态资源
|
||
├── biome.jsonc # Biome 配置
|
||
├── drizzle.config.ts # Drizzle 配置
|
||
├── next.config.ts # Next.js 配置
|
||
├── package.json # 依赖配置
|
||
└── tsconfig.json # TypeScript 配置
|
||
```
|
||
|
||
---
|
||
|
||
## 环境配置
|
||
|
||
### 必需的环境变量
|
||
|
||
创建 `.env.local` 文件并配置以下变量:
|
||
|
||
```bash
|
||
# 数据库
|
||
POSTGRES_URL=postgresql://user:password@host:port/database
|
||
|
||
# NextAuth
|
||
AUTH_SECRET=your-secret-key-here
|
||
AUTH_URL=http://localhost:3000
|
||
|
||
# AI Gateway (非 Vercel 部署时需要)
|
||
AI_GATEWAY_API_KEY=your-gateway-api-key
|
||
|
||
# Redis (可选,用于可恢复流式传输)
|
||
REDIS_URL=redis://localhost:6379
|
||
|
||
# Vercel Blob (文件存储,可选)
|
||
BLOB_READ_WRITE_TOKEN=your-blob-token
|
||
```
|
||
|
||
### 环境变量说明
|
||
|
||
- **POSTGRES_URL**: PostgreSQL 数据库连接字符串(必需)
|
||
- **AUTH_SECRET**: NextAuth 加密密钥,使用 `openssl rand -base64 32` 生成(必需)
|
||
- **AUTH_URL**: 应用的基础 URL(必需)
|
||
- **AI_GATEWAY_API_KEY**: Vercel AI Gateway API 密钥(非 Vercel 部署时必需)
|
||
- **REDIS_URL**: Redis 连接字符串(可选,用于可恢复流式传输)
|
||
- **BLOB_READ_WRITE_TOKEN**: Vercel Blob 存储令牌(可选)
|
||
|
||
### 安装和运行
|
||
|
||
```bash
|
||
# 安装依赖
|
||
pnpm install
|
||
|
||
# 运行数据库迁移
|
||
pnpm db:migrate
|
||
|
||
# 启动开发服务器
|
||
pnpm dev
|
||
```
|
||
|
||
应用将在 `http://localhost:3000` 运行。
|
||
|
||
---
|
||
|
||
## 核心功能模块
|
||
|
||
### 1. 聊天系统
|
||
|
||
聊天系统是应用的核心,位于 `app/(chat)/` 目录。
|
||
|
||
#### 主要组件
|
||
|
||
- **`components/chat.tsx`**: 聊天主组件,管理消息状态和 UI
|
||
- **`components/messages.tsx`**: 消息列表组件
|
||
- **`components/message.tsx`**: 单条消息组件
|
||
- **`components/multimodal-input.tsx`**: 多模态输入组件(支持文本、文件等)
|
||
|
||
#### 关键功能
|
||
|
||
- 实时流式响应
|
||
- 消息历史持久化
|
||
- 消息投票(点赞/点踩)
|
||
- 消息重新生成
|
||
- 消息编辑
|
||
- 自动滚动到底部
|
||
|
||
### 2. 用户认证
|
||
|
||
认证系统使用 NextAuth 5,支持两种用户类型:
|
||
|
||
- **注册用户**: 通过邮箱和密码注册
|
||
- **访客用户**: 临时用户,无需注册
|
||
|
||
**注意**: 当前版本**没有管理员功能**,所有用户都是普通用户。如需添加管理员功能,需要扩展用户表和认证系统。
|
||
|
||
#### 认证流程
|
||
|
||
1. 用户访问应用
|
||
2. 未登录用户自动创建访客账户
|
||
3. 注册用户通过登录页面登录
|
||
4. 会话信息存储在 JWT 中
|
||
|
||
#### 相关文件
|
||
|
||
- `app/(auth)/auth.ts`: NextAuth 配置
|
||
- `app/(auth)/auth.config.ts`: 认证配置
|
||
- `app/(auth)/login/page.tsx`: 登录页面
|
||
- `app/(auth)/register/page.tsx`: 注册页面
|
||
|
||
### 3. 消息系统
|
||
|
||
消息系统使用新的 `parts` 架构,支持多种内容类型。
|
||
|
||
#### 消息结构
|
||
|
||
```typescript
|
||
type DBMessage = {
|
||
id: string;
|
||
chatId: string;
|
||
role: "user" | "assistant";
|
||
parts: MessagePart[]; // 消息部分数组
|
||
attachments: Attachment[];
|
||
createdAt: Date;
|
||
};
|
||
```
|
||
|
||
#### 消息部分类型
|
||
|
||
- `text`: 文本内容
|
||
- `tool-call`: 工具调用
|
||
- `tool-result`: 工具结果
|
||
- `data`: 自定义数据
|
||
|
||
### 4. Artifact 系统
|
||
|
||
Artifact 是 AI 生成的可编辑文档,支持四种类型:
|
||
|
||
- **text**: 富文本文档
|
||
- **code**: 代码文件
|
||
- **sheet**: 表格数据
|
||
- **image**: 图片生成
|
||
|
||
#### Artifact 架构
|
||
|
||
每个 Artifact 类型包含:
|
||
|
||
1. **客户端组件** (`artifacts/{kind}/client.tsx`): UI 渲染和交互
|
||
2. **服务端处理器** (`artifacts/{kind}/server.ts`): 创建和更新逻辑
|
||
|
||
#### 创建 Artifact
|
||
|
||
```typescript
|
||
// AI 工具调用
|
||
createDocument({
|
||
title: "示例代码",
|
||
kind: "code"
|
||
})
|
||
```
|
||
|
||
#### 更新 Artifact
|
||
|
||
```typescript
|
||
// AI 工具调用
|
||
updateDocument({
|
||
documentId: "...",
|
||
description: "添加错误处理"
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 数据库设计
|
||
|
||
### 表结构
|
||
|
||
#### User 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
email: varchar(64) (唯一)
|
||
password: varchar(64) (可空,访客用户无密码)
|
||
}
|
||
```
|
||
|
||
#### Chat 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
createdAt: timestamp
|
||
title: text
|
||
userId: uuid (外键 -> User.id)
|
||
visibility: "public" | "private"
|
||
lastContext: jsonb (最后的使用统计)
|
||
}
|
||
```
|
||
|
||
#### Message_v2 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
chatId: uuid (外键 -> Chat.id)
|
||
role: "user" | "assistant"
|
||
parts: json (消息部分数组)
|
||
attachments: json (附件数组)
|
||
createdAt: timestamp
|
||
}
|
||
```
|
||
|
||
#### Document 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
createdAt: timestamp (主键的一部分)
|
||
title: text
|
||
content: text (可空)
|
||
kind: "text" | "code" | "image" | "sheet"
|
||
userId: uuid (外键 -> User.id)
|
||
}
|
||
```
|
||
|
||
#### Vote_v2 表
|
||
|
||
```typescript
|
||
{
|
||
chatId: uuid (主键的一部分)
|
||
messageId: uuid (主键的一部分)
|
||
isUpvoted: boolean
|
||
}
|
||
```
|
||
|
||
#### Suggestion 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
documentId: uuid
|
||
documentCreatedAt: timestamp
|
||
originalText: text
|
||
suggestedText: text
|
||
description: text (可空)
|
||
isResolved: boolean
|
||
userId: uuid (外键 -> User.id)
|
||
createdAt: timestamp
|
||
}
|
||
```
|
||
|
||
#### Stream 表
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
chatId: uuid (外键 -> Chat.id)
|
||
createdAt: timestamp
|
||
}
|
||
```
|
||
|
||
### 数据库查询
|
||
|
||
所有数据库查询函数位于 `lib/db/queries.ts`,包括:
|
||
|
||
- `getUser()`: 获取用户
|
||
- `createUser()`: 创建用户
|
||
- `createGuestUser()`: 创建访客用户
|
||
- `saveChat()`: 保存聊天
|
||
- `getChatById()`: 获取聊天
|
||
- `getMessagesByChatId()`: 获取消息列表
|
||
- `saveMessages()`: 保存消息
|
||
- `saveDocument()`: 保存文档
|
||
- `getDocumentById()`: 获取文档
|
||
- 等等...
|
||
|
||
### 数据库迁移
|
||
|
||
使用 Drizzle Kit 管理数据库迁移:
|
||
|
||
```bash
|
||
# 生成迁移文件
|
||
pnpm db:generate
|
||
|
||
# 应用迁移
|
||
pnpm db:migrate
|
||
|
||
# 推送更改(开发环境)
|
||
pnpm db:push
|
||
|
||
# 打开 Drizzle Studio
|
||
pnpm db:studio
|
||
```
|
||
|
||
---
|
||
|
||
## API 路由
|
||
|
||
### 聊天 API
|
||
|
||
**路径**: `/api/chat`
|
||
|
||
#### POST - 发送消息
|
||
|
||
创建新聊天或继续现有聊天。
|
||
|
||
**请求体**:
|
||
```typescript
|
||
{
|
||
id: string; // 聊天 ID
|
||
message: ChatMessage; // 用户消息
|
||
selectedChatModel: string; // 选择的模型 ID
|
||
selectedVisibilityType: "public" | "private";
|
||
}
|
||
```
|
||
|
||
**响应**: Server-Sent Events (SSE) 流
|
||
|
||
**功能**:
|
||
- 验证用户身份
|
||
- 检查速率限制
|
||
- 创建或获取聊天
|
||
- 流式生成 AI 响应
|
||
- 保存消息到数据库
|
||
|
||
#### DELETE - 删除聊天
|
||
|
||
**查询参数**:
|
||
- `id`: 聊天 ID
|
||
|
||
**响应**: 删除的聊天对象
|
||
|
||
### 文档 API
|
||
|
||
**路径**: `/api/document/[id]`
|
||
|
||
#### GET - 获取文档
|
||
|
||
获取指定 ID 的文档。
|
||
|
||
#### POST - 更新文档
|
||
|
||
更新文档内容。
|
||
|
||
### 文件 API
|
||
|
||
**路径**: `/api/files`
|
||
|
||
处理文件上传和存储。
|
||
|
||
### 历史记录 API
|
||
|
||
**路径**: `/api/history`
|
||
|
||
获取用户的聊天历史记录(分页)。
|
||
|
||
### 建议 API
|
||
|
||
**路径**: `/api/suggestions`
|
||
|
||
获取文档的建议列表。
|
||
|
||
### 投票 API
|
||
|
||
**路径**: `/api/vote`
|
||
|
||
对消息进行投票(点赞/点踩)。
|
||
|
||
---
|
||
|
||
## 认证系统
|
||
|
||
### NextAuth 配置
|
||
|
||
认证系统使用 NextAuth 5,配置在 `app/(auth)/auth.ts`。
|
||
|
||
#### 认证提供者
|
||
|
||
1. **Credentials Provider**: 邮箱密码登录
|
||
2. **Guest Provider**: 访客模式(自动创建临时用户)
|
||
|
||
#### 会话结构
|
||
|
||
```typescript
|
||
{
|
||
user: {
|
||
id: string;
|
||
email: string | null;
|
||
type: "guest" | "regular";
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 认证中间件
|
||
|
||
使用 `auth()` 函数获取当前会话:
|
||
|
||
```typescript
|
||
import { auth } from "@/app/(auth)/auth";
|
||
|
||
const session = await auth();
|
||
if (!session?.user) {
|
||
// 未登录
|
||
}
|
||
```
|
||
|
||
### 用户权限
|
||
|
||
用户权限定义在 `lib/ai/entitlements.ts`:
|
||
|
||
```typescript
|
||
export const entitlementsByUserType = {
|
||
guest: {
|
||
maxMessagesPerDay: 10,
|
||
},
|
||
regular: {
|
||
maxMessagesPerDay: 100,
|
||
},
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## AI 集成
|
||
|
||
### 模型提供商
|
||
|
||
项目使用 Vercel AI Gateway 统一访问多个 AI 模型,配置在 `lib/ai/providers.ts`。
|
||
|
||
#### 可用模型
|
||
|
||
- **chat-model**: Grok Vision (xai/grok-2-vision-1212)
|
||
- **chat-model-reasoning**: Grok Reasoning (xai/grok-3-mini)
|
||
- **title-model**: Grok 2 (xai/grok-2-1212)
|
||
- **artifact-model**: Grok 2 (xai/grok-2-1212)
|
||
|
||
#### 切换模型提供商
|
||
|
||
要切换到其他提供商(如 OpenAI),修改 `lib/ai/providers.ts`:
|
||
|
||
```typescript
|
||
import { openai } from "@ai-sdk/openai";
|
||
|
||
export const myProvider = customProvider({
|
||
languageModels: {
|
||
"chat-model": openai("gpt-4"),
|
||
// ...
|
||
},
|
||
});
|
||
```
|
||
|
||
### AI 工具
|
||
|
||
AI 可以调用以下工具:
|
||
|
||
1. **getWeather**: 获取天气信息
|
||
2. **createDocument**: 创建文档(text/code/sheet/image)
|
||
3. **updateDocument**: 更新文档
|
||
4. **requestSuggestions**: 请求文档建议
|
||
|
||
#### 添加新工具
|
||
|
||
1. 在 `lib/ai/tools/` 创建工具文件
|
||
2. 在 `app/(chat)/api/chat/route.ts` 注册工具:
|
||
|
||
```typescript
|
||
tools: {
|
||
// ... 现有工具
|
||
myNewTool: myNewTool({ session, dataStream }),
|
||
}
|
||
```
|
||
|
||
3. 在 `experimental_activeTools` 数组中添加工具名称
|
||
|
||
### 提示词系统
|
||
|
||
系统提示词定义在 `lib/ai/prompts.ts`,包括:
|
||
|
||
- `systemPrompt()`: 主聊天提示词
|
||
- `titlePrompt`: 标题生成提示词
|
||
- `codePrompt`: 代码生成提示词
|
||
- `textPrompt`: 文本生成提示词
|
||
- `sheetPrompt`: 表格生成提示词
|
||
- `updateDocumentPrompt()`: 文档更新提示词
|
||
|
||
### 流式响应
|
||
|
||
使用 AI SDK 的 `streamText()` 和 `createUIMessageStream()` 实现流式响应:
|
||
|
||
```typescript
|
||
const stream = createUIMessageStream({
|
||
execute: ({ writer: dataStream }) => {
|
||
const result = streamText({
|
||
model: myProvider.languageModel(selectedChatModel),
|
||
messages: convertToModelMessages(uiMessages),
|
||
tools: { /* ... */ },
|
||
});
|
||
|
||
dataStream.merge(result.toUIMessageStream());
|
||
},
|
||
onFinish: async ({ messages }) => {
|
||
// 保存消息到数据库
|
||
},
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Artifact 系统
|
||
|
||
### Artifact 类型
|
||
|
||
#### 1. Text Artifact
|
||
|
||
富文本文档,使用 ProseMirror 编辑器。
|
||
|
||
**文件**:
|
||
- `artifacts/text/client.tsx`: 客户端组件
|
||
- `artifacts/text/server.ts`: 服务端处理器
|
||
|
||
**功能**:
|
||
- Markdown 支持
|
||
- 实时编辑
|
||
- 版本历史
|
||
|
||
#### 2. Code Artifact
|
||
|
||
代码文件,使用 CodeMirror 编辑器。
|
||
|
||
**文件**:
|
||
- `artifacts/code/client.tsx`: 客户端组件
|
||
- `artifacts/code/server.ts`: 服务端处理器
|
||
|
||
**功能**:
|
||
- 语法高亮
|
||
- 代码补全
|
||
- 多语言支持(JavaScript、Python 等)
|
||
- 代码执行(通过 Pyodide)
|
||
|
||
#### 3. Sheet Artifact
|
||
|
||
表格数据,使用 react-data-grid。
|
||
|
||
**文件**:
|
||
- `artifacts/sheet/client.tsx`: 客户端组件
|
||
- `artifacts/sheet/server.ts`: 服务端处理器
|
||
|
||
**功能**:
|
||
- CSV 导入/导出
|
||
- 数据格式化
|
||
- 数据清理工具
|
||
|
||
#### 4. Image Artifact
|
||
|
||
图片生成和编辑。
|
||
|
||
**文件**:
|
||
- `artifacts/image/client.tsx`: 客户端组件
|
||
|
||
**功能**:
|
||
- 图片生成
|
||
- 图片编辑
|
||
- 版本历史
|
||
|
||
### 创建自定义 Artifact
|
||
|
||
1. **定义 Artifact 类型**
|
||
|
||
在 `components/artifact.tsx` 中添加类型:
|
||
|
||
```typescript
|
||
export const artifactDefinitions = [
|
||
// ... 现有 Artifact
|
||
myCustomArtifact,
|
||
];
|
||
```
|
||
|
||
2. **创建客户端组件**
|
||
|
||
`artifacts/my-custom/client.tsx`:
|
||
|
||
```typescript
|
||
import { Artifact } from "@/components/create-artifact";
|
||
|
||
export const myCustomArtifact = new Artifact({
|
||
kind: "my-custom",
|
||
description: "我的自定义 Artifact",
|
||
initialize: () => null,
|
||
onStreamPart: ({ setArtifact, streamPart }) => {
|
||
if (streamPart.type === "data-myCustomDelta") {
|
||
setArtifact((draft) => ({
|
||
...draft,
|
||
content: streamPart.data,
|
||
isVisible: true,
|
||
status: "streaming",
|
||
}));
|
||
}
|
||
},
|
||
content: ({ content }) => {
|
||
return <MyCustomEditor content={content} />;
|
||
},
|
||
});
|
||
```
|
||
|
||
3. **创建服务端处理器**
|
||
|
||
`artifacts/my-custom/server.ts`:
|
||
|
||
```typescript
|
||
import { createDocumentHandler } from "@/lib/artifacts/server";
|
||
|
||
export const myCustomDocumentHandler = createDocumentHandler({
|
||
kind: "my-custom",
|
||
onCreateDocument: async ({ title, dataStream }) => {
|
||
// 生成内容逻辑
|
||
// 使用 dataStream.write() 发送增量更新
|
||
return finalContent;
|
||
},
|
||
onUpdateDocument: async ({ document, description, dataStream }) => {
|
||
// 更新内容逻辑
|
||
return updatedContent;
|
||
},
|
||
});
|
||
```
|
||
|
||
4. **注册处理器**
|
||
|
||
在 `lib/artifacts/server.ts` 中注册:
|
||
|
||
```typescript
|
||
export const documentHandlersByArtifactKind = [
|
||
// ... 现有处理器
|
||
myCustomDocumentHandler,
|
||
];
|
||
```
|
||
|
||
5. **更新数据库模式**
|
||
|
||
在 `lib/db/schema.ts` 中更新 `Document.kind` 类型:
|
||
|
||
```typescript
|
||
kind: varchar("text", {
|
||
enum: ["text", "code", "image", "sheet", "my-custom"]
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 开发指南
|
||
|
||
### 代码规范
|
||
|
||
项目使用 Biome 进行代码格式化和 linting,配置继承自 Ultracite。
|
||
|
||
#### 运行检查
|
||
|
||
```bash
|
||
# 检查代码
|
||
pnpm lint
|
||
|
||
# 自动修复
|
||
pnpm format
|
||
```
|
||
|
||
#### 主要规则
|
||
|
||
- 使用 TypeScript 严格模式
|
||
- 遵循 React Hooks 规则
|
||
- 使用函数式组件和 Hooks
|
||
- 避免使用 `any` 类型
|
||
- 使用 Zod 进行数据验证
|
||
- 遵循无障碍性 (a11y) 标准
|
||
|
||
### 添加新功能
|
||
|
||
#### 1. 添加新的 API 路由
|
||
|
||
在 `app/(chat)/api/` 下创建新目录和 `route.ts` 文件:
|
||
|
||
```typescript
|
||
import { auth } from "@/app/(auth)/auth";
|
||
|
||
export async function GET(request: Request) {
|
||
const session = await auth();
|
||
if (!session?.user) {
|
||
return new Response("Unauthorized", { status: 401 });
|
||
}
|
||
|
||
// 处理逻辑
|
||
return Response.json({ data: "..." });
|
||
}
|
||
```
|
||
|
||
#### 2. 添加新的 Server Action
|
||
|
||
在 `app/(chat)/actions.ts` 中添加:
|
||
|
||
```typescript
|
||
"use server";
|
||
|
||
export async function myAction() {
|
||
// 服务端逻辑
|
||
}
|
||
```
|
||
|
||
#### 3. 添加新的 UI 组件
|
||
|
||
在 `components/` 目录下创建组件:
|
||
|
||
```typescript
|
||
"use client";
|
||
|
||
export function MyComponent() {
|
||
return <div>...</div>;
|
||
}
|
||
```
|
||
|
||
### 测试
|
||
|
||
项目使用 Playwright 进行 E2E 测试。
|
||
|
||
#### 运行测试
|
||
|
||
```bash
|
||
pnpm test
|
||
```
|
||
|
||
#### 测试文件结构
|
||
|
||
- `tests/e2e/`: E2E 测试用例
|
||
- `tests/pages/`: 页面对象模型
|
||
- `tests/routes/`: API 路由测试
|
||
|
||
### 调试
|
||
|
||
#### 开发模式
|
||
|
||
```bash
|
||
pnpm dev
|
||
```
|
||
|
||
#### 数据库调试
|
||
|
||
使用 Drizzle Studio:
|
||
|
||
```bash
|
||
pnpm db:studio
|
||
```
|
||
|
||
#### 查看日志
|
||
|
||
- 服务端日志:控制台输出
|
||
- 客户端日志:浏览器控制台
|
||
|
||
---
|
||
|
||
## 部署指南
|
||
|
||
### Vercel 部署
|
||
|
||
1. **连接 GitHub 仓库**
|
||
|
||
在 Vercel 控制台连接你的 GitHub 仓库。
|
||
|
||
2. **配置环境变量**
|
||
|
||
在 Vercel 项目设置中添加环境变量:
|
||
- `POSTGRES_URL`
|
||
- `AUTH_SECRET`
|
||
- `AUTH_URL`
|
||
- `REDIS_URL` (可选)
|
||
- `BLOB_READ_WRITE_TOKEN` (可选)
|
||
|
||
3. **部署**
|
||
|
||
推送代码到 GitHub,Vercel 会自动部署。
|
||
|
||
### 数据库迁移
|
||
|
||
在部署前或部署后运行迁移:
|
||
|
||
```bash
|
||
pnpm db:migrate
|
||
```
|
||
|
||
或在 Vercel 的构建命令中:
|
||
|
||
```json
|
||
{
|
||
"scripts": {
|
||
"build": "tsx lib/db/migrate && next build"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 环境检查清单
|
||
|
||
- [ ] PostgreSQL 数据库已配置
|
||
- [ ] 环境变量已设置
|
||
- [ ] 数据库迁移已运行
|
||
- [ ] AI Gateway API 密钥已配置(如需要)
|
||
- [ ] Redis 已配置(如需要可恢复流式传输)
|
||
|
||
---
|
||
|
||
## 系统设置和管理员功能
|
||
|
||
### 功能概述
|
||
|
||
项目已实现完整的管理员系统设置功能,包括:
|
||
|
||
- ✅ 用户管理(激活/删除/编辑用户)
|
||
- ✅ 网站设置(LOGO、网站名、浏览器图标、主题模式LOGO)
|
||
- ✅ 工具库管理(启用/禁用 AI 工具)
|
||
|
||
### 数据库 Schema
|
||
|
||
#### User 表扩展
|
||
|
||
已为 User 表添加以下字段:
|
||
|
||
```typescript
|
||
{
|
||
role: "guest" | "regular" | "admin" (默认: "regular")
|
||
isActive: boolean (默认: true)
|
||
createdAt: timestamp
|
||
updatedAt: timestamp
|
||
}
|
||
```
|
||
|
||
#### SystemSettings 表
|
||
|
||
用于存储系统配置:
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
key: string (唯一键)
|
||
value: jsonb (配置值)
|
||
updatedAt: timestamp
|
||
updatedBy: uuid (外键 -> User.id)
|
||
}
|
||
```
|
||
|
||
支持的配置键:
|
||
- `siteName`: 网站名称
|
||
- `siteLogo`: 网站 LOGO URL
|
||
- `favicon`: 浏览器图标 URL
|
||
- `logoLight`: 白天模式 LOGO URL
|
||
- `logoDark`: 黑夜模式 LOGO URL
|
||
|
||
#### ToolConfig 表
|
||
|
||
用于管理 AI 工具配置:
|
||
|
||
```typescript
|
||
{
|
||
id: uuid (主键)
|
||
toolName: string (唯一键)
|
||
isEnabled: boolean (是否启用)
|
||
description: string (工具描述)
|
||
config: jsonb (工具配置)
|
||
updatedAt: timestamp
|
||
updatedBy: uuid (外键 -> User.id)
|
||
}
|
||
```
|
||
|
||
### 认证系统
|
||
|
||
#### 用户类型
|
||
|
||
系统支持三种用户类型:
|
||
|
||
- **guest**: 访客用户(临时账户)
|
||
- **regular**: 普通注册用户
|
||
- **admin**: 管理员用户
|
||
|
||
#### 管理员权限
|
||
|
||
管理员拥有以下权限:
|
||
|
||
- 无限消息数量(`maxMessagesPerDay: Infinity`)
|
||
- 访问所有 AI 模型
|
||
- 访问系统设置页面
|
||
- 管理用户账户
|
||
- 配置系统设置
|
||
- 管理 AI 工具
|
||
|
||
### 管理员中间件
|
||
|
||
使用 `lib/middleware/admin.ts` 中的 `requireAdmin()` 函数保护管理员路由:
|
||
|
||
```typescript
|
||
import { requireAdmin } from "@/lib/middleware/admin";
|
||
|
||
export async function GET(request: Request) {
|
||
const session = await requireAdmin();
|
||
// 只有管理员可以访问
|
||
}
|
||
```
|
||
|
||
### API 路由
|
||
|
||
#### 用户管理 API
|
||
|
||
**路径**: `/api/admin/users`
|
||
|
||
- **GET**: 获取用户列表(支持分页)
|
||
- 查询参数: `limit`, `offset`
|
||
- **PATCH**: 更新用户信息
|
||
- 请求体: `{ id, email?, role?, isActive? }`
|
||
- **DELETE**: 删除用户
|
||
- 查询参数: `id`
|
||
|
||
#### 系统设置 API
|
||
|
||
**路径**: `/api/admin/settings`
|
||
|
||
- **GET**: 获取系统设置
|
||
- 查询参数: `key` (可选,获取特定设置)
|
||
- **POST**: 更新系统设置
|
||
- 请求体: `{ key, value }`
|
||
|
||
#### 工具管理 API
|
||
|
||
**路径**: `/api/admin/tools`
|
||
|
||
- **GET**: 获取工具配置列表
|
||
- 查询参数: `toolName` (可选,获取特定工具)
|
||
- **POST**: 更新工具配置
|
||
- 请求体: `{ toolName, isEnabled, description?, config? }`
|
||
|
||
### 系统设置页面
|
||
|
||
**路径**: `/admin/settings`
|
||
|
||
管理员可以通过此页面管理:
|
||
|
||
#### 1. 用户管理
|
||
|
||
- 查看所有用户列表
|
||
- 修改用户角色(guest/regular/admin)
|
||
- 激活/禁用用户账户
|
||
- 删除用户账户
|
||
|
||
#### 2. 网站设置
|
||
|
||
- 设置网站名称
|
||
- 配置网站 LOGO URL
|
||
- 配置浏览器图标(Favicon)URL
|
||
- 配置白天模式 LOGO URL
|
||
- 配置黑夜模式 LOGO URL
|
||
|
||
#### 3. 工具库管理
|
||
|
||
- 查看所有可用 AI 工具
|
||
- 启用/禁用工具
|
||
- 工具状态实时更新
|
||
|
||
### 工具注册系统
|
||
|
||
系统使用 `lib/ai/tools-registry.ts` 管理工具启用状态:
|
||
|
||
```typescript
|
||
import { getEnabledTools } from "@/lib/ai/tools-registry";
|
||
|
||
// 获取启用的工具列表
|
||
const enabledTools = await getEnabledTools();
|
||
// 返回: ["getWeather", "createDocument", ...]
|
||
```
|
||
|
||
聊天 API 会自动根据工具配置决定哪些工具可用。
|
||
|
||
### 数据库迁移
|
||
|
||
运行以下命令创建数据库迁移:
|
||
|
||
```bash
|
||
# 生成迁移文件
|
||
pnpm db:generate
|
||
|
||
# 应用迁移
|
||
pnpm db:migrate
|
||
```
|
||
|
||
### 创建管理员账户
|
||
|
||
要创建管理员账户,可以通过以下方式:
|
||
|
||
1. **通过数据库直接更新**:
|
||
|
||
```sql
|
||
UPDATE "User" SET role = 'admin' WHERE email = 'admin@example.com';
|
||
```
|
||
|
||
2. **通过系统设置页面**:
|
||
|
||
- 以管理员身份登录
|
||
- 访问 `/admin/settings`
|
||
- 在"用户管理"标签页中找到目标用户
|
||
- 将角色修改为"管理员"
|
||
|
||
### 使用示例
|
||
|
||
#### 访问系统设置页面
|
||
|
||
1. 以管理员身份登录
|
||
2. 访问 `http://localhost:3000/admin/settings`
|
||
3. 使用三个标签页管理不同功能
|
||
|
||
#### 更新网站设置
|
||
|
||
```typescript
|
||
// 通过 API
|
||
await fetch("/api/admin/settings", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
key: "siteName",
|
||
value: "我的 AI 聊天机器人",
|
||
}),
|
||
});
|
||
```
|
||
|
||
#### 禁用工具
|
||
|
||
```typescript
|
||
// 通过 API
|
||
await fetch("/api/admin/tools", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
toolName: "getWeather",
|
||
isEnabled: false,
|
||
description: "获取天气信息",
|
||
}),
|
||
});
|
||
```
|
||
|
||
### 安全注意事项
|
||
|
||
- 所有管理员 API 都使用 `requireAdmin()` 中间件保护
|
||
- 只有管理员角色的用户才能访问系统设置页面
|
||
- 用户删除操作需要确认,防止误操作
|
||
- 系统设置更改会记录更新者信息
|
||
|
||
---
|
||
|
||
## 常见问题
|
||
|
||
### 1. 数据库连接失败
|
||
|
||
**问题**: 无法连接到 PostgreSQL 数据库
|
||
|
||
**解决方案**:
|
||
- 检查 `POSTGRES_URL` 环境变量是否正确
|
||
- 确认数据库服务正在运行
|
||
- 检查网络连接和防火墙设置
|
||
|
||
### 2. 认证失败
|
||
|
||
**问题**: 用户无法登录
|
||
|
||
**解决方案**:
|
||
- 检查 `AUTH_SECRET` 是否设置
|
||
- 确认 `AUTH_URL` 与部署 URL 匹配
|
||
- 检查数据库中的用户数据
|
||
|
||
### 3. AI 模型无响应
|
||
|
||
**问题**: AI 模型不返回响应
|
||
|
||
**解决方案**:
|
||
- 检查 AI Gateway API 密钥(非 Vercel 部署)
|
||
- 确认模型 ID 正确
|
||
- 检查网络连接
|
||
- 查看控制台错误日志
|
||
|
||
### 4. 流式传输中断
|
||
|
||
**问题**: 流式响应中途断开
|
||
|
||
**解决方案**:
|
||
- 配置 Redis 以启用可恢复流式传输
|
||
- 检查网络稳定性
|
||
- 增加超时时间设置
|
||
|
||
### 5. Artifact 不显示
|
||
|
||
**问题**: Artifact 创建后不显示
|
||
|
||
**解决方案**:
|
||
- 检查 `dataStream.write()` 调用是否正确
|
||
- 确认 Artifact 类型已注册
|
||
- 查看浏览器控制台错误
|
||
- 检查数据库中的文档记录
|
||
|
||
### 6. 消息不保存
|
||
|
||
**问题**: 消息发送后未保存到数据库
|
||
|
||
**解决方案**:
|
||
- 检查数据库连接
|
||
- 确认 `saveMessages()` 函数被调用
|
||
- 查看服务端日志
|
||
- 检查数据库表结构
|
||
|
||
### 7. 如何添加管理员功能
|
||
|
||
**问题**: 项目没有管理员功能,如何添加?
|
||
|
||
**解决方案**:
|
||
- 参考文档中的"系统设置和管理员功能"章节
|
||
- 扩展数据库 schema 添加角色字段
|
||
- 更新认证系统支持管理员类型
|
||
- 创建管理员中间件和页面
|
||
- 实现管理员专用的 API 路由
|
||
|
||
---
|
||
|
||
## 扩展资源
|
||
|
||
### 官方文档
|
||
|
||
- [Next.js 文档](https://nextjs.org/docs)
|
||
- [AI SDK 文档](https://ai-sdk.dev)
|
||
- [Drizzle ORM 文档](https://orm.drizzle.team)
|
||
- [NextAuth 文档](https://authjs.dev)
|
||
- [shadcn/ui 文档](https://ui.shadcn.com)
|
||
|
||
### 相关链接
|
||
|
||
- [Vercel AI Gateway](https://vercel.com/docs/ai-gateway)
|
||
- [Neon Serverless Postgres](https://neon.tech)
|
||
- [Vercel Blob](https://vercel.com/storage/blob)
|
||
|
||
---
|
||
|
||
## 贡献指南
|
||
|
||
### 代码提交
|
||
|
||
1. 创建功能分支
|
||
2. 编写代码并添加测试
|
||
3. 运行 `pnpm lint` 和 `pnpm format`
|
||
4. 提交 Pull Request
|
||
|
||
### 代码审查
|
||
|
||
- 确保所有测试通过
|
||
- 遵循代码规范
|
||
- 添加必要的文档
|
||
- 更新 CHANGELOG(如适用)
|
||
|
||
---
|
||
|
||
## 许可证
|
||
|
||
查看 `LICENSE` 文件了解许可证信息。
|
||
|
||
---
|
||
|
||
## 更新日志
|
||
|
||
### v3.1.0
|
||
|
||
- 支持多种 Artifact 类型
|
||
- 改进的消息系统(parts 架构)
|
||
- 可恢复流式传输支持
|
||
- 用户权限系统
|
||
- 消息投票功能
|
||
|
||
---
|
||
|
||
**最后更新**: 2024年
|
||
|
||
**维护者**: 项目团队
|
||
|