Initial TrueGrowth source import
This commit is contained in:
187
specs/003-chat-drawer/research.md
Normal file
187
specs/003-chat-drawer/research.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Research: 对话抽屉 (Chat Drawer)
|
||||
|
||||
**Date**: 2025-12-03
|
||||
**Feature**: 001-chat-drawer
|
||||
|
||||
## 技术决策
|
||||
|
||||
### 1. 抽屉组件实现方案
|
||||
|
||||
**Decision**: 使用 CSS Transform + Transition 实现抽屉动画
|
||||
|
||||
**Rationale**:
|
||||
- CSS Transform 利用 GPU 加速,性能最优
|
||||
- 现有项目已有类似动画模式(unified-toolbar 的响应式切换)
|
||||
- 简单直接,易于维护
|
||||
|
||||
**Alternatives Considered**:
|
||||
- Framer Motion:功能强大但增加依赖体积
|
||||
- React Spring:学习曲线较高
|
||||
- TDesign Drawer:与画板布局集成复杂
|
||||
|
||||
### 2. 流式响应实现方案
|
||||
|
||||
**Decision**: 使用 Fetch API + ReadableStream 处理 SSE (Server-Sent Events)
|
||||
|
||||
**Rationale**:
|
||||
- 原生支持,无需额外依赖
|
||||
- 与现有 Gemini API 集成模式一致
|
||||
- 可以逐字符/逐词渲染,提供最佳用户体验
|
||||
|
||||
**Alternatives Considered**:
|
||||
- WebSocket:需要服务端支持,过于复杂
|
||||
- 轮询:用户体验差,延迟高
|
||||
- 第三方库(如 openai-streams):增加依赖
|
||||
|
||||
### 3. 对话存储方案
|
||||
|
||||
**Decision**: IndexedDB via localforage,独立 store
|
||||
|
||||
**Rationale**:
|
||||
- 项目已使用 localforage(task-queue 模块)
|
||||
- IndexedDB 支持大容量存储(50MB+)
|
||||
- 异步 API 不阻塞主线程
|
||||
- 支持复杂查询和索引
|
||||
|
||||
**Alternatives Considered**:
|
||||
- localStorage:5MB 限制,同步 API
|
||||
- 纯 IndexedDB:API 复杂,localforage 封装更友好
|
||||
- 云端存储:需要后端支持,超出当前范围
|
||||
|
||||
### 4. 会话状态管理方案
|
||||
|
||||
**Decision**: React Context + useReducer + RxJS Subject
|
||||
|
||||
**Rationale**:
|
||||
- 与现有 DrawnixContext 模式一致
|
||||
- RxJS 用于跨组件事件通信(参考 task-queue-service)
|
||||
- useReducer 管理复杂状态转换
|
||||
|
||||
**Alternatives Considered**:
|
||||
- Redux/Zustand:增加依赖,当前规模不需要
|
||||
- 纯 Context:复杂状态难以管理
|
||||
- Jotai/Recoil:团队不熟悉
|
||||
|
||||
### 5. 附件处理方案
|
||||
|
||||
**Decision**: FileReader + Base64 编码存储小文件,大文件使用 Blob URL
|
||||
|
||||
**Rationale**:
|
||||
- 小文件(<5MB)Base64 存储便于 IndexedDB 持久化
|
||||
- 大文件 Blob URL 避免内存问题
|
||||
- 与现有 media-cache-service 模式一致
|
||||
|
||||
**Alternatives Considered**:
|
||||
- 全部 Base64:大文件性能差
|
||||
- 全部 Blob:刷新后丢失
|
||||
- 云存储:需要后端
|
||||
|
||||
### 6. 响应式布局方案
|
||||
|
||||
**Decision**: CSS Media Query + ResizeObserver + isMobile 状态
|
||||
|
||||
**Rationale**:
|
||||
- 与现有 unified-toolbar 响应式模式一致
|
||||
- 结合 CSS 和 JS 实现精确控制
|
||||
- 复用现有 isMobile 检测逻辑
|
||||
|
||||
**Alternatives Considered**:
|
||||
- 纯 CSS:复杂状态难以处理
|
||||
- 纯 JS:性能开销大
|
||||
|
||||
### 7. AI API 集成方案
|
||||
|
||||
**Decision**: 复用现有 gemini-api 工具,扩展支持聊天接口
|
||||
|
||||
**Rationale**:
|
||||
- API Key 管理已在 settings-manager 中实现
|
||||
- 减少重复代码
|
||||
- 统一的错误处理和重试逻辑
|
||||
|
||||
**Alternatives Considered**:
|
||||
- 新建独立 API 模块:重复工作
|
||||
- 使用第三方 SDK:增加依赖
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### React 组件结构
|
||||
|
||||
```typescript
|
||||
// 组件拆分策略 - 确保每个文件 <500 行
|
||||
// ChatDrawer.tsx: 主容器,状态管理 (~200行)
|
||||
// MessageList.tsx: 消息列表渲染 (~150行)
|
||||
// MessageItem.tsx: 单条消息 (~100行)
|
||||
// MessageInput.tsx: 输入框 (~150行)
|
||||
// SessionList.tsx: 会话列表 (~100行)
|
||||
// SessionItem.tsx: 单个会话 (~80行)
|
||||
// AttachmentPreview.tsx: 附件预览 (~100行)
|
||||
// StreamingText.tsx: 流式文本 (~80行)
|
||||
```
|
||||
|
||||
### 性能优化
|
||||
|
||||
```typescript
|
||||
// 1. 消息列表虚拟化(长列表场景)
|
||||
// 使用 react-window 或自定义实现
|
||||
|
||||
// 2. 消息组件记忆化
|
||||
const MessageItem = React.memo(({ message }) => {...});
|
||||
|
||||
// 3. 存储操作防抖
|
||||
const debouncedSave = useMemo(
|
||||
() => debounce(saveToStorage, 500),
|
||||
[]
|
||||
);
|
||||
|
||||
// 4. 流式渲染优化
|
||||
// 使用 requestAnimationFrame 批量更新
|
||||
```
|
||||
|
||||
### 错误处理
|
||||
|
||||
```typescript
|
||||
// 统一错误边界
|
||||
class ChatErrorBoundary extends React.Component {
|
||||
static getDerivedStateFromError(error) {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <ChatErrorFallback error={this.state.error} />;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
// API 错误处理
|
||||
try {
|
||||
await sendMessage(content);
|
||||
} catch (error) {
|
||||
if (error.name === 'AbortError') {
|
||||
// 用户取消
|
||||
} else if (error.status === 429) {
|
||||
// 限流
|
||||
} else {
|
||||
// 通用错误
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 技术风险
|
||||
|
||||
| Risk | Impact | Mitigation |
|
||||
|------|--------|------------|
|
||||
| AI API 响应慢 | 用户体验差 | 流式显示 + 加载状态 + 超时处理 |
|
||||
| IndexedDB 存储满 | 数据丢失 | 存储限额监控 + 自动清理旧数据 |
|
||||
| 长对话性能 | 卡顿 | 虚拟滚动 + 消息分页 |
|
||||
| 移动端键盘遮挡 | 输入困难 | 监听 visualViewport + 自动滚动 |
|
||||
| 网络断开 | 消息发送失败 | 离线检测 + 队列重试 |
|
||||
|
||||
## 参考实现
|
||||
|
||||
- **现有 Dialog 系统**: `packages/drawnix/src/components/dialog/dialog.tsx`
|
||||
- **Task Queue UI**: `packages/drawnix/src/components/task-queue/`
|
||||
- **存储服务**: `packages/drawnix/src/services/storage-service.ts`
|
||||
- **Settings Manager**: `packages/drawnix/src/utils/settings-manager.ts`
|
||||
- **Gemini API**: `packages/drawnix/src/utils/gemini-api/`
|
||||
Reference in New Issue
Block a user