DeepChat 多窗口多标签架构设计

DeepChat 多窗口多标签架构设计

引言

现代用户在使用 AI 工具时往往需要同时处理多个任务或主题,这就要求应用程序具备良好的多任务处理能力。DeepChat 采用了创新的多窗口+多标签架构,支持跨维度的并行多会话操作,让用户能够像使用浏览器一样使用 AI,提供非阻塞的优秀体验。本文将深入分析这一架构的设计与实现。

多窗口多标签架构概述

设计理念

DeepChat 的多窗口多标签架构基于以下设计理念:

  1. 并行处理 - 允许用户同时进行多个独立的对话
  2. 上下文隔离 - 每个会话都有独立的上下文,互不干扰
  3. 灵活组织 - 用户可以根据需要组织和管理会话
  4. 资源优化 - 合理管理内存和计算资源

架构图示

┌─────────────────────────────────────────────────────────────────────┐
│                        DeepChat 多窗口架构                          │
├─────────────────────────────────────────────────────────────────────┤
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐  │
│  │   主窗口         │    │   子窗口A        │    │   子窗口B        │  │
│  │                 │    │                 │    │                 │  │
│  │ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │  │
│  │ │  标签页1     │ │    │ │  标签页1     │ │    │ │  标签页1     │ │  │
│  │ ├─────────────┤ │    │ ├─────────────┤ │    │ ├─────────────┤ │  │
│  │ │  标签页2     │ │    │ │  标签页2     │ │    │ │  标签页2     │ │  │
│  │ ├─────────────┤ │    │ └─────────────┘ │    │ └─────────────┘ │  │
│  │ │  标签页3     │ │    │                 │    │                 │  │
│  │ └─────────────┘ │    │                 │    │                 │  │
│  └─────────────────┘    └─────────────────┘    └─────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

会话管理机制

会话数据结构

DeepChat 中的会话采用如下数据结构:

interface Session {
  id: string;                    // 会话唯一标识
  title: string;                 // 会话标题
  createdAt: Date;              // 创建时间
  updatedAt: Date;              // 最后更新时间
  messages: Message[];          // 消息历史
  modelConfig: ModelConfig;     // 模型配置
  tags: string[];               // 标签
  windowId: string;             // 所属窗口ID
  tabIndex: number;             // 标签页索引
}

interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: Date;
  metadata?: any;
}

会话生命周期管理

DeepChat 实现了完整的会话生命周期管理:

class SessionManager {
  private sessions: Map<string, Session> = new Map();
  private activeSessions: Set<string> = new Set();
  
  // 创建新会话
  createSession(windowId: string, config?: Partial<Session>): Session {
    const sessionId = this.generateId();
    const session: Session = {
      id: sessionId,
      title: '新会话',
      createdAt: new Date(),
      updatedAt: new Date(),
      messages: [],
      modelConfig: defaultModelConfig,
      tags: [],
      windowId,
      tabIndex: this.getNextTabIndex(windowId),
      ...config
    };
    
    this.sessions.set(sessionId, session);
    return session;
  }
  
  // 获取会话
  getSession(sessionId: string): Session | undefined {
    return this.sessions.get(sessionId);
  }
  
  // 更新会话
  updateSession(sessionId: string, updates: Partial<Session>): void {
    const session = this.sessions.get(sessionId);
    if (session) {
      Object.assign(session, updates, { updatedAt: new Date() });
    }
  }
  
  // 删除会话
  deleteSession(sessionId: string): void {
    this.sessions.delete(sessionId);
    this.activeSessions.delete(sessionId);
  }
  
  // 激活会话
  activateSession(sessionId: string): void {
    this.activeSessions.add(sessionId);
  }
  
  // 休眠会话
  deactivateSession(sessionId: string): void {
    this.activeSessions.delete(sessionId);
  }
}

窗口管理系统

窗口数据结构

