pycoze 0.1.423__py3-none-any.whl → 0.1.425__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pycoze/bot/chat_base.py CHANGED
@@ -87,15 +87,86 @@ def dumps_markdown_json(data):
87
87
 
88
88
 
89
89
 
90
+ class BufferProcessor:
91
+ def __init__(self):
92
+ self.buffer = ""
93
+ self.in_json_block = False
94
+ self.json_block_content = ""
95
+ self.text_content = ""
96
+
97
+ def process_buffer(self):
98
+ """
99
+ 处理 buffer 中的内容,并返回生成的内容类型和内容。
100
+ 返回格式为 (type, content),其中 type 可以是 "text" 或 "json"。
101
+ """
102
+ results = []
103
+ while self.buffer:
104
+ if not self.in_json_block:
105
+ # 查找 JSON 代码块的起始标记
106
+ json_start_match = re.search(r"```json", self.buffer, re.IGNORECASE)
107
+ if json_start_match:
108
+ # 提取 JSON 代码块之前的文本
109
+ self.text_content += self.buffer[:json_start_match.start()]
110
+ # 如果 text_content 不为空,先 yield 文本
111
+ if self.text_content.strip():
112
+ results.append(("text", self.text_content.strip()))
113
+ self.text_content = ""
114
+ # 进入 JSON 代码块模式
115
+ self.in_json_block = True
116
+ self.buffer = self.buffer[json_start_match.end():]
117
+ else:
118
+ # 如果没有找到 JSON 代码块,继续累积到 text_content
119
+ self.text_content += self.buffer
120
+ self.buffer = ""
121
+ else:
122
+ # 查找 JSON 代码块的结束标记
123
+ json_end_match = re.search(r"```", self.buffer)
124
+ if json_end_match:
125
+ # 提取 JSON 代码块内容
126
+ self.json_block_content += self.buffer[:json_end_match.start()]
127
+ # yield JSON 代码块
128
+ results.append(("json", self.json_block_content.strip()))
129
+ self.json_block_content = ""
130
+ self.in_json_block = False
131
+ self.buffer = self.buffer[json_end_match.end():]
132
+ else:
133
+ # 如果没有找到结束标记,继续累积 JSON 内容
134
+ self.json_block_content += self.buffer
135
+ self.buffer = ""
136
+ return results
137
+
138
+ def finalize(self):
139
+ """
140
+ 处理流结束后的剩余内容。
141
+ 返回格式为 (type, content),其中 type 可以是 "text" 或 "json"。
142
+ """
143
+ results = []
144
+ if self.in_json_block:
145
+ # 如果仍在 JSON 代码块模式,处理剩余的 JSON 内容
146
+ if self.json_block_content.strip():
147
+ results.append(("json", self.json_block_content.strip()))
148
+ else:
149
+ # 如果不在 JSON 代码块模式,处理剩余的文本内容
150
+ if self.text_content.strip():
151
+ results.append(("text", self.text_content.strip()))
152
+ return results
153
+
154
+ def reset(self):
155
+ """
156
+ 重置 buffer 处理器的状态。
157
+ """
158
+ self.buffer = ""
159
+ self.in_json_block = False
160
+ self.json_block_content = ""
161
+ self.text_content = ""
162
+
163
+
90
164
  async def stream_openai_response(conversation_history, start_new_stream):
91
165
  """
92
166
  异步流式传输 OpenAI 聊天完成响应并处理结构化输出
93
167
  """
94
168
  stream = None
95
- buffer = ""
96
- in_json_block = False
97
- json_block_content = ""
98
- text_content = ""
169
+ buffer_processor = BufferProcessor()
99
170
 
100
171
  while True:
101
172
  # 检查是否需要重新创建流
@@ -104,10 +175,7 @@ async def stream_openai_response(conversation_history, start_new_stream):
104
175
  await stream.aclose() # 关闭之前的流
105
176
  stream = chat_stream_async(conversation_history) # 获取新的异步生成器
106
177
  start_new_stream["value"] = False # 重置标志
