DeepChat 多窗口多标签架构设计
引言
现代用户在使用 AI 工具时往往需要同时处理多个任务或主题,这就要求应用程序具备良好的多任务处理能力。DeepChat 采用了创新的多窗口+多标签架构,支持跨维度的并行多会话操作,让用户能够像使用浏览器一样使用 AI,提供非阻塞的优秀体验。本文将深入分析这一架构的设计与实现。
多窗口多标签架构概述
设计理念
DeepChat 的多窗口多标签架构基于以下设计理念:
- 并行处理 - 允许用户同时进行多个独立的对话
- 上下文隔离 - 每个会话都有独立的上下文,互不干扰
- 灵活组织 - 用户可以根据需要组织和管理会话
- 资源优化 - 合理管理内存和计算资源
架构图示
┌─────────────────────────────────────────────────────────────────────┐
│ 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
// 广播状态更新 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.FCtab ${tab.id === activeTab ? 'active' : ''}
}
onClick={() => onSwitchTab(tab.id)}
>
{tab.title}
<button
className=“tab-close”
onClick={(e) => {
e.stopPropagation();
onCloseTab(tab.id);
}}
>
×