``typescript interface WindowState { id: string; // 窗口唯一标识 title: string; // 窗口标题 bounds: Rectangle; // 窗口位置和大小 sessions: string[]; // 包含的会话ID列表 activeSession: string | null; // 当前激活的会话 tabs: TabState[]; // 标签页状态 }

interface TabState { id: string; // 标签页ID sessionId: string; // 关联的会话ID title: string; // 标签页标题 isActive: boolean; // 是否为当前标签页 }


### 窗口管理实现

``typescript
class WindowManager {
  private windows: Map<string, WindowState> = new Map();
  
  // 创建新窗口
  createWindow(options?: BrowserWindowOptions): WindowState {
    const windowId = this.generateId();
    
    // 创建 Electron 窗口
    const browserWindow = new BrowserWindow({
      width: 1200,
      height: 800,
      ...options
    });
    
    const windowState: WindowState = {
      id: windowId,
      title: 'DeepChat',
      bounds: browserWindow.getBounds(),
      sessions: [],
      activeSession: null,
      tabs: []
    };
    
    this.windows.set(windowId, windowState);
    
    // 监听窗口事件
    browserWindow.on('resize', () => {
      this.updateWindowBounds(windowId, browserWindow.getBounds());
    });
    
    return windowState;
  }
  
  // 添加标签页到窗口
  addTabToWindow(windowId: string, session: Session): TabState {
    const window = this.windows.get(windowId);
    if (!window) {
      throw new Error(`Window ${windowId} not found`);
    }
    
    const tab: TabState = {
      id: this.generateId(),
      sessionId: session.id,
      title: session.title,
      isActive: window.tabs.length === 0
    };
    
    window.tabs.push(tab);
    window.sessions.push(session.id);
    
    if (tab.isActive) {
      window.activeSession = session.id;
    }
    
    return tab;
  }
  
  // 切换标签页
  switchToTab(windowId: string, tabId: string): void {
    const window = this.windows.get(windowId);
    if (!window) return;
    
    // 更新标签页激活状态
    window.tabs.forEach(tab => {
      tab.isActive = tab.id === tabId;
    });
    
    // 更新当前会话
    const tab = window.tabs.find(t => t.id === tabId);
    if (tab) {
      window.activeSession = tab.sessionId;
    }
  }
}

数据同步与状态管理

跨窗口状态同步

为了确保多个窗口间的数据一致性,DeepChat 实现了跨窗口状态同步机制:

``typescript class StateSyncManager { private syncChannels: Map<string, Set> = new Map();

// 广播状态更新 broadcastStateUpdate(channel: string, data: any): void { const windows = this.syncChannels.get(channel) || new Set();

windows.forEach(windowId => {
  const window = WindowManager.getInstance().getWindow(windowId);
  if (window) {
    window.webContents.send('state-update', {
      channel,
      data
    });
  }
});

}

// 订阅状态更新 subscribeToUpdates(windowId: string, channels: string[]): void { channels.forEach(channel => { if (!this.syncChannels.has(channel)) { this.syncChannels.set(channel, new Set()); } this.syncChannels.get(channel)!.add(windowId); }); } }


### 会话状态持久化

DeepChat 将会话状态持久化到本地存储:

``typescript
class SessionPersistence {
  private storagePath: string;
  
  constructor(storagePath: string) {
    this.storagePath = storagePath;
  }
  
  // 保存会话
  async saveSession(session: Session): Promise<void> {
    const filePath = path.join(this.storagePath, `${session.id}.json`);
    await fs.promises.writeFile(
      filePath, 
      JSON.stringify(session, null, 2)
    );
  }
  
  // 加载会话
  async loadSession(sessionId: string): Promise<Session | null> {
    try {
      const filePath = path.join(this.storagePath, `${sessionId}.json`);
      const data = await fs.promises.readFile(filePath, 'utf-8');
      return JSON.parse(data);
    } catch (error) {
      return null;
    }
  }
  
  // 获取所有会话列表
  async listSessions(): Promise<SessionMetadata[]> {
    const files = await fs.promises.readdir(this.storagePath);
    const sessions: SessionMetadata[] = [];
    
    for (const file of files) {
      if (file.endsWith('.json')) {
        const sessionId = path.basename(file, '.json');
        const session = await this.loadSession(sessionId);
        if (session) {
          sessions.push({
            id: session.id,
            title: session.title,
            createdAt: session.createdAt,
            updatedAt: session.updatedAt,
            messageCount: session.messages.length
          });
        }
      }
    }
    
    return sessions.sort((a, b) => 
      b.updatedAt.getTime() - a.updatedAt.getTime()
    );
  }
}

用户界面设计与交互体验

标签页界面设计

DeepChat 的标签页界面设计注重用户体验:

``tsx // 标签页组件 const TabBar: React.FC = ({ tabs, activeTab, onSwitchTab, onCloseTab }) => { return (

{tabs.map(tab => ( <div key={tab.id} className={tab ${tab.id === activeTab ? 'active' : ''}} onClick={() => onSwitchTab(tab.id)} > {tab.title} <button className=“tab-close” onClick={(e) => { e.stopPropagation(); onCloseTab(tab.id); }} > ×
))}
); };


