bluewinliang commited on
Commit
7099da4
·
verified ·
1 Parent(s): 8d3ffb0

Upload proxy_handler.py

Browse files
Files changed (1) hide show
  1. proxy_handler.py +15 -9
proxy_handler.py CHANGED
@@ -49,14 +49,14 @@ class ProxyHandler:
49
 
50
  def _clean_answer_content(self, text: str) -> str:
51
  """
52
- Cleans only <glm_block> tags from the final answer content,
53
- preserving other potential markdown or HTML formatting.
54
  """
55
  if not text:
56
  return ""
57
  # Remove only tool call blocks
58
  cleaned_text = re.sub(r'<glm_block.*?</glm_block>', '', text, flags=re.DOTALL)
59
- return cleaned_text.strip()
60
 
61
  def _serialize_msgs(self, msgs) -> list:
62
  """Converts message objects to a list of dictionaries."""
@@ -85,29 +85,34 @@ class ProxyHandler:
85
 
86
  async def yield_content(content_type: str, text: str):
87
  nonlocal think_open
88
- if not text: return
89
 
90
  # Apply cleaning based on content type
91
  cleaned_text = ""
92
  if content_type == "thinking":
93
  cleaned_text = self._clean_thinking_content(text)
94
  elif content_type == "answer":
 
95
  cleaned_text = self._clean_answer_content(text)
96
 
97
- if not cleaned_text: return
 
 
 
 
98
 
99
  if content_type == "thinking" and settings.SHOW_THINK_TAGS:
100
  if not think_open:
101
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': '<think>'}, 'finish_reason': None}]})}\n\n"
102
  think_open = True
103
-
104
- yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': cleaned_text}, 'finish_reason': None}]})}\n\n"
105
 
106
  elif content_type == "answer":
107
  if think_open:
108
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': '</think>'}, 'finish_reason': None}]})}\n\n"
109
  think_open = False
110
 
 
111
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': cleaned_text}, 'finish_reason': None}]})}\n\n"
112
 
113
  async with self.client.stream("POST", settings.UPSTREAM_URL, json=body, headers=headers) as resp:
@@ -190,8 +195,9 @@ class ProxyHandler:
190
  else: continue
191
  break
192
 
193
- # Clean the final answer text, removing only <glm_block> tags.
194
- cleaned_ans_text = self._clean_answer_content(''.join(raw_answer_parts))
 
195
  final_content = cleaned_ans_text
196
 
197
  if settings.SHOW_THINK_TAGS and raw_thinking_parts:
 
49
 
50
  def _clean_answer_content(self, text: str) -> str:
51
  """
52
+ Cleans only <glm_block> tags from answer content.
53
+ Does NOT strip whitespace to preserve markdown in streams.
54
  """
55
  if not text:
56
  return ""
57
  # Remove only tool call blocks
58
  cleaned_text = re.sub(r'<glm_block.*?</glm_block>', '', text, flags=re.DOTALL)
59
+ return cleaned_text # <-- FIX: Removed .strip() to preserve whitespace in chunks
60
 
61
  def _serialize_msgs(self, msgs) -> list:
62
  """Converts message objects to a list of dictionaries."""
 
85
 
86
  async def yield_content(content_type: str, text: str):
87
  nonlocal think_open
 
88
 
89
  # Apply cleaning based on content type
90
  cleaned_text = ""
91
  if content_type == "thinking":
92
  cleaned_text = self._clean_thinking_content(text)
93
  elif content_type == "answer":
94
+ # Use the non-stripping cleaner for stream chunks
95
  cleaned_text = self._clean_answer_content(text)
96
 
97
+ if not cleaned_text and not (content_type == "answer" and text):
98
+ # For answer, even if cleaning results in empty (e.g. only a glm_block),
99
+ # the original might have been just whitespace, so we allow it to pass if text was present.
100
+ # This logic is now simpler: if there's no text, don't yield.
101
+ if not text: return
102
 
103
  if content_type == "thinking" and settings.SHOW_THINK_TAGS:
104
  if not think_open:
105
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': '<think>'}, 'finish_reason': None}]})}\n\n"
106
  think_open = True
107
+ if cleaned_text:
108
+ yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': cleaned_text}, 'finish_reason': None}]})}\n\n"
109
 
110
  elif content_type == "answer":
111
  if think_open:
112
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': '</think>'}, 'finish_reason': None}]})}\n\n"
113
  think_open = False
114
 
115
+ # Yield the cleaned text, which now preserves crucial whitespace
116
  yield f"data: {json.dumps({'id': comp_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': req.model, 'choices': [{'index': 0, 'delta': {'content': cleaned_text}, 'finish_reason': None}]})}\n\n"
117
 
118
  async with self.client.stream("POST", settings.UPSTREAM_URL, json=body, headers=headers) as resp:
 
195
  else: continue
196
  break
197
 
198
+ # Clean the joined answer text, then strip the final result.
199
+ full_answer = ''.join(raw_answer_parts)
200
+ cleaned_ans_text = self._clean_answer_content(full_answer).strip() # <-- FIX: Apply .strip() here
201
  final_content = cleaned_ans_text
202
 
203
  if settings.SHOW_THINK_TAGS and raw_thinking_parts: