tarujain8's picture
initial deploy
a613e88
Raw
History Blame Contribute Delete
3.04 kB
import json
import re
from typing import Any
def safe_invoke(llm, prompt: str) -> str:
"""
Safely invoke any LangChain LLM and always return a string.
Handles:
- AIMessage (ChatOpenAI, etc.)
- raw string outputs
- dict / list responses
"""
if not prompt or not isinstance(prompt, str):
raise ValueError("Prompt must be a non-empty string")
try:
response = llm.invoke(prompt)
# Case 1: Chat models (AIMessage)
if hasattr(response, "content"):
return str(response.content)
# Case 2: Already string
if isinstance(response, str):
return response
# Case 3: dict / list → stringify safely
return json.dumps(response, indent=2)
except Exception as e:
return f"[LLM_ERROR] {str(e)}"
# ---------------------------------------------------
def safe_json_parse(text: str) -> dict:
"""
Try to parse LLM output into JSON safely.
If fails, return fallback structure.
"""
if not isinstance(text, str):
return {
"error": "Invalid JSON from model",
"raw_output": text,
}
candidates = []
stripped = text.strip()
candidates.append(stripped)
fence_match = re.search(r"```(?:json)?\s*(.*?)\s*```", stripped, re.DOTALL | re.IGNORECASE)
if fence_match:
candidates.append(fence_match.group(1).strip())
first_object = stripped.find("{")
last_object = stripped.rfind("}")
if first_object != -1 and last_object != -1 and last_object > first_object:
candidates.append(stripped[first_object:last_object + 1].strip())
first_array = stripped.find("[")
last_array = stripped.rfind("]")
if first_array != -1 and last_array != -1 and last_array > first_array:
candidates.append(stripped[first_array:last_array + 1].strip())
seen = set()
for candidate in candidates:
if not candidate or candidate in seen:
continue
seen.add(candidate)
try:
return json.loads(candidate)
except Exception:
continue
return {
"error": "Invalid JSON from model",
"raw_output": text
}
# ---------------------------------------------------
def safe_merge(*args: Any) -> str:
"""
Safely merge multiple inputs into one string.
Handles:
- None
- dict
- list
- string
"""
merged_parts = []
for arg in args:
if arg is None:
continue
if isinstance(arg, (dict, list)):
merged_parts.append(json.dumps(arg, indent=2))
else:
merged_parts.append(str(arg))
return "\n".join(merged_parts)
# ---------------------------------------------------
def safe_input(text: Any, fallback: str) -> str:
"""
Normalize optional user inputs (chat / feelings).
"""
if text is None:
return fallback
if isinstance(text, str) and text.strip() == "":
return fallback
return str(text)