AQIT 0.1.0
Loading...
Searching...
No Matches
llm_json.py
Go to the documentation of this file.
1# Copyright (c) 2025-present Aquin Labs Private Limited. All Rights Reserved.
2"""Parse JSON objects from LLM chat responses."""
3from __future__ import annotations
4
5import json
6import re
7from typing import Any
8
9
10def parse_llm_json_object(raw: str) -> dict[str, Any]:
11 """Extract the first JSON object from an LLM reply (handles fences and trailing text)."""
12 text = (raw or "").strip()
13 if not text:
14 raise ValueError("empty response")
15
16 if text.startswith("```"):
17 parts = text.split("```")
18 if len(parts) >= 2:
19 text = parts[1].strip()
20 if text.lower().startswith("json"):
21 text = text[4:].lstrip()
22
23 start = text.find("{")
24 if start == -1:
25 raise ValueError("no JSON object found")
26 text = text[start:]
27
28 try:
29 obj, _ = json.JSONDecoder().raw_decode(text)
30 except json.JSONDecodeError:
31 match = re.search(r"\{[\s\S]*\}", text)
32 if not match:
33 raise
34 obj, _ = json.JSONDecoder().raw_decode(match.group(0))
35
36 if not isinstance(obj, dict):
37 raise ValueError("expected JSON object")
38 return obj
39
40
41def sentence_lists_from_llm(raw: str) -> tuple[list[str], list[str]]:
42 """Parse positive/negative sentence lists from an LLM JSON reply."""
43 data = parse_llm_json_object(raw)
44 positive = _as_str_list(data.get("positive"))
45 negative = _as_str_list(data.get("negative"))
46 if not positive and not negative:
47 raise ValueError("empty sentence lists")
48 return positive, negative
49
50
51def _as_str_list(value: Any) -> list[str]:
52 if not isinstance(value, list):
53 return []
54 return [str(item).strip() for item in value if str(item).strip()]
56
58 """User-facing message when LLM example generation fails."""
59 return (
60 "Could not generate example sentences for this feature. "
61 "Try again in a moment, or use a larger --corpus."
62 )
63
64
65def chat_json_completion(client: Any, **kwargs: Any) -> Any:
66 """Chat completion preferring JSON object mode, with a plain fallback."""
67 try:
68 return client.chat.completions.create(
69 **kwargs,
70 response_format={"type": "json_object"},
71 )
72 except Exception:
73 kwargs.pop("response_format", None)
74 return client.chat.completions.create(**kwargs)
tuple[list[str], list[str]] sentence_lists_from_llm(str raw)
Definition llm_json.py:45
list[str] _as_str_list(Any value)
Definition llm_json.py:55
Any chat_json_completion(Any client, **Any kwargs)
Definition llm_json.py:69
dict[str, Any] parse_llm_json_object(str raw)
Definition llm_json.py:14
str llm_sentence_generation_error()
Definition llm_json.py:61