Spaces:
Sleeping
Sleeping
GitHub Actions commited on
Commit Β·
33950ca
1
Parent(s): 0ab7e48
Deploy 607a293
Browse files- app/pipeline/nodes/generate.py +85 -70
app/pipeline/nodes/generate.py
CHANGED
|
@@ -264,9 +264,12 @@ def make_generate_node(llm_client: LLMClient, gemini_client=None) -> Callable[[P
|
|
| 264 |
complexity="simple",
|
| 265 |
)
|
| 266 |
full_answer = ""
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
|
|
|
|
|
|
|
|
|
| 270 |
return {"answer": full_answer, "sources": source_refs, "path": "enumeration"}
|
| 271 |
|
| 272 |
# ββ Not-found path ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -337,73 +340,85 @@ def make_generate_node(llm_client: LLMClient, gemini_client=None) -> Callable[[P
|
|
| 337 |
token_chunk_count = 0 # number of token chunks received
|
| 338 |
think_first_emitted = False # CoT first-sentence status already sent
|
| 339 |
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
if
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
# ββ Strip CoT scratchpad β single canonical pass ββββββββββββββββββββββ
|
| 409 |
# _strip_think_tags is the ONLY think-tag removal in the codebase.
|
|
|
|
| 264 |
complexity="simple",
|
| 265 |
)
|
| 266 |
full_answer = ""
|
| 267 |
+
try:
|
| 268 |
+
async for token in stream:
|
| 269 |
+
full_answer += token
|
| 270 |
+
writer({"type": "token", "text": token})
|
| 271 |
+
except (Exception, asyncio.CancelledError) as exc:
|
| 272 |
+
logger.warning("Enumeration stream interrupted: %s / Returning partial answer.", exc)
|
| 273 |
return {"answer": full_answer, "sources": source_refs, "path": "enumeration"}
|
| 274 |
|
| 275 |
# ββ Not-found path ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 340 |
token_chunk_count = 0 # number of token chunks received
|
| 341 |
think_first_emitted = False # CoT first-sentence status already sent
|
| 342 |
|
| 343 |
+
try:
|
| 344 |
+
async for token in stream:
|
| 345 |
+
raw_answer += token
|
| 346 |
+
token_chunk_count += 1
|
| 347 |
+
|
| 348 |
+
if think_done or no_cot:
|
| 349 |
+
# Phase 2: emit all but the last _TAG_BOUNDARY_WINDOW chars so that
|
| 350 |
+
# a split closing tag ("</thi" in chunk N, "nk>" in chunk N+1) is
|
| 351 |
+
# always buffered until complete before routing to the token event.
|
| 352 |
+
phase2_buf += token
|
| 353 |
+
if len(phase2_buf) > _TAG_BOUNDARY_WINDOW:
|
| 354 |
+
emit_part = phase2_buf[:-_TAG_BOUNDARY_WINDOW]
|
| 355 |
+
phase2_buf = phase2_buf[-_TAG_BOUNDARY_WINDOW:]
|
| 356 |
+
writer({"type": "token", "text": emit_part})
|
| 357 |
+
continue
|
| 358 |
+
|
| 359 |
+
buf += token
|
| 360 |
+
|
| 361 |
+
if not in_think:
|
| 362 |
+
if "<think>" in buf:
|
| 363 |
+
in_think = True
|
| 364 |
+
pre = buf[: buf.index("<think>")]
|
| 365 |
+
if pre.strip():
|
| 366 |
+
# Text before the think tag is part of the answer.
|
| 367 |
+
writer({"type": "token", "text": pre})
|
| 368 |
+
buf = buf[buf.index("<think>") + 7:] # 7 = len("<think>")
|
| 369 |
+
elif token_chunk_count >= _THINK_LOOKAHEAD:
|
| 370 |
+
# No CoT block in first 50 chunks β emit buffered and go direct.
|
| 371 |
+
no_cot = True
|
| 372 |
+
writer({"type": "token", "text": buf})
|
| 373 |
+
buf = ""
|
| 374 |
+
else:
|
| 375 |
+
# Phase 1: inside the <think> block; buffer until </think>.
|
| 376 |
+
if "</think>" in buf:
|
| 377 |
+
idx = buf.index("</think>")
|
| 378 |
+
think_txt = buf[:idx].strip()
|
| 379 |
+
after_think = buf[idx + 9:] # 9 = len("</think>")
|
| 380 |
+
|
| 381 |
+
if think_txt and not think_first_emitted:
|
| 382 |
+
# Surface the first sentence as a legible status label.
|
| 383 |
+
for j, ch in enumerate(think_txt):
|
| 384 |
+
if ch in ".?!\n":
|
| 385 |
+
first_sent = think_txt[: j + 1].strip()[:120]
|
| 386 |
+
writer({"type": "status", "label": first_sent})
|
| 387 |
+
think_first_emitted = True
|
| 388 |
+
break
|
| 389 |
+
|
| 390 |
+
if think_txt:
|
| 391 |
+
writer({"type": "thinking", "text": think_txt})
|
| 392 |
+
|
| 393 |
+
think_done = True
|
| 394 |
+
buf = ""
|
| 395 |
+
if after_think.strip():
|
| 396 |
+
writer({"type": "token", "text": after_think})
|
| 397 |
+
|
| 398 |
+
# Flush Phase 2 tail buffer β strip any orphaned closing think tags that
|
| 399 |
+
# arrived in the final window before emitting to the client.
|
| 400 |
+
if phase2_buf:
|
| 401 |
+
clean_tail = _THINK_CLOSE_RE.sub("", phase2_buf)
|
| 402 |
+
if clean_tail:
|
| 403 |
+
writer({"type": "token", "text": clean_tail})
|
| 404 |
+
|
| 405 |
+
# Flush Phase 1 / lookahead buffer if stream ended mid-detection.
|
| 406 |
+
# Apply canonical strip so an incomplete opening tag doesn't surface.
|
| 407 |
+
if buf:
|
| 408 |
+
clean_buf = _strip_think_tags(buf)
|
| 409 |
+
if clean_buf:
|
| 410 |
+
writer({"type": "token", "text": clean_buf})
|
| 411 |
+
except (Exception, asyncio.CancelledError) as exc:
|
| 412 |
+
logger.warning("Generation stream interrupted: %s / Returning partial answer.", exc)
|
| 413 |
+
# Flush whatever we have if the stream was cut
|
| 414 |
+
if buf:
|
| 415 |
+
clean_buf = _strip_think_tags(buf)
|
| 416 |
+
if clean_buf:
|
| 417 |
+
writer({"type": "token", "text": clean_buf})
|
| 418 |
+
if phase2_buf:
|
| 419 |
+
clean_tail = _THINK_CLOSE_RE.sub("", phase2_buf)
|
| 420 |
+
if clean_tail:
|
| 421 |
+
writer({"type": "token", "text": clean_tail})
|
| 422 |
|
| 423 |
# ββ Strip CoT scratchpad β single canonical pass ββββββββββββββββββββββ
|
| 424 |
# _strip_think_tags is the ONLY think-tag removal in the codebase.
|