Fix expected string or bytes-like object TypeError in format_thinking_tags by ensuring text is returned and type-checked
Browse files- src/engine.py +19 -0
src/engine.py
CHANGED
|
@@ -239,6 +239,12 @@ def format_thinking_tags(text: str) -> str:
|
|
| 239 |
Replaces model <thinking></thinking> tags with clean, modern HTML Details panels
|
| 240 |
for premium rendering in the Gradio chat viewport.
|
| 241 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
if "<thinking>" in text:
|
| 243 |
parts = text.split("<thinking>", 1)
|
| 244 |
before_thinking = parts[0]
|
|
@@ -252,12 +258,19 @@ def format_thinking_tags(text: str) -> str:
|
|
| 252 |
else:
|
| 253 |
# Thinking block is still generating, render it open
|
| 254 |
return f"{before_thinking}<details open class='thinking-block'><summary>Thinking Process...</summary>\n\n{rest.strip()}\n\n</details>"
|
|
|
|
| 255 |
|
| 256 |
def extract_artifacts(text: str) -> list:
|
| 257 |
"""
|
| 258 |
Extracts all <artifact> blocks (including in-progress ones)
|
| 259 |
from the streaming text.
|
| 260 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
artifacts = []
|
| 262 |
# Match tags: <artifact title="x" type="y" language="z">content</artifact> or open tags at the end of text
|
| 263 |
pattern = r'<artifact\s+title="([^"]*)"\s+type="([^"]*)"\s+language="([^"]*)"\s*>(.*?)(?:</artifact>|$)'
|
|
@@ -280,6 +293,12 @@ def clean_chatbot_response(text: str) -> str:
|
|
| 280 |
Replaces <artifact> blocks in the response with a clean visual badge
|
| 281 |
so the raw code doesn't clutter the main chat viewport.
|
| 282 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
pattern = r'<artifact\s+title="([^"]*)"\s+type="([^"]*)"\s+language="([^"]*)"\s*>.*?(?:</artifact>|$)'
|
| 284 |
|
| 285 |
def replace_with_badge(match):
|
|
|
|
| 239 |
Replaces model <thinking></thinking> tags with clean, modern HTML Details panels
|
| 240 |
for premium rendering in the Gradio chat viewport.
|
| 241 |
"""
|
| 242 |
+
if not isinstance(text, str):
|
| 243 |
+
if isinstance(text, (list, tuple)):
|
| 244 |
+
text = " ".join(str(x) for x in text)
|
| 245 |
+
else:
|
| 246 |
+
text = str(text) if text is not None else ""
|
| 247 |
+
|
| 248 |
if "<thinking>" in text:
|
| 249 |
parts = text.split("<thinking>", 1)
|
| 250 |
before_thinking = parts[0]
|
|
|
|
| 258 |
else:
|
| 259 |
# Thinking block is still generating, render it open
|
| 260 |
return f"{before_thinking}<details open class='thinking-block'><summary>Thinking Process...</summary>\n\n{rest.strip()}\n\n</details>"
|
| 261 |
+
return text
|
| 262 |
|
| 263 |
def extract_artifacts(text: str) -> list:
|
| 264 |
"""
|
| 265 |
Extracts all <artifact> blocks (including in-progress ones)
|
| 266 |
from the streaming text.
|
| 267 |
"""
|
| 268 |
+
if not isinstance(text, str):
|
| 269 |
+
if isinstance(text, (list, tuple)):
|
| 270 |
+
text = " ".join(str(x) for x in text)
|
| 271 |
+
else:
|
| 272 |
+
text = str(text) if text is not None else ""
|
| 273 |
+
|
| 274 |
artifacts = []
|
| 275 |
# Match tags: <artifact title="x" type="y" language="z">content</artifact> or open tags at the end of text
|
| 276 |
pattern = r'<artifact\s+title="([^"]*)"\s+type="([^"]*)"\s+language="([^"]*)"\s*>(.*?)(?:</artifact>|$)'
|
|
|
|
| 293 |
Replaces <artifact> blocks in the response with a clean visual badge
|
| 294 |
so the raw code doesn't clutter the main chat viewport.
|
| 295 |
"""
|
| 296 |
+
if not isinstance(text, str):
|
| 297 |
+
if isinstance(text, (list, tuple)):
|
| 298 |
+
text = " ".join(str(x) for x in text)
|
| 299 |
+
else:
|
| 300 |
+
text = str(text) if text is not None else ""
|
| 301 |
+
|
| 302 |
pattern = r'<artifact\s+title="([^"]*)"\s+type="([^"]*)"\s+language="([^"]*)"\s*>.*?(?:</artifact>|$)'
|
| 303 |
|
| 304 |
def replace_with_badge(match):
|