Commit 8bcd41e5 authored by ligaowei's avatar ligaowei

Push all changes to Git server

parent ae753c87
......@@ -17,7 +17,7 @@ import { ref, onUnmounted, onMounted } from 'vue'
import type { TimelineEvent, ToolResultEvent } from '../types/timeline'
import { eventTypeLabels } from '../types/timeline'
import { SimplifiedTimelineService } from '../services/SimplifiedTimelineService'
import { TimelineService } from '../services/TimelineService'
import TimelinePanel from './TimelinePanel.vue'
// 事件数据
......@@ -65,7 +65,7 @@ const hasValidToolOutput = (event: TimelineEvent): boolean => {
};
// 时间轴服务不再需要,因为我们现在直接处理事件
// const simplifiedTimelineService = new SimplifiedTimelineService((event: TimelineEvent) => {
// const timelineService = new TimelineService((event: TimelineEvent) => {
// // 添加事件到列表
// events.value.push(event);
// console.log('[TimelineContainer] 成功添加事件:', event.type, event.title);
......@@ -81,7 +81,7 @@ const addEvent = (event: any) => {
// 清除时间轴
const handleClearTimeline = () => {
events.value = [];
// 不再调用simplifiedTimelineService.clearTimeline(),因为它是空实现
// 不再调用timelineService.clearTimeline(),因为它是空实现
// stateManager.clearAllStates();
// cacheService.clearAllCaches();
};
......
......@@ -15,12 +15,12 @@
import { ref, onMounted, onUnmounted } from 'vue'
import TimelineContainer from './TimelineContainer.vue'
import WebpageBrowser from './WebpageBrowser.vue'
import { SimplifiedTimelineService } from '../services/SimplifiedTimelineService'
import { TimelineService } from '../services/TimelineService'
const activeTab = ref('timeline')
const timelineContainerRef = ref<InstanceType<typeof TimelineContainer> | null>(null)
const webBrowser = ref()
let timelineService: SimplifiedTimelineService | null = null
let timelineService: TimelineService | null = null
// 添加事件到时间轴
const addEvent = (event: any): void => {
......@@ -30,7 +30,7 @@ const addEvent = (event: any): void => {
// 初始化Timeline服务
const initTimelineService = () => {
if (timelineContainerRef.value) {
timelineService = new SimplifiedTimelineService((event: any) => {
timelineService = new TimelineService((event: any) => {
addEvent(event)
})
timelineService.connectSSE()
......
# 前端服务层优化说明
## 概述
本文档介绍了前端服务层的一系列优化措施,旨在提高代码质量、可维护性和性能。
## 优化内容
### 1. 统一类型定义
- **文件**: `types/timeline.ts`
- **功能**: 统一定义了所有时间轴相关的事件类型和标签映射
- **优势**: 避免类型重复定义,提高类型安全性
### 2. 工具函数库
- **文件**: `utils/timelineUtils.ts`
- **功能**: 包含时间轴相关的工具函数,如事件类型判断、输入输出验证等
- **优势**: 集中管理工具函数,避免重复实现
### 3. 类型守卫函数
- **文件**: `utils/typeGuards.ts`
- **功能**: 提供类型守卫函数,用于精确的类型检查
- **优势**: 提高类型安全性,减少运行时错误
### 4. 事件去重服务
- **文件**: `services/EventDeduplicationService.ts`
- **功能**: 统一处理事件去重逻辑
- **优势**: 避免重复事件处理,节省资源
### 5. 对象池服务
- **文件**: `services/ObjectPoolService.ts`
- **功能**: 提供通用的对象池实现
- **优势**: 减少对象创建和垃圾回收压力,提高性能
### 6. 优化的事件处理服务
- **文件**: `services/OptimizedEventProcessingService.ts`
- **功能**: 使用对象池优化事件对象的创建和管理
- **优势**: 提高性能,减少内存分配
### 7. 统一事件处理器
- **文件**: `services/UnifiedEventProcessor.ts`
- **功能**: 整合所有事件处理逻辑
- **优势**: 统一事件处理流程,便于维护
## 使用方法
### 1. 类型和工具函数使用
```typescript
import type { TimelineEvent } from '../types/timeline';
import { isToolEventType, hasValidToolInput } from '../utils/timelineUtils';
import { isThoughtEvent } from '../utils/typeGuards';
```
### 2. 事件处理服务使用
```typescript
import { UnifiedEventProcessor } from '../services/UnifiedEventProcessor';
const eventProcessor = new UnifiedEventProcessor();
eventProcessor.registerHandler((event: TimelineEvent) => {
// 处理事件
});
```
### 3. 性能监控
在TimelineContainer组件中提供了性能监控功能:
```typescript
// 显示性能统计信息
showPerformanceStats();
// 定期输出性能统计(每30秒)
// 在控制台查看: [TimelineContainer] 定期性能统计
```
## 性能优化效果
通过对象池和事件去重等优化措施,预期可以获得以下性能提升:
1. 减少对象创建次数,降低垃圾回收压力
2. 避免重复事件处理,节省CPU资源
3. 提高事件处理速度,改善用户体验
## 维护建议
1. 定期查看性能监控数据,评估优化效果
2. 新增事件类型时,需在`types/timeline.ts`中定义相应类型
3. 新增工具函数时,应添加到`utils/timelineUtils.ts`
4. 保持服务层的单一职责原则,避免功能交叉
\ No newline at end of file
......@@ -2,7 +2,7 @@
* Timeline服务类
* 整合了SSE管理功能,减少服务层级
*/
export class SimplifiedTimelineService {
export class TimelineService {
private eventSource: EventSource | null = null;
private retryCount = 0;
private maxRetries = 5;
......@@ -26,23 +26,16 @@ export class SimplifiedTimelineService {
// 从localStorage获取token
const token = localStorage.getItem('token');
// 创建一个包含token的URL对象
const url = new URL(eventSourceUrl, window.location.origin);
// 使用请求头而不是URL参数传递token
if (token) {
url.searchParams.append('token', token);
}
eventSourceUrl = url.toString().replace(window.location.origin, '');
// 如果是相对路径,确保以/开头
if (!eventSourceUrl.startsWith('/')) {
eventSourceUrl = '/' + eventSourceUrl;
// 创建自定义的EventSource实现,支持添加请求头
const eventSource = new EventSourceWithAuth(eventSourceUrl, token);
this.eventSource = eventSource as unknown as EventSource;
} else {
// 如果没有token,仍然使用标准EventSource
this.eventSource = new EventSource(eventSourceUrl);
}
console.log('[TimelinePanel] 尝试连接SSE:', eventSourceUrl);
// 建立连接
this.eventSource = new EventSource(eventSourceUrl);
this.eventSource.onmessage = this.handleMessage.bind(this);
this.eventSource.onerror = this.handleError.bind(this);
this.eventSource.onopen = this.handleOpen.bind(this);
......@@ -300,4 +293,117 @@ export class SimplifiedTimelineService {
hasValidToolOutput(event: any): boolean {
return event.type === 'tool_result' && event.toolOutput !== null && event.toolOutput !== undefined;
}
}
// 自定义EventSource实现,支持添加Authorization请求头
class EventSourceWithAuth extends EventTarget {
private xhr: XMLHttpRequest | null = null;
private timeoutId: number | null = null;
private _readyState: number;
private _url: string;
private _token: string;
static readonly CONNECTING = 0;
static readonly OPEN = 1;
static readonly CLOSED = 2;
constructor(url: string, token: string) {
super();
this._url = url;
this._token = token;
this._readyState = EventSourceWithAuth.CONNECTING;
this.connect();
}
private connect() {
if (this.xhr) {
this.xhr.abort();
}
this.xhr = new XMLHttpRequest();
this.xhr.open('GET', this._url, true);
this.xhr.setRequestHeader('Accept', 'text/event-stream');
this.xhr.setRequestHeader('Cache-Control', 'no-cache');
this.xhr.setRequestHeader('Authorization', `Bearer ${this._token}`);
this.xhr.withCredentials = true;
this.xhr.onreadystatechange = () => {
if (this.xhr?.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
if (this.xhr.status === 200) {
this._readyState = EventSourceWithAuth.OPEN;
this.dispatchEvent(new Event('open'));
} else {
this.handleError();
}
}
};
this.xhr.onprogress = () => {
if (this.xhr) {
const lines = this.xhr.responseText.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
const event = new MessageEvent('message', { data });
this.dispatchEvent(event);
}
}
}
};
this.xhr.onload = () => {
this._readyState = EventSourceWithAuth.CLOSED;
this.dispatchEvent(new Event('close'));
};
this.xhr.onerror = () => {
this.handleError();
};
this.xhr.send();
// 每30秒重新连接一次,保持连接活跃
this.timeoutId = window.setTimeout(() => {
this.reconnect();
}, 30000);
}
private handleError() {
this._readyState = EventSourceWithAuth.CLOSED;
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
this.dispatchEvent(new Event('error'));
// 尝试重新连接
setTimeout(() => this.reconnect(), 3000);
}
private reconnect() {
if (this._readyState !== EventSourceWithAuth.CLOSED) {
this.connect();
}
}
close() {
this._readyState = EventSourceWithAuth.CLOSED;
if (this.xhr) {
this.xhr.abort();
}
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
this.dispatchEvent(new Event('close'));
}
get readyState() {
return this._readyState;
}
get url() {
return this._url;
}
get withCredentials() {
return false;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment