hermes / api_client.py
Googolplexic's picture
Documentation
08a6cc3
import requests
import json
def parse_key_value_string(key_value_string):
"""Parse a key-value string into a dictionary (meant for API arguments).
Parameters:
- key_value_string: String with key-value pairs, one per line, separated by ':'
Returns:
- Dictionary of parsed key-value pairs
"""
result = {}
if not key_value_string:
return result
lines = key_value_string.strip().split("\n")
for line in lines:
if ":" in line:
key, value = line.split(":", 1)
key = key.strip()
value = value.strip()
if key: # Only add non-empty keys
# Try to parse numeric values
if value.isdigit():
result[key] = int(value)
elif value.lower() == "true":
result[key] = True
elif value.lower() == "false":
result[key] = False
else:
result[key] = value
return result
def call_api(
method="GET",
base_url=None,
endpoint=None,
param_keys_values=None,
header_keys_values=None,
additional_params=None,
):
"""Make an API call to fetch data with dynamic headers and parameters.
Parameters:
- method: HTTP method to use (GET, POST, PUT, DELETE)
- base_url: The base URL of the API
- endpoint: The specific API endpoint
- param_keys_values: Parameter key-value pairs, one per line
- header_keys_values: Header key-value pairs, one per line
- additional_params: Optional JSON string for complex parameters
Examples:
1. Simple GET request to a search API:
method: "GET"
base_url: "https://v2.xivapi.com/api"
endpoint: "search"
param_keys_values:
query: Name~"popoto"
sheets: Item
fields: Name,Description
language: en
limit: 1
2. GitHub API request with headers:
method: "GET"
base_url: "https://api.github.com"
endpoint: "repos/microsoft/TypeScript/issues"
param_keys_values:
state: open
per_page: 5
header_keys_values:
Accept: application/vnd.github.v3+json
3. POST request with JSON body. the "messages" parameter is complexly structured, so it requires special handling."
method: "POST"
base_url: "https://api.anthropic.com"
endpoint: "v1/messages"
param_keys_values:
model: claude-opus-4-20250514
max_tokens: 1024
header_keys_values:
x-api-key: your_api_key_here
content-type: application/json
additional_params: {"messages": [{"role": "user", "content": "Hello there!"}]}
"""
# Build params and headers dictionaries from key-value pairs
params = parse_key_value_string(param_keys_values)
headers = parse_key_value_string(header_keys_values)
# Handle additional parameters
if additional_params and additional_params.strip():
try:
# Parse additional JSON parameters
extra_params = json.loads(additional_params)
if isinstance(extra_params, dict):
params.update(extra_params)
else:
return "Error: Additional parameters must be a valid JSON object"
except json.JSONDecodeError as e:
return f"Error parsing additional parameters: {str(e)}"
try:
client = APIClient(base_url)
result = client.make_request(
endpoint=endpoint,
params=params,
headers=headers,
method=method,
)
return result
except Exception as e:
return f"Error making API call: {str(e)}"
class APIClient:
def __init__(self, base_url):
"""
Initialize the API client with a base URL
Parameters:
- base_url: The base URL of the API
"""
self.base_url = base_url.rstrip("/")
def make_request(self, endpoint="", params=None, headers=None, method="GET"):
"""
Make an HTTP request to the API endpoint.
Parameters:
- endpoint: API endpoint (without leading slash)
- params: Dictionary of parameters to include in the request
- headers: Dictionary of headers to include in the request
- method: HTTP method (GET, POST, PUT, DELETE)
Returns:
- String representation of the API response
"""
url = f"{self.base_url}/{endpoint.lstrip('/')}" if endpoint else self.base_url
# Initialize headers dictionary if None
if headers is None:
headers = {}
try:
if method.upper() == "GET":
response = requests.get(url, params=params, headers=headers)
elif method.upper() == "POST":
response = requests.post(url, json=params, headers=headers)
elif method.upper() == "PUT":
response = requests.put(url, json=params, headers=headers)
elif method.upper() == "DELETE":
response = requests.delete(url, json=params, headers=headers)
else:
return f"Unsupported method: {method}"
# Check if the response is successful
response.raise_for_status()
# Try to parse JSON response
try:
result = response.json()
return json.dumps(result, indent=2)
except ValueError:
# Return raw text if not JSON
return response.text
except requests.exceptions.RequestException as e:
return f"Request error: {str(e)}"