### 拖拽与重新排列

支持标签页的拖拽和重新排列:

``typescript
class TabDragManager {
  handleTabDragStart(tabId: string, event: DragEvent): void {
    event.dataTransfer?.setData('text/plain', tabId);
    event.dataTransfer!.effectAllowed = 'move';
  }
  
  handleTabDragOver(event: DragEvent): void {
    event.preventDefault();
    event.dataTransfer!.dropEffect = 'move';
  }
  
  handleTabDrop(targetTabId: string, event: DragEvent): void {
    event.preventDefault();
    const draggedTabId = event.dataTransfer?.getData('text/plain');
    if (draggedTabId && draggedTabId !== targetTabId) {
      this.reorderTabs(draggedTabId, targetTabId);
    }
  }
  
  private reorderTabs(draggedTabId: string, targetTabId: string): void {
    // 实现标签页重新排序逻辑
  }
}

性能优化策略

内存管理

为了优化内存使用,DeepChat 实现了会话的懒加载和卸载机制:

``typescript class MemoryManager { private loadedSessions: Map<string, Session> = new Map(); private sessionCache: LRUCache<string, Session>;

constructor(maxCachedSessions: number = 50) { this.sessionCache = new LRUCache(maxCachedSessions); }

// 获取会话(自动加载) async getSession(sessionId: string): Promise<Session | null> { // 检查已加载的会话 if (this.loadedSessions.has(sessionId)) { return this.loadedSessions.get(sessionId)!; }

// 检查缓存
if (this.sessionCache.has(sessionId)) {
  const session = this.sessionCache.get(sessionId)!;
  this.loadedSessions.set(sessionId, session);
  return session;
}

// 从持久化存储加载
const session = await SessionPersistence.getInstance().loadSession(sessionId);
if (session) {
  this.loadedSessions.set(sessionId, session);
  this.sessionCache.set(sessionId, session);
}

return session;

}

// 卸载不活跃的会话 unloadInactiveSessions(): void { const activeSessionIds = WindowManager.getInstance().getActiveSessionIds();

for (const [sessionId, session] of this.loadedSessions.entries()) {
  if (!activeSessionIds.includes(sessionId)) {
    // 从已加载集合中移除
    this.loadedSessions.delete(sessionId);
    // 保留在缓存中以备快速重新加载
  }
}

} }


### 虚拟化渲染

对于包含大量消息的会话,采用虚拟化渲染技术:

``tsx
const VirtualizedMessageList: React.FC<MessageListProps> = ({ messages }) => {
  const { visibleItems, totalHeight, itemHeight } = useVirtualizedList({
    items: messages,
    itemHeight: 100, // 估计的每条消息高度
    windowHeight: 600
  });
  
  return (
    <div className="message-list" style={{ height: totalHeight }}>
      {visibleItems.map((message, index) => (
        <div 
          key={message.id}
          className="message-item"
          style={{ 
            height: itemHeight,
            transform: `translateY(${index * itemHeight}px)`
          }}
        >
          <MessageView message={message} />
        </div>
      ))}
    </div>
  );
};

小结

DeepChat 的多窗口多标签架构为用户提供了强大的并行处理能力,其主要特点包括:

  1. 灵活的会话管理 - 支持创建、切换、重命名和删除会话
  2. 跨窗口同步 - 确保多个窗口间的数据一致性
  3. 状态持久化 - 会话数据本地存储,支持持久化保存
  4. 优秀的用户体验 - 直观的标签页界面和拖拽操作
  5. 性能优化 - 内存管理和虚拟化渲染技术

这一架构让用户能够像使用现代浏览器一样使用 AI 工具,大大提高了工作效率和用户体验。

在下一篇文章中,我们将探讨 DeepChat 的安全与隐私保护机制,分析其如何确保用户数据的安全。