Files
ailine/frontend/REFACTOR.md
root 626bae54ff
Some checks failed
构建并部署 AI Agent 服务 / deploy (push) Failing after 18s
前端修改
2026-04-16 03:21:38 +08:00

8.7 KiB
Raw Blame History

🏗️ 前端重构说明

重构目标

将原来的单体 frontend.py280+ 行)拆分为模块化、可维护的架构,参考后端的分层设计模式。


📁 新架构

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 集中管理所有配置,支持环境变量覆盖。

@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。

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)

设计理念:封装所有与后端的通信,支持流式响应。

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 - 左侧栏

def render_sidebar():
    """渲染左侧栏"""
    with st.sidebar:
        _render_user_section()      # 用户登录
        _render_history_section()   # 历史列表

chat_area.py - 中间聊天区

def render_chat_area():
    """渲染中间聊天区域"""
    _render_model_selector()        # 模型选择
    _render_chat_container()        # 消息显示
    _render_input_box()             # 输入框 + 流式响应

info_panel.py - 右侧信息面板

def render_info_panel():
    """渲染右侧信息面板"""
    _render_thread_info()           # 当前线程
    _render_message_stats()         # 消息统计
    _render_tips()                  # 使用提示

优势

  • 组件独立(每个文件 < 150 行)
  • 职责清晰(一个组件一个文件)
  • 易于复用(可在其他页面复用组件)
  • 易于测试(可独立测试每个组件)

5. 主入口 (frontend.py)

设计理念:仅负责组装各模块,代码量 < 50 行。

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

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.pyapi_client.py 编写测试
  2. 错误边界:在组件中添加 try-except避免单个组件崩溃影响全局
  3. 性能优化:使用 st.cache_data 缓存 API 响应
  4. 国际化:提取所有文本到 i18n.py,支持多语言
  5. 主题支持:添加暗色/亮色主题切换

🎉 前端重构完成!代码结构更清晰,维护成本大幅降低!