306 lines
7.6 KiB
Markdown
306 lines
7.6 KiB
Markdown
|
|
# LaodingBot WebUI 开发技术与需求说明
|
|||
|
|
|
|||
|
|
> 版本: v1.0
|
|||
|
|
> 目标读者: 下一个执行 WebUI 开发任务的 LLM / 前端工程师
|
|||
|
|
> 依据: 当前后端已落地代码(`internal/transport/webui/bot.go`、`cmd/bot/main.go`、`internal/agent/orchestrator.go`)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 文档目标与范围
|
|||
|
|
|
|||
|
|
本说明用于指导“仅 WebUI 页面层/前端层”的开发,确保严格对接当前 LaodingBot 已开放的 WebUI 后端能力。
|
|||
|
|
|
|||
|
|
本期范围:
|
|||
|
|
- 支持纯文本对话
|
|||
|
|
- 支持独立文档上传(上传后立即返回 `file_id`)
|
|||
|
|
- 支持“先上传文档,再发送文本提问”的两阶段交互
|
|||
|
|
|
|||
|
|
非本期范围:
|
|||
|
|
- 不改动后端接口语义
|
|||
|
|
- 不引入新的后端路由
|
|||
|
|
- 不实现复杂权限系统(当前后端无鉴权)
|
|||
|
|
- 不实现流式输出(当前为一次性响应)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 当前后端能力总览
|
|||
|
|
|
|||
|
|
### 2.1 消息通道
|
|||
|
|
后端已支持 `MESSAGE_CHANNEL=webui`,入口在 `cmd/bot/main.go`。
|
|||
|
|
|
|||
|
|
当通道为 `webui` 时:
|
|||
|
|
- 启动 HTTP 服务
|
|||
|
|
- 暴露两个接口:
|
|||
|
|
- `POST /api/upload`
|
|||
|
|
- `POST /api/chat`
|
|||
|
|
|
|||
|
|
### 2.2 运行配置
|
|||
|
|
关键环境变量(`configs/env.sample`):
|
|||
|
|
- `MESSAGE_CHANNEL=webui`
|
|||
|
|
- `WEBUI_LISTEN_ADDR=:8090`
|
|||
|
|
- `WEBUI_MAX_UPLOAD_MB=20`
|
|||
|
|
- `LLM_*` 相关配置(含文件模型切换)
|
|||
|
|
|
|||
|
|
### 2.3 文件上下文机制(非常关键)
|
|||
|
|
当前后端使用 `chat_id + user_id` 作为会话键缓存 `file_id`:
|
|||
|
|
- 上传接口会把文件上传到 LLM,并把 `file_id` 缓存到该键
|
|||
|
|
- 后续 `chat` 接口只要带同一组 `session_id`/`user_id`,就会自动消费缓存文件上下文
|
|||
|
|
|
|||
|
|
结论:
|
|||
|
|
- 前端必须稳定维护并复用 `session_id` 与 `user_id`
|
|||
|
|
- 两者变化会导致上传文件上下文丢失(从后端视角是新会话)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 后端 API 契约(以代码为准)
|
|||
|
|
|
|||
|
|
## 3.1 `POST /api/upload`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
- 独立上传文档
|
|||
|
|
- 后端立即调用 LLM 文件上传并返回 `file_id`
|
|||
|
|
- 同时缓存到当前会话,供下一次聊天使用
|
|||
|
|
|
|||
|
|
请求:
|
|||
|
|
- Method: `POST`
|
|||
|
|
- Content-Type: `multipart/form-data`
|
|||
|
|
- Form 字段:
|
|||
|
|
- `file` (required)
|
|||
|
|
- `session_id` (optional,建议前端始终传)
|
|||
|
|
- `user_id` (optional,建议前端始终传)
|
|||
|
|
|
|||
|
|
响应 `200`:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"file_id": "file-xxx",
|
|||
|
|
"file_ids": ["file-xxx"],
|
|||
|
|
"file_name": "report.pdf",
|
|||
|
|
"mime_type": "application/pdf",
|
|||
|
|
"size_bytes": 12345,
|
|||
|
|
"session_id": "sess_xxx",
|
|||
|
|
"user_id": "user_xxx"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
错误响应:
|
|||
|
|
- `400`:
|
|||
|
|
- `{"error":"file is required"}`
|
|||
|
|
- `{"error":"invalid multipart form"}`
|
|||
|
|
- `{"error":"invalid file name"}`
|
|||
|
|
- `{"error":"empty file"}`
|
|||
|
|
- `{"error":"read file failed"}`
|
|||
|
|
- `413`:
|
|||
|
|
- `{"error":"file too large"}`
|
|||
|
|
- `500`:
|
|||
|
|
- `{"error":"upload failed"}`
|
|||
|
|
- `{"error":"upload succeeded but file_id is empty"}`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3.2 `POST /api/chat`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
- 发送纯文本消息
|
|||
|
|
- 若该 `session_id + user_id` 下已有上传文件,会自动携带文件上下文进行问答
|
|||
|
|
|
|||
|
|
请求:
|
|||
|
|
- Method: `POST`
|
|||
|
|
- Content-Type: `application/json`
|
|||
|
|
- Body:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"text": "请总结我上传的文档",
|
|||
|
|
"session_id": "sess_xxx",
|
|||
|
|
"user_id": "user_xxx"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应 `200`:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"reply": "...",
|
|||
|
|
"session_id": "sess_xxx",
|
|||
|
|
"user_id": "user_xxx"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
错误响应:
|
|||
|
|
- `400`:
|
|||
|
|
- `{"error":"content-type must be application/json"}`
|
|||
|
|
- `{"error":"invalid json body"}`
|
|||
|
|
- `{"error":"text is required"}`
|
|||
|
|
- `405`:
|
|||
|
|
- `{"error":"method not allowed"}`
|
|||
|
|
- `500`:
|
|||
|
|
- `{"error":"chat failed"}`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. WebUI 功能需求(给前端实现)
|
|||
|
|
|
|||
|
|
### 4.1 页面最小能力
|
|||
|
|
必须实现:
|
|||
|
|
1. 聊天消息列表
|
|||
|
|
2. 文本输入框 + 发送按钮
|
|||
|
|
3. 文件选择器 + 上传按钮
|
|||
|
|
4. 当前会话标识展示(`session_id`、`user_id`)
|
|||
|
|
5. 上传结果区(展示 `file_id`、文件名、大小、时间)
|
|||
|
|
6. 错误提示区(接口失败、文件超限、网络错误)
|
|||
|
|
|
|||
|
|
### 4.2 会话策略
|
|||
|
|
必须:
|
|||
|
|
- 首次进入页面时生成并持久化 `session_id`、`user_id`(例如 LocalStorage)
|
|||
|
|
- 每次请求都携带这两个字段
|
|||
|
|
- 提供“重置会话”操作(清空本地 session/user 并重新生成)
|
|||
|
|
|
|||
|
|
建议 ID 规则:
|
|||
|
|
- `session_id`: `sess_<uuid>`
|
|||
|
|
- `user_id`: `user_<uuid>`
|
|||
|
|
|
|||
|
|
### 4.3 文件上传交互
|
|||
|
|
必须:
|
|||
|
|
- 文件选择后显示基本信息(名称、大小、类型)
|
|||
|
|
- 点击上传后调用 `/api/upload`
|
|||
|
|
- 上传成功后将返回的 `file_id` 加入“已上传文件列表”
|
|||
|
|
- 上传失败时给出明确错误提示
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
- 前端先做大小校验(默认 20MB,可配置)
|
|||
|
|
- 上传中禁用重复点击
|
|||
|
|
|
|||
|
|
### 4.4 聊天交互
|
|||
|
|
必须:
|
|||
|
|
- 发送前校验 `text` 非空
|
|||
|
|
- 调用 `/api/chat`
|
|||
|
|
- 成功后追加机器人消息
|
|||
|
|
- 失败后展示错误并保留用户输入
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
- 支持回车发送(Shift+Enter 换行)
|
|||
|
|
- 增加“请求中”状态,避免并发多发
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 前端状态模型(建议)
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type UploadedFile = {
|
|||
|
|
fileId: string;
|
|||
|
|
fileName: string;
|
|||
|
|
mimeType: string;
|
|||
|
|
sizeBytes: number;
|
|||
|
|
uploadedAt: number;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
type ChatMessage = {
|
|||
|
|
id: string;
|
|||
|
|
role: "user" | "assistant" | "system";
|
|||
|
|
content: string;
|
|||
|
|
createdAt: number;
|
|||
|
|
status?: "sending" | "sent" | "failed";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
type AppState = {
|
|||
|
|
sessionId: string;
|
|||
|
|
userId: string;
|
|||
|
|
messages: ChatMessage[];
|
|||
|
|
uploadedFiles: UploadedFile[];
|
|||
|
|
uploading: boolean;
|
|||
|
|
chatting: boolean;
|
|||
|
|
lastError?: string;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
状态约束:
|
|||
|
|
- `uploading=true` 时不应再次触发上传
|
|||
|
|
- `chatting=true` 时可选禁用发送(或允许排队)
|
|||
|
|
- 任何失败都要更新 `lastError`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 接口调用示例
|
|||
|
|
|
|||
|
|
### 6.1 上传
|
|||
|
|
```bash
|
|||
|
|
curl -X POST http://localhost:8090/api/upload \
|
|||
|
|
-F "session_id=sess_demo" \
|
|||
|
|
-F "user_id=user_demo" \
|
|||
|
|
-F "file=@./demo.pdf"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 聊天
|
|||
|
|
```bash
|
|||
|
|
curl -X POST http://localhost:8090/api/chat \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"text":"这份文档主要讲了什么?","session_id":"sess_demo","user_id":"user_demo"}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 开发任务拆解(给下一个 LLM)
|
|||
|
|
|
|||
|
|
1. 初始化 WebUI 工程(技术栈自选,建议 React + TypeScript)。
|
|||
|
|
2. 实现全局状态管理(至少管理 session/user/messages/uploads)。
|
|||
|
|
3. 实现 API Client 层:
|
|||
|
|
- `uploadFile(formData)`
|
|||
|
|
- `sendChat(payload)`
|
|||
|
|
- 统一错误解析
|
|||
|
|
4. 实现页面组件:
|
|||
|
|
- `ChatPanel`
|
|||
|
|
- `Composer`
|
|||
|
|
- `UploadPanel`
|
|||
|
|
- `SessionBadge`
|
|||
|
|
5. 实现本地持久化:
|
|||
|
|
- 启动时恢复 `session_id`、`user_id`
|
|||
|
|
- 重置会话功能
|
|||
|
|
6. 完成联调与自测。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 验收标准
|
|||
|
|
|
|||
|
|
必须全部满足:
|
|||
|
|
1. 纯文本聊天可用(无文件也能正常回复)。
|
|||
|
|
2. 文档上传可用,返回并展示 `file_id`。
|
|||
|
|
3. 上传后同会话提问能基于文档回答。
|
|||
|
|
4. 刷新页面后会话 ID 不丢失(可继续提问)。
|
|||
|
|
5. 文件超限、空消息、网络失败均有可见错误反馈。
|
|||
|
|
6. 同一会话多文件上传后,后续问答仍可使用文件上下文。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 已知限制与后续建议
|
|||
|
|
|
|||
|
|
当前后端限制(前端需知晓):
|
|||
|
|
- 无鉴权机制
|
|||
|
|
- 无流式输出
|
|||
|
|
- 上传 MIME 未做白名单限制
|
|||
|
|
- 无会话文件列表接口(前端只能依赖本地记录)
|
|||
|
|
|
|||
|
|
后续建议(非本期必做):
|
|||
|
|
1. 新增后端 `GET /api/session/files` 以便页面恢复历史上传列表。
|
|||
|
|
2. 增加鉴权中间件(Bearer Token/JWT)。
|
|||
|
|
3. 增加流式聊天接口(SSE/WebSocket)。
|
|||
|
|
4. 增加上传文件类型白名单和病毒扫描。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 对下一个 LLM 的执行指令模板
|
|||
|
|
|
|||
|
|
可直接复制给下一个 LLM:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
请基于 `doc/WebUI开发技术与需求说明.md` 实现 WebUI 前端,严格对接现有后端接口:
|
|||
|
|
- POST /api/upload
|
|||
|
|
- POST /api/chat
|
|||
|
|
|
|||
|
|
必须满足:
|
|||
|
|
1) 纯文本聊天
|
|||
|
|
2) 独立文档上传
|
|||
|
|
3) 上传后同会话提问可利用文档上下文
|
|||
|
|
4) session_id/user_id 持久化
|
|||
|
|
5) 完整错误处理和可视化反馈
|
|||
|
|
|
|||
|
|
不允许修改后端接口语义;若需新增接口,请先输出变更提案,不直接改。
|
|||
|
|
```
|