107
- buffer = ""
108
- in_json_block = False
109
- json_block_content = ""
110
- text_content = ""
178
+ buffer_processor.reset()
111
179
 
112
180
  # 使用 async for 迭代异步生成器
113
181
  try:
@@ -117,44 +185,11 @@ async def stream_openai_response(conversation_history, start_new_stream):
117
185
  break # 退出当前的 async for 循环,进入下一次 while 循环
118
186
 
119
187
  info("assistant", chunk)
120
- buffer += chunk
188
+ buffer_processor.buffer += chunk
121
189
 
122
- if "\n" not in chunk: # 行为基本的处理单位
123
- continue
124
- # 处理 buffer 中的内容
125
- while buffer:
126
- if not in_json_block:
127
- # 查找 JSON 代码块的起始标记
128
- json_start_match = re.search(r"```json", buffer, re.IGNORECASE)
129
- if json_start_match:
130
- # 提取 JSON 代码块之前的文本
131
- text_content += buffer[:json_start_match.start()]
132
- # 如果 text_content 不为空,先 yield 文本
133
- if text_content.strip():
134
- yield ("text", text_content.strip())
135
- text_content = ""
136
- # 进入 JSON 代码块模式
137
- in_json_block = True
138
- buffer = buffer[json_start_match.end():]
139
- else:
140
- # 如果没有找到 JSON 代码块,继续累积到 text_content
141
- text_content += buffer
142
- buffer = ""
143
- else:
144
- # 查找 JSON 代码块的结束标记
145
- json_end_match = re.search(r"```", buffer)
146
- if json_end_match:
147
- # 提取 JSON 代码块内容
148
- json_block_content += buffer[:json_end_match.start()]
149
- # yield JSON 代码块
150
- yield ("json", json_block_content.strip())
151
- json_block_content = ""
152
- in_json_block = False
153
- buffer = buffer[json_end_match.end():]
154
- else:
155
- # 如果没有找到结束标记,继续累积 JSON 内容
156
- json_block_content += buffer
157
- buffer = ""
190
+ if "\n" in chunk:
191
+ for result in buffer_processor.process_buffer():
192
+ yield result
158
193
 
159
194
  # 如果流正常结束,退出 while 循环
160
195
  break
@@ -163,50 +198,10 @@ async def stream_openai_response(conversation_history, start_new_stream):
163
198
  # 捕获其他异常(如网络错误)
164
199
  print(f"Error: {e}", style="bold red")
165
200
  break
166
-
167
- if buffer:
168
- if not in_json_block:
169
- # 查找 JSON 代码块的起始标记
170
- json_start_match = re.search(r"```json", buffer, re.IGNORECASE)
171
- if json_start_match:
172
- # 提取 JSON 代码块之前的文本
173
- text_content += buffer[:json_start_match.start()]
174
- # 如果 text_content 不为空,先 yield 文本
175
- if text_content.strip():
176
- yield ("text", text_content.strip())
177
- text_content = ""
178
- # 进入 JSON 代码块模式
179
- in_json_block = True
180
- buffer = buffer[json_start_match.end():]
181
- else:
182
- # 如果没有找到 JSON 代码块,继续累积到 text_content
183
- text_content += buffer
184
- buffer = ""
185
- else:
186
- # 查找 JSON 代码块的结束标记
187
- json_end_match = re.search(r"```", buffer)
188
- if json_end_match:
189
- # 提取 JSON 代码块内容
190
- json_block_content += buffer[:json_end_match.start()]
191
- # yield JSON 代码块
192
- yield ("json", json_block_content.strip())
193
- json_block_content = ""
194
- in_json_block = False
195
- buffer = buffer[json_end_match.end():]
196
- else:
197
- # 如果没有找到结束标记,继续累积 JSON 内容
198
- json_block_content += buffer
199
- buffer = ""
200
-
201
+
201
202
  # 处理流结束后的剩余内容
202
- if in_json_block:
203
- # 如果仍在 JSON 代码块模式,处理剩余的 JSON 内容
204
- if json_block_content.strip():
205
- yield ("json", json_block_content.strip())
206
- else:
207
- # 如果不在 JSON 代码块模式,处理剩余的文本内容
208
- if text_content.strip():
209
- yield ("text", text_content.strip())
203
+ for result in buffer_processor.finalize():
204
+ yield result
210
205
 
