Spaces:
Paused
Paused
Upload proxy_handler.py
Browse files- 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
|
| 53 |
-
|
| 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:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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
|
| 194 |
-
|
|
|
|
| 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:
|