-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstream_buffer.py
More file actions
188 lines (153 loc) · 5.08 KB
/
Copy pathstream_buffer.py
File metadata and controls
188 lines (153 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""
流式缓冲区状态机 - 处理 SSE 流式响应
支持分块传输、缓冲区管理、状态追踪
"""
import logging
from enum import Enum
from typing import Dict, Optional, List, Generator
from dataclasses import dataclass
logger = logging.getLogger(__name__)
class StreamState(Enum):
"""流式状态"""
IDLE = "idle"
RECEIVING = "receiving"
BUFFERING = "buffering"
FLUSHING = "flushing"
DONE = "done"
ERROR = "error"
@dataclass
class StreamChunk:
"""流式数据块"""
event: str
data: str
raw: str
index: int
class StreamBuffer:
"""流式缓冲区状态机"""
def __init__(self, buffer_size: int = 4096):
self.buffer_size = buffer_size
self.state = StreamState.IDLE
self.buffer: List[str] = []
self.chunks: List[StreamChunk] = []
self.current_index = 0
self.mappings: Dict[str, str] = {}
def reset(self):
"""重置缓冲区"""
self.state = StreamState.IDLE
self.buffer.clear()
self.chunks.clear()
self.current_index = 0
self.mappings.clear()
def set_mappings(self, mappings: Dict[str, str]):
"""设置还原映射"""
self.mappings = mappings
def feed(self, data: str) -> List[StreamChunk]:
"""
输入数据流,解析并返回数据块
"""
self.state = StreamState.RECEIVING
self.buffer.append(data)
# 解析 SSE 格式
chunks = self._parse_sse(data)
self.chunks.extend(chunks)
return chunks
def _parse_sse(self, data: str) -> List[StreamChunk]:
"""解析 SSE 格式数据"""
chunks = []
lines = data.split('\n')
for line in lines:
if not line:
continue
if line.startswith('data: '):
raw_data = line[6:]
if raw_data == '[DONE]':
self.state = StreamState.DONE
chunks.append(StreamChunk(
event='done',
data='[DONE]',
raw=line,
index=self.current_index
))
else:
chunks.append(StreamChunk(
event='message',
data=raw_data,
raw=line,
index=self.current_index
))
self.current_index += 1
elif line.startswith('event: '):
# 事件类型行
pass
elif line.startswith(':'):
# 注释行,忽略
pass
else:
# 其他数据
chunks.append(StreamChunk(
event='raw',
data=line,
raw=line,
index=self.current_index
))
return chunks
def process_chunk(self, chunk: StreamChunk, unmask_func) -> StreamChunk:
"""
处理单个数据块,执行还原
"""
if chunk.event == 'done':
return chunk
# 还原敏感信息
unmasked_data = unmask_func(chunk.data, self.mappings)
return StreamChunk(
event=chunk.event,
data=unmasked_data,
raw=chunk.raw,
index=chunk.index
)
def flush(self) -> str:
"""
刷新缓冲区,返回完整数据
"""
self.state = StreamState.FLUSHING
result = '\n'.join([chunk.raw for chunk in self.chunks])
self.state = StreamState.DONE
return result
def is_done(self) -> bool:
"""检查是否完成"""
return self.state == StreamState.DONE
def is_error(self) -> bool:
"""检查是否出错"""
return self.state == StreamState.ERROR
def set_error(self, error_msg: str):
"""设置错误状态"""
self.state = StreamState.ERROR
logger.error(f"[流式错误] {error_msg}")
class StreamProcessor:
"""流式处理器"""
def __init__(self, unmask_func):
self.unmask_func = unmask_func
self.buffer = StreamBuffer()
def process_stream(self, stream: Generator[str, None, None]) -> Generator[str, None, None]:
"""
处理流式数据
"""
self.buffer.reset()
for data in stream:
chunks = self.buffer.feed(data)
for chunk in chunks:
processed = self.buffer.process_chunk(chunk, self.unmask_func)
if processed.event == 'done':
yield 'data: [DONE]\n\n'
elif processed.event == 'message':
yield f'data: {processed.data}\n\n'
else:
yield f'{processed.raw}\n'
if self.buffer.is_done():
break
if self.buffer.is_error():
yield 'data: {"error": "stream processing error"}\n\n'
break
def create_stream_processor(unmask_func) -> StreamProcessor:
"""创建流式处理器"""
return StreamProcessor(unmask_func)