PutuAPI / app /utils /parser.py
suzmen's picture
Upload 64 files
2af6ef5 verified
"""PhantomAPI — Tool-call parser.
Extracts structured tool-call JSON from ChatGPT's free-form text
responses, converting them into OpenAI-compatible function call objects.
"""
import json
import re
import uuid
def parse_tool_calls(response_text: str) -> list[dict] | None:
"""Attempt to extract tool_calls JSON from the response text.
Returns a list of OpenAI-compatible tool-call dicts, or None if
no valid tool calls were found.
"""
cleaned = response_text.strip()
# Strip markdown code fences if present
if "```" in cleaned:
match = re.search(r"```(?:json)?\s*\n?(.*?)\n?\s*```", cleaned, re.DOTALL)
if match:
cleaned = match.group(1).strip()
# Build candidate strings to try parsing
candidates = [cleaned]
json_match = re.search(r'\{[\s\S]*"tool_calls"[\s\S]*\}', cleaned)
if json_match:
candidates.append(json_match.group(0))
for candidate in candidates:
try:
parsed = json.loads(candidate)
if isinstance(parsed, dict) and "tool_calls" in parsed:
raw_calls = parsed["tool_calls"]
if isinstance(raw_calls, list) and len(raw_calls) > 0:
return _format_calls(raw_calls)
except (json.JSONDecodeError, TypeError, KeyError):
continue
return None
def _format_calls(raw_calls: list[dict]) -> list[dict]:
"""Convert raw parsed tool calls into the OpenAI function-call schema."""
formatted = []
for call in raw_calls:
tool_name = call.get("name", "")
arguments = call.get("arguments", {})
arguments_str = (
json.dumps(arguments, ensure_ascii=False)
if isinstance(arguments, dict)
else str(arguments)
)
formatted.append(
{
"id": f"call_{uuid.uuid4().hex[:24]}",
"type": "function",
"function": {
"name": tool_name,
"arguments": arguments_str,
},
}
)
return formatted