Migrate LLM client to OpenAI SDK and implement WebUI-specific fileID handling

This commit is contained in:
2026-03-10 17:54:50 +08:00
parent 49f6297631
commit 0e1a800646
23 changed files with 1162 additions and 8201 deletions

View File

@@ -0,0 +1,305 @@
# 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) 完整错误处理和可视化反馈
不允许修改后端接口语义;若需新增接口,请先输出变更提案,不直接改。
```