211
206
 
212
207
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pycoze
3
- Version: 0.1.423
3
+ Version: 0.1.425
4
4
  Summary: Package for pycoze only!
5
5
  Author: Yuan Jie Xiong
6
6
  Author-email: aiqqqqqqq@qq.com
@@ -11,7 +11,7 @@ pycoze/api/lib/web.py,sha256=GWgtiTJOolKOX2drXcwuyqTcbo5FQVxa1NuBGcNyjyc,223
11
11
  pycoze/api/lib/window.py,sha256=dkzWfLwn5pE_L0DfQ38K8nx9tQyT5KO-GYyXi0rytFc,2073
12
12
  pycoze/bot/__init__.py,sha256=rL3Q-ycczRpSFfKn84fg3QBl5k22WpyeIU5qOEjEby8,79
13
13
  pycoze/bot/chat.py,sha256=qEuMxH0cVFU9QSU36FrOsjhRAxtsvOv7CQtuXvM3F6Y,6446
14
- pycoze/bot/chat_base.py,sha256=ezA8zTnA5lDhymA3mm2Hu3gRWj7Lg-wks_TsmjRgBb4,12993
14
+ pycoze/bot/chat_base.py,sha256=_yAzwngBqEmgDmF8mV44gms6-MkDlu4HeboqGZole2w,12267
15
15
  pycoze/bot/lib.py,sha256=_bQ52mKsWgFGAogFHnmRBJbvK_tPOwsAJ8NqJNMR5K4,7210
16
16
  pycoze/bot/message.py,sha256=udnIi-h4QgGzkbr_5VcAsVGjoLp9wXJSfBCeuOz7_Bk,802
17
17
  pycoze/bot/prompt.md,sha256=t7NQdiiNe-jCDVfeVbvTPfq5WK5nF8CxFUQUFMyXJlo,13880
@@ -31,8 +31,8 @@ pycoze/utils/arg.py,sha256=jop1tBfe5hYkHW1NSpCeaZBEznkgguBscj_7M2dWfrs,503
31
31
  pycoze/utils/env.py,sha256=5pWlXfM1F5ZU9hhv1rHlDEanjEW5wf0nbyez9bNRqqA,559
32
32
  pycoze/utils/socket.py,sha256=bZbFFRH4mfThzRqt55BAAGQ6eICx_ja4x8UGGrUdAm8,2428
33
33
  pycoze/utils/text_or_file.py,sha256=gpxZVWt2DW6YiEg_MnMuwg36VNf3TX383QD_1oZNB0Y,551
34
- pycoze-0.1.423.dist-info/LICENSE,sha256=QStd_Qsd0-kAam_-sOesCIp_uKrGWeoKwt9M49NVkNU,1090
35
- pycoze-0.1.423.dist-info/METADATA,sha256=oE3uAJ3Xa-psi-4qdE88527WUbAHt5KjbJ5WUWZ929I,854
36
- pycoze-0.1.423.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
- pycoze-0.1.423.dist-info/top_level.txt,sha256=76dPeDhKvOCleL3ZC5gl1-y4vdS1tT_U1hxWVAn7sFo,7
38
- pycoze-0.1.423.dist-info/RECORD,,
34
+ pycoze-0.1.425.dist-info/LICENSE,sha256=QStd_Qsd0-kAam_-sOesCIp_uKrGWeoKwt9M49NVkNU,1090
35
+ pycoze-0.1.425.dist-info/METADATA,sha256=r4rZ7Vt1KvP4uPnYTtdMX2h8XU2GLNqLNUEzNivUMQI,854
36
+ pycoze-0.1.425.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
+ pycoze-0.1.425.dist-info/top_level.txt,sha256=76dPeDhKvOCleL3ZC5gl1-y4vdS1tT_U1hxWVAn7sFo,7
38
+ pycoze-0.1.425.dist-info/RECORD,,