ics-simlab-config-gen-claude/services/response_extract.py

70 lines
2.3 KiB
Python

from __future__ import annotations
import json
from typing import Any, List, Optional, Tuple
def _pick_json_like_text(texts: List[str]) -> str:
candidates = [t.strip() for t in texts if isinstance(t, str) and t.strip()]
for t in reversed(candidates):
s = t.lstrip()
if s.startswith("{") or s.startswith("["):
return t
return candidates[-1] if candidates else ""
def extract_json_string_from_response(resp: Any) -> Tuple[str, Optional[str]]:
"""
Try to extract a JSON object either from structured 'json' content parts,
or from text content parts.
Returns: (raw_json_string, error_message_or_None)
"""
out_text = getattr(resp, "output_text", None)
if isinstance(out_text, str) and out_text.strip():
s = out_text.lstrip()
if s.startswith("{") or s.startswith("["):
return out_text, None
outputs = getattr(resp, "output", None) or []
texts: List[str] = []
for item in outputs:
content = getattr(item, "content", None)
if content is None and isinstance(item, dict):
content = item.get("content")
if not content:
continue
for part in content:
ptype = getattr(part, "type", None)
if ptype is None and isinstance(part, dict):
ptype = part.get("type")
if ptype == "refusal":
refusal_msg = getattr(part, "refusal", None)
if refusal_msg is None and isinstance(part, dict):
refusal_msg = part.get("refusal")
return "", f"Model refusal: {refusal_msg}"
j = getattr(part, "json", None)
if j is None and isinstance(part, dict):
j = part.get("json")
if j is not None:
try:
return json.dumps(j, ensure_ascii=False), None
except Exception as e:
return "", f"Failed to serialize json content part: {e}"
t = getattr(part, "text", None)
if t is None and isinstance(part, dict):
t = part.get("text")
if isinstance(t, str) and t.strip():
texts.append(t)
raw = _pick_json_like_text(texts)
if raw:
return raw, None
return "", "Empty output (no json/text content parts found)"