add kia ai chat tools16
CI/CD Pipeline / build-and-deploy (push) Successful in 19s
Details
CI/CD Pipeline / build-and-deploy (push) Successful in 19s
Details
This commit is contained in:
parent
b94402df6b
commit
1ece942eba
|
|
@ -122,6 +122,10 @@ class KiaAIService:
|
||||||
Core SSE parser — yields one AIMessageChunk per content delta token.
|
Core SSE parser — yields one AIMessageChunk per content delta token.
|
||||||
Final chunk: AIMessageChunk(content="", usage_metadata={...}).
|
Final chunk: AIMessageChunk(content="", usage_metadata={...}).
|
||||||
Raises RuntimeError on KIA server errors (triggers retry in stream()).
|
Raises RuntimeError on KIA server errors (triggers retry in stream()).
|
||||||
|
|
||||||
|
Uses aiter_bytes(chunk_size=32) instead of aiter_lines() so every
|
||||||
|
byte received from the network is processed immediately without
|
||||||
|
waiting for httpx's internal 64 KB read buffer to fill up.
|
||||||
"""
|
"""
|
||||||
usage: dict = {}
|
usage: dict = {}
|
||||||
|
|
||||||
|
|
@ -139,57 +143,69 @@ class KiaAIService:
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
||||||
line_count = 0
|
line_count = 0
|
||||||
async for line in resp.aiter_lines():
|
buf = ""
|
||||||
line_count += 1
|
done = False
|
||||||
if line_count <= 3:
|
|
||||||
print(f"[KiaAI] raw[{line_count}]: {line!r}")
|
|
||||||
|
|
||||||
if not line:
|
async for raw in resp.aiter_bytes(chunk_size=32):
|
||||||
continue
|
buf += raw.decode("utf-8", errors="replace")
|
||||||
|
|
||||||
|
while "\n" in buf:
|
||||||
|
line, buf = buf.split("\n", 1)
|
||||||
|
line = line.rstrip("\r")
|
||||||
|
line_count += 1
|
||||||
|
if line_count <= 3:
|
||||||
|
print(f"[KiaAI] raw[{line_count}]: {line!r}")
|
||||||
|
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Non-data lines may carry KIA error JSON
|
||||||
|
if not line.startswith("data:"):
|
||||||
|
try:
|
||||||
|
err = json.loads(line)
|
||||||
|
code = err.get("code")
|
||||||
|
if code and int(code) >= 400:
|
||||||
|
msg = err.get("msg", "Unknown error")
|
||||||
|
print(f"[KiaAI] Error line: code={code} msg={msg!r}")
|
||||||
|
raise RuntimeError(f"KIA error {code}: {msg}")
|
||||||
|
except (json.JSONDecodeError, ValueError):
|
||||||
|
pass
|
||||||
|
print(f"[KiaAI] non-data line: {line!r}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
raw_data = line[6:] if line.startswith("data: ") else line[5:]
|
||||||
|
|
||||||
|
if raw_data.strip() == "[DONE]":
|
||||||
|
print("[KiaAI] [DONE]")
|
||||||
|
done = True
|
||||||
|
break
|
||||||
|
|
||||||
# Non-data lines may carry KIA error JSON
|
|
||||||
if not line.startswith("data:"):
|
|
||||||
try:
|
try:
|
||||||
err = json.loads(line)
|
data = json.loads(raw_data)
|
||||||
code = err.get("code")
|
except json.JSONDecodeError:
|
||||||
if code and int(code) >= 400:
|
print(f"[KiaAI] JSON decode error: {raw_data!r}")
|
||||||
msg = err.get("msg", "Unknown error")
|
continue
|
||||||
print(f"[KiaAI] Error line: code={code} msg={msg!r}")
|
|
||||||
raise RuntimeError(f"KIA error {code}: {msg}")
|
|
||||||
except (json.JSONDecodeError, ValueError):
|
|
||||||
pass
|
|
||||||
print(f"[KiaAI] non-data line: {line!r}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
raw_data = line[6:] if line.startswith("data: ") else line[5:]
|
# KIA server error embedded in stream body
|
||||||
|
if data.get("code") and int(data["code"]) >= 500:
|
||||||
|
msg = data.get("msg", "Unknown error")
|
||||||
|
print(f"[KiaAI] Error chunk: {data['code']} {msg!r}")
|
||||||
|
raise RuntimeError(f"KIA error {data['code']}: {msg}")
|
||||||
|
|
||||||
if raw_data.strip() == "[DONE]":
|
# Yield content tokens
|
||||||
print("[KiaAI] [DONE]")
|
for choice in (data.get("choices") or []):
|
||||||
|
delta = choice.get("delta") or {}
|
||||||
|
token = delta.get("content") or ""
|
||||||
|
if token:
|
||||||
|
yield AIMessageChunk(content=token)
|
||||||
|
|
||||||
|
# Capture usage from final summary chunk
|
||||||
|
if data.get("usage"):
|
||||||
|
usage = data["usage"]
|
||||||
|
|
||||||
|
if done:
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
|
||||||
data = json.loads(raw_data)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
print(f"[KiaAI] JSON decode error: {raw_data!r}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# KIA server error embedded in stream body
|
|
||||||
if data.get("code") and int(data["code"]) >= 500:
|
|
||||||
msg = data.get("msg", "Unknown error")
|
|
||||||
print(f"[KiaAI] Error chunk: {data['code']} {msg!r}")
|
|
||||||
raise RuntimeError(f"KIA error {data['code']}: {msg}")
|
|
||||||
|
|
||||||
# Yield content tokens
|
|
||||||
for choice in (data.get("choices") or []):
|
|
||||||
delta = choice.get("delta") or {}
|
|
||||||
token = delta.get("content") or ""
|
|
||||||
if token:
|
|
||||||
yield AIMessageChunk(content=token)
|
|
||||||
|
|
||||||
# Capture usage from final summary chunk
|
|
||||||
if data.get("usage"):
|
|
||||||
usage = data["usage"]
|
|
||||||
|
|
||||||
# Final chunk carries usage metadata
|
# Final chunk carries usage metadata
|
||||||
print(f"[KiaAI] Stream done | total_lines={line_count} | usage={usage}")
|
print(f"[KiaAI] Stream done | total_lines={line_count} | usage={usage}")
|
||||||
yield AIMessageChunk(
|
yield AIMessageChunk(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue