add kia ai chat tools7
CI/CD Pipeline / build-and-deploy (push) Successful in 18s Details

This commit is contained in:
vahidrezvani 2026-02-25 12:34:16 +03:30
parent 9217a54b35
commit e6f7f33a09
1 changed files with 43 additions and 9 deletions

View File

@ -25,21 +25,18 @@ def _to_openai_messages(messages: list[BaseMessage]) -> list[dict]:
Supports multimodal HumanMessages where content is already a list Supports multimodal HumanMessages where content is already a list
(e.g. [{"type": "text", "text": "..."}, {"type": "image_url", ...}]). (e.g. [{"type": "text", "text": "..."}, {"type": "image_url", ...}]).
For plain text-only content lists, normalizes to a plain string.
""" """
result = [] result = []
for msg in messages: for msg in messages:
if isinstance(msg, SystemMessage): if isinstance(msg, SystemMessage):
result.append({"role": "system", "content": msg.content}) result.append({"role": "system", "content": _normalize_content(msg.content)})
elif isinstance(msg, HumanMessage): elif isinstance(msg, HumanMessage):
# content may be a plain string or a multimodal list result.append({"role": "user", "content": _normalize_content(msg.content)})
if isinstance(msg.content, list):
result.append({"role": "user", "content": msg.content})
else:
result.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage): elif isinstance(msg, AIMessage):
result.append({"role": "assistant", "content": msg.content}) result.append({"role": "assistant", "content": _normalize_content(msg.content)})
elif isinstance(msg, ToolMessage): elif isinstance(msg, ToolMessage):
result.append({ result.append({
@ -54,6 +51,28 @@ def _to_openai_messages(messages: list[BaseMessage]) -> list[dict]:
return result return result
def _normalize_content(content) -> str | list:
"""
If content is a list containing only text-type items, return plain string.
If it contains images or other types, return the list as-is (multimodal).
"""
if isinstance(content, str):
return content
if isinstance(content, list):
# Check if all items are plain text type
is_text_only = all(
isinstance(item, dict) and item.get("type") == "text"
for item in content
)
if is_text_only:
return " ".join(item.get("text", "") for item in content)
# Multimodal — keep as list
return content
return str(content)
class KiaAIService: class KiaAIService:
""" """
Service for calling KIA AI models directly via httpx SSE streaming. Service for calling KIA AI models directly via httpx SSE streaming.
@ -92,7 +111,17 @@ class KiaAIService:
print(f"[KiaAI] POST {url}") print(f"[KiaAI] POST {url}")
print(f"[KiaAI] messages_count={len(messages)} | reasoning_effort={reasoning_effort}") print(f"[KiaAI] messages_count={len(messages)} | reasoning_effort={reasoning_effort}")
print(f"[KiaAI] payload (no content): { {k: v for k, v in payload.items() if k != 'messages'} }")
openai_messages = _to_openai_messages(messages)
for i, m in enumerate(openai_messages):
content_preview = m["content"][:120] if isinstance(m["content"], str) else str(m["content"])[:120]
print(f"[KiaAI] msg[{i}] role={m['role']} | content={content_preview!r}")
payload: dict = {"messages": openai_messages}
# Add reasoning_effort only for models that support it
if reasoning_effort and model_name in REASONING_MODELS:
payload["reasoning_effort"] = reasoning_effort
full_content = "" full_content = ""
usage: dict = {} usage: dict = {}
@ -116,7 +145,6 @@ class KiaAIService:
if not line.strip(): if not line.strip():
continue continue
# SSE lines: "data: {...}" or "data: [DONE]" or raw JSON
raw_data = line.removeprefix("data:").strip() raw_data = line.removeprefix("data:").strip()
if raw_data == "[DONE]": if raw_data == "[DONE]":
@ -129,6 +157,12 @@ class KiaAIService:
print(f"[KiaAI] Skipping non-JSON line: {raw_data!r}") print(f"[KiaAI] Skipping non-JSON line: {raw_data!r}")
continue continue
# KIA server error inside stream
if chunk.get("code") and chunk["code"] != 200:
error_msg = chunk.get("msg", "Unknown KIA error")
print(f"[KiaAI] Server error in stream: code={chunk['code']} msg={error_msg!r}")
raise RuntimeError(f"KIA API error {chunk['code']}: {error_msg}")
print(f"[KiaAI] CHUNK keys={list(chunk.keys())} choices={chunk.get('choices')}") print(f"[KiaAI] CHUNK keys={list(chunk.keys())} choices={chunk.get('choices')}")
choices = chunk.get("choices") or [] choices = chunk.get("choices") or []