Files
ailine/frontend/REFACTOR.md

289 lines
8.7 KiB
Markdown
Raw Normal View History

2026-04-16 03:21:38 +08:00
# 🏗️ 前端重构说明
## 重构目标
将原来的单体 `frontend.py`280+ 行)拆分为模块化、可维护的架构,参考后端的分层设计模式。
---
## 📁 新架构
```
frontend/
├── __init__.py # 包初始化
├── frontend.py # 主入口50 行,仅负责组装)
├── config.py # 配置管理(数据类 + 环境变量)
├── state.py # 状态管理(统一 Session State 操作)
├── api_client.py # API 客户端(封装所有后端通信)
├── utils.py # 工具函数(通用辅助函数)
└── components/ # UI 组件
├── __init__.py
├── sidebar.py # 左侧栏:用户登录 + 历史列表
├── chat_area.py # 中间栏:聊天区域 + 流式响应
└── info_panel.py # 右侧栏:信息面板
```
---
## 🎯 核心模块说明
### 1. **配置管理** (`config.py`)
**设计理念**:使用 Python `dataclass` 集中管理所有配置,支持环境变量覆盖。
```python
@dataclass
class FrontendConfig:
api_base: str = ""
page_title: str = "AI 个人助手"
default_model: str = "zhipu"
history_limit: int = 50
# ... 其他配置
# 全局配置实例
config = FrontendConfig()
```
**优势**
- ✅ 类型安全dataclass 自动类型检查)
- ✅ 集中管理(所有配置在一处)
- ✅ 易于测试(可轻松 mock 配置)
- ✅ 环境变量支持(`__post_init__` 中加载)
---
### 2. **状态管理** (`state.py`)
**设计理念**:封装所有 `st.session_state` 操作,提供统一的 API。
```python
class AppState:
@staticmethod
def init():
"""初始化所有状态"""
if "user_id" not in st.session_state:
st.session_state.user_id = config.default_user_id
# ...
@staticmethod
def login(username: str):
"""用户登录"""
st.session_state.user_id = username.strip()
st.session_state.logged_in = True
@staticmethod
def get_messages() -> List[Dict[str, str]]:
"""获取消息列表"""
return st.session_state.messages
```
**优势**
- ✅ 统一接口(所有状态操作通过 AppState
- ✅ 类型提示IDE 自动补全)
- ✅ 易于维护(状态逻辑集中)
- ✅ 避免魔法字符串(不再直接使用 `st.session_state["xxx"]`
---
### 3. **API 客户端** (`api_client.py`)
**设计理念**:封装所有与后端的通信,支持流式响应。
```python
class APIClient:
def get_user_threads(self, user_id: str, limit: int) -> List[Dict]:
"""获取用户历史列表"""
resp = requests.get(f"{self.base_url}/threads", ...)
return resp.json().get("threads", [])
def chat_stream(self, message: str, ...) -> AsyncGenerator[Dict, None]:
"""流式对话"""
with requests.post(..., stream=True) as response:
for line in response.iter_lines():
yield json.loads(line)
```
**优势**
- ✅ 职责单一(仅负责 API 通信)
- ✅ 错误处理集中(统一的异常捕获)
- ✅ 易于测试(可 mock APIClient
- ✅ 流式支持Generator 逐行 yield
---
### 4. **UI 组件** (`components/`)
**设计理念**:每个组件独立渲染,通过 State 和 API Client 交互。
#### `sidebar.py` - 左侧栏
```python
def render_sidebar():
"""渲染左侧栏"""
with st.sidebar:
_render_user_section() # 用户登录
_render_history_section() # 历史列表
```
#### `chat_area.py` - 中间聊天区
```python
def render_chat_area():
"""渲染中间聊天区域"""
_render_model_selector() # 模型选择
_render_chat_container() # 消息显示
_render_input_box() # 输入框 + 流式响应
```
#### `info_panel.py` - 右侧信息面板
```python
def render_info_panel():
"""渲染右侧信息面板"""
_render_thread_info() # 当前线程
_render_message_stats() # 消息统计
_render_tips() # 使用提示
```
**优势**
- ✅ 组件独立(每个文件 < 150
- ✅ 职责清晰(一个组件一个文件)
- ✅ 易于复用(可在其他页面复用组件)
- ✅ 易于测试(可独立测试每个组件)
---
### 5. **主入口** (`frontend.py`)
**设计理念**:仅负责组装各模块,代码量 < 50
```python
from .config import config
from .state import AppState
from .components.sidebar import render_sidebar
from .components.chat_area import render_chat_area
from .components.info_panel import render_info_panel
st.set_page_config(...)
AppState.init()
def main():
st.title("🤖 个人生活与数据分析助手")
col_sidebar, col_chat, col_info = st.columns([1, 3, 1])
with col_sidebar:
render_sidebar()
with col_chat:
render_chat_area()
with col_info:
render_info_panel()
if __name__ == "__main__":
main()
```
**优势**
- ✅ 极简主义(< 50
- ✅ 清晰结构(一眼看懂整体架构)
- ✅ 易于维护(修改功能只需改对应组件)
---
## 重构对比
| 指标 | 重构前 | 重构后 | 改进 |
|------|--------|--------|------|
| **主文件行数** | 280+ 行 | 48 行 | ✅ -83% |
| **代码结构** | 单体文件 | 模块化架构 | ✅ 分层清晰 |
| **组件独立性** | 耦合严重 | 独立组件 | ✅ 可复用 |
| **测试友好性** | 难以测试 | 易于 Mock | ✅ 可测试 |
| **维护成本** | 高(改一处影响全局) | 低(改组件不影响其他) | ✅ 易维护 |
| **代码可读性** | 差(滚动查找) | 优(模块化) | ✅ 易读 |
---
## 🎨 架构设计模式
### 1. **分层架构**
```
┌─────────────────────────────────────┐
│ 表现层 (Components) │
│ sidebar.py, chat_area.py, ... │
├─────────────────────────────────────┤
│ 业务层 (State) │
│ state.py - 状态管理 │
├─────────────────────────────────────┤
│ 数据层 (API Client) │
│ api_client.py - 后端通信 │
├─────────────────────────────────────┤
│ 配置层 (Config) │
│ config.py - 配置管理 │
└─────────────────────────────────────┘
```
### 2. **依赖方向**
```
Components → State → API Client → Config
↑ ↓
└────────────────────────┘
(全局单例实例)
```
**规则**
- ✅ 上层依赖下层
- ✅ 禁止循环依赖
- ✅ 配置和客户端为全局单例
---
## 🚀 使用示例
### 扩展新功能:添加对话导出按钮
只需修改 `components/sidebar.py`
```python
def _render_history_actions():
"""渲染历史操作按钮"""
if st.button("🔄 刷新列表", use_container_width=True):
_refresh_threads()
if st.button(" 新对话", type="primary", use_container_width=True):
AppState.start_new_thread()
st.rerun()
# 新增:导出对话按钮
if st.button("📤 导出对话", use_container_width=True):
_export_current_thread()
def _export_current_thread():
"""导出当前对话为 Markdown"""
messages = AppState.get_messages()
content = "\n\n".join([f"**{m['role']}**: {m['content']}" for m in messages])
st.download_button("下载", content, "conversation.md")
```
**优势**:修改仅影响 `sidebar.py`,不影响其他模块!
---
## ✅ 重构优势总结
1. **模块化**:每个文件职责单一,易于理解和维护
2. **可扩展**:添加新功能只需修改对应模块
3. **可测试**:各模块独立,便于编写单元测试
4. **可复用**:组件可在其他项目中复用
5. **类型安全**:使用 dataclass 和类型提示
6. **代码质量**:遵循 SOLID 原则和 Clean Architecture
---
## 📝 后续优化建议
1. **添加单元测试**:为 `state.py``api_client.py` 编写测试
2. **错误边界**:在组件中添加 try-except避免单个组件崩溃影响全局
3. **性能优化**:使用 `st.cache_data` 缓存 API 响应
4. **国际化**:提取所有文本到 `i18n.py`,支持多语言
5. **主题支持**:添加暗色/亮色主题切换
---
**🎉 前端重构完成!代码结构更清晰,维护成本大幅降低!**