hermes-agent / api_functions.py
D3AMON's picture
Upload api_functions.py with huggingface_hub
383fb6a verified
Raw History Blame Contribute Delete
77.8 kB
"""
Comprehensive API Functions for Hermes Agent
These are the executable tools that the Hermes LLM can call.
Each function has a clear docstring so the LLM knows when and how to use it.
"""
import requests
import json
import os
import random
from typing import Dict, List, Optional, Any, Union
from datetime import datetime, timedelta
# ============================================================
# UTILITY FUNCTIONS
# ============================================================
def _safe_get(url: str, params: dict = None, headers: dict = None, timeout: int = 15) -> dict:
"""Safely make a GET request and return JSON"""
try:
response = requests.get(url, params=params, headers=headers, timeout=timeout)
response.raise_for_status()
return response.json() if response.text else {"status": "success", "data": ""}
except Exception as e:
return {"error": str(e), "url": url}
def _safe_post(url: str, data: dict = None, json_data: dict = None, headers: dict = None, timeout: int = 15) -> dict:
"""Safely make a POST request and return JSON"""
try:
response = requests.post(url, data=data, json=json_data, headers=headers, timeout=timeout)
response.raise_for_status()
return response.json() if response.text else {"status": "success"}
except Exception as e:
return {"error": str(e), "url": url}
# ============================================================
# ANIMALS
# ============================================================
def get_random_dog(breed: str = None) -> dict:
"""
Get a random dog image. Optionally specify a breed.
Args:
breed: Dog breed (e.g., 'labrador', 'bulldog', 'beagle'). Leave empty for random.
Returns:
dict: Contains message (image URL) and status
"""
if breed:
url = f"https://dog.ceo/api/breed/{breed}/images/random"
else:
url = "https://dog.ceo/api/breeds/image/random"
result = _safe_get(url)
if "message" in result and result.get("status") == "success":
return {"image_url": result["message"], "breed": breed or "random"}
return result
def get_dog_breeds() -> dict:
"""Get a list of all available dog breeds"""
return _safe_get("https://dog.ceo/api/breeds/list/all")
def get_random_cat(fact_only: bool = False) -> dict:
"""
Get a random cat fact or image
Args:
fact_only: If True, returns only a fact. If False, returns both fact and image.
"""
fact_result = _safe_get("https://catfact.ninja/fact")
if fact_only:
return fact_result
# Also get a random cat image
image_result = _safe_get("https://api.thecatapi.com/v1/images/search")
return {
"fact": fact_result.get("fact", ""),
"fact_length": fact_result.get("length", 0),
"image": image_result[0] if isinstance(image_result, list) and image_result else None
}
def get_random_fox() -> dict:
"""Get a random fox image URL"""
result = _safe_get("https://randomfox.ca/floof")
return result
def get_random_duck() -> dict:
"""Get a random duck image and message"""
return _safe_get("https://random-d.uk/api/random")
def get_shibe(count: int = 1) -> dict:
"""
Get random Shiba Inu images
Args:
count: Number of images (1-100)
"""
result = _safe_get(f"https://shibe.online/api/shibes?count={min(count, 100)}")
return {"images": result if isinstance(result, list) else []}
# ============================================================
# ANIME
# ============================================================
def search_anime(query: str, limit: int = 5) -> dict:
"""
Search for anime by title
Args:
query: Anime title or keyword
limit: Maximum number of results
Returns:
dict: List of matching anime with details
"""
result = _safe_get(f"https://api.jikan.moe/v4/anime?q={query}&limit={limit}")
if "data" in result:
animes = []
for anime in result["data"]:
animes.append({
"title": anime.get("title", ""),
"title_english": anime.get("title_english", ""),
"episodes": anime.get("episodes"),
"score": anime.get("score"),
"status": anime.get("status"),
"synopsis": anime.get("synopsis", "")[:200] if anime.get("synopsis") else "",
"url": anime.get("url", ""),
"image": anime.get("images", {}).get("jpg", {}).get("image_url", "")
})
return {"results": animes, "count": len(animes)}
return result
def get_anime_details(anime_id: int) -> dict:
"""
Get detailed information about a specific anime
Args:
anime_id: The MyAnimeList ID of the anime
"""
return _safe_get(f"https://api.jikan.moe/v4/anime/{anime_id}/full")
def get_top_anime(limit: int = 10) -> dict:
"""
Get top ranked anime
Args:
limit: Number of results (max 25)
"""
result = _safe_get(f"https://api.jikan.moe/v4/top/anime?limit={min(limit, 25)}")
if "data" in result:
return {"top_anime": [{"rank": a.get("rank"), "title": a.get("title"),
"score": a.get("score"), "episodes": a.get("episodes")}
for a in result["data"]]}
return result
def get_current_season_anime() -> dict:
"""Get anime currently airing this season"""
return _safe_get("https://api.jikan.moe/v4/seasons/now")
def get_random_anime_quote() -> dict:
"""Get a random anime quote"""
# Try waifu.pics for sfw anime image
result = _safe_get("https://api.waifu.pics/sfw/waifu")
return result
# ============================================================
# ART & CULTURE
# ============================================================
def search_artworks(query: str = "", limit: int = 5) -> dict:
"""
Search artworks from the Art Institute of Chicago
Args:
query: Search term (artist, title, etc.)
limit: Number of results
"""
if query:
url = f"https://api.artic.edu/api/v1/artworks/search?q={query}&limit={limit}&fields=id,title,artist_display,date_display,medium_display,image_id"
else:
url = f"https://api.artic.edu/api/v1/artworks?limit={limit}&fields=id,title,artist_display,date_display,medium_display,image_id"
result = _safe_get(url)
if "data" in result:
iiif_url = result.get("config", {}).get("iiif_url", "https://www.artic.edu/iiif/2")
artworks = []
for art in result["data"]:
img_url = f"{iiif_url}/{art.get('image_id')}/full/400,/0/default.jpg" if art.get("image_id") else None
artworks.append({
"title": art.get("title", ""),
"artist": art.get("artist_display", ""),
"date": art.get("date_display", ""),
"medium": art.get("medium_display", ""),
"image_url": img_url
})
return {"artworks": artworks, "total": result.get("pagination", {}).get("total", 0)}
return result
def search_met_museum(query: str) -> dict:
"""
Search the Metropolitan Museum of Art collection
Args:
query: Search term
"""
search_result = _safe_get(f"https://collectionapi.metmuseum.org/public/collection/v1/search?q={query}&hasImages=true")
if "objectIDs" in search_result and search_result["objectIDs"]:
objects = []
for obj_id in search_result["objectIDs"][:5]:
obj = _safe_get(f"https://collectionapi.metmuseum.org/public/collection/v1/objects/{obj_id}")
if "objectID" in obj:
objects.append({
"title": obj.get("title", ""),
"artist": obj.get("artistDisplayName", ""),
"department": obj.get("department", ""),
"date": obj.get("objectDate", ""),
"medium": obj.get("medium", ""),
"image": obj.get("primaryImageSmall", "")
})
return {"objects": objects, "total_results": search_result.get("total", 0)}
return search_result
# ============================================================
# BOOKS
# ============================================================
def search_books(query: str, limit: int = 5) -> dict:
"""
Search books on Open Library
Args:
query: Book title, author, or ISBN
limit: Maximum results
"""
result = _safe_get(f"https://openlibrary.org/search.json?q={query}&limit={limit}")
if "docs" in result:
books = []
for book in result["docs"][:limit]:
books.append({
"title": book.get("title", ""),
"author": book.get("author_name", ["Unknown"])[0] if book.get("author_name") else "Unknown",
"first_publish": book.get("first_publish_year"),
"isbn": book.get("isbn", [""])[0] if book.get("isbn") else "",
"pages": book.get("number_of_pages_median"),
"subjects": book.get("subject", [])[:3],
"cover_id": book.get("cover_i"),
"openlibrary_key": book.get("key", "")
})
return {"books": books, "total_found": result.get("numFound", 0)}
return result
def get_book_by_isbn(isbn: str) -> dict:
"""
Get book details by ISBN
Args:
isbn: ISBN-10 or ISBN-13
"""
return _safe_get(f"https://openlibrary.org/isbn/{isbn}.json")
def get_random_quote(category: str = None) -> dict:
"""
Get a random quote
Args:
category: Optional category like 'life', 'love', 'inspirational', 'science'
"""
if category:
result = _safe_get(f"https://api.quotable.io/quotes/random?tags={category}")
else:
result = _safe_get("https://api.quotable.io/quotes/random")
if isinstance(result, list) and result:
q = result[0]
return {
"quote": q.get("content", ""),
"author": q.get("author", ""),
"tags": q.get("tags", [])
}
return result
def get_quote_of_the_day() -> dict:
"""Get today's inspirational quote"""
result = _safe_get("https://zenquotes.io/api/today")
if isinstance(result, list) and result:
q = result[0]
return {"quote": q.get("q", ""), "author": q.get("a", "")}
return result
def get_random_gutenberg_book(limit: int = 5) -> dict:
"""
Get random books from Project Gutenberg
Args:
limit: Number of books
"""
result = _safe_get(f"https://gutendex.com/books/?page={random.randint(1, 100)}")
if "results" in result:
books = []
for book in result["results"][:limit]:
books.append({
"title": book.get("title", ""),
"authors": [a.get("name") for a in book.get("authors", [])],
"languages": book.get("languages", []),
"download_count": book.get("download_count"),
"subjects": book.get("subjects", [])[:3],
"formats": {k: v for k, v in list(book.get("formats", {}).items())[:2]}
})
return {"books": books}
return result
# ============================================================
# CRYPTO
# ============================================================
def get_crypto_price(coin_id: str = "bitcoin", currency: str = "usd") -> dict:
"""
Get cryptocurrency price and market data
Args:
coin_id: Coin ID (bitcoin, ethereum, cardano, solana, etc.)
currency: Price currency (usd, eur, gbp)
"""
result = _safe_get(f"https://api.coingecko.com/api/v3/coins/{coin_id}?localization=false&tickers=false&market_data=true&community_data=false&developer_data=false")
if "market_data" in result:
md = result["market_data"]
return {
"name": result.get("name", ""),
"symbol": result.get("symbol", "").upper(),
"current_price": md.get("current_price", {}).get(currency.lower()),
"market_cap": md.get("market_cap", {}).get(currency.lower()),
"24h_high": md.get("high_24h", {}).get(currency.lower()),
"24h_low": md.get("low_24h", {}).get(currency.lower()),
"24h_change_percent": md.get("price_change_percentage_24h"),
"7d_change_percent": md.get("price_change_percentage_7d"),
"30d_change_percent": md.get("price_change_percentage_30d"),
"circulating_supply": md.get("circulating_supply"),
"total_supply": md.get("total_supply"),
"max_supply": md.get("max_supply"),
"last_updated": md.get("last_updated")
}
return result
def get_trending_crypto() -> dict:
"""Get top 7 trending cryptocurrencies in the last 24 hours"""
result = _safe_get("https://api.coingecko.com/api/v3/search/trending")
if "coins" in result:
coins = []
for coin in result["coins"]:
item = coin.get("item", {})
coins.append({
"rank": coin.get("item", {}).get("market_cap_rank"),
"name": item.get("name"),
"symbol": item.get("symbol"),
"thumb": item.get("thumb"),
"price_btc": item.get("price_btc"),
"score": item.get("score")
})
return {"trending": coins}
return result
def get_global_crypto_data() -> dict:
"""Get global cryptocurrency market data"""
result = _safe_get("https://api.coingecko.com/api/v3/global")
if "data" in result:
d = result["data"]
return {
"active_cryptocurrencies": d.get("active_cryptocurrencies"),
"markets": d.get("markets"),
"total_market_cap_usd": d.get("total_market_cap", {}).get("usd"),
"total_volume_24h_usd": d.get("total_volume", {}).get("usd"),
"market_cap_change_24h": d.get("market_cap_change_percentage_24h_usd"),
"btc_dominance": d.get("market_cap_percentage", {}).get("btc"),
"eth_dominance": d.get("market_cap_percentage", {}).get("eth"),
}
return result
def get_bitcoin_data() -> dict:
"""Get Bitcoin-specific data including blockchain stats"""
result = _safe_get("https://api.blockchain.info/stats")
return result
def convert_crypto(amount: float, from_currency: str = "bitcoin", to_currency: str = "usd") -> dict:
"""
Convert cryptocurrency to fiat or another crypto
Args:
amount: Amount to convert
from_currency: Source currency ID
to_currency: Target currency ID
"""
result = _safe_get(f"https://api.coingecko.com/api/v3/simple/price?ids={from_currency}&vs_currencies={to_currency}")
if from_currency in result and to_currency in result[from_currency]:
rate = result[from_currency][to_currency]
converted = amount * rate
return {
"amount": amount,
"from": from_currency,
"to": to_currency,
"rate": rate,
"converted_amount": converted
}
return result
# ============================================================
# CURRENCY
# ============================================================
def convert_currency(amount: float, from_currency: str = "USD", to_currency: str = "EUR") -> dict:
"""
Convert currency using latest exchange rates
Args:
amount: Amount to convert
from_currency: 3-letter currency code (USD, EUR, GBP, etc.)
to_currency: 3-letter currency code
"""
result = _safe_get(f"https://api.exchangerate-api.com/v4/latest/{from_currency.upper()}")
if "rates" in result and to_currency.upper() in result["rates"]:
rate = result["rates"][to_currency.upper()]
converted = amount * rate
return {
"amount": amount,
"from": from_currency.upper(),
"to": to_currency.upper(),
"rate": rate,
"converted_amount": round(converted, 4),
"date": result.get("date")
}
return result
def get_exchange_rates(base: str = "USD") -> dict:
"""
Get latest exchange rates for a base currency
Args:
base: Base currency code (USD, EUR, etc.)
"""
return _safe_get(f"https://api.exchangerate-api.com/v4/latest/{base.upper()}")
# ============================================================
# DEVELOPMENT & TECH
# ============================================================
def github_search(query: str, type: str = "repositories", limit: int = 5) -> dict:
"""
Search GitHub for repositories, users, or code
Args:
query: Search query
type: 'repositories', 'users', or 'code'
limit: Number of results
"""
headers = {"Accept": "application/vnd.github.v3+json"}
result = _safe_get(f"https://api.github.com/search/{type}?q={query}&per_page={limit}", headers=headers)
if "items" in result:
items = []
for item in result["items"][:limit]:
if type == "repositories":
items.append({
"name": item.get("full_name"),
"description": item.get("description", "")[:100],
"stars": item.get("stargazers_count"),
"language": item.get("language"),
"url": item.get("html_url"),
"updated": item.get("updated_at")
})
elif type == "users":
items.append({
"username": item.get("login"),
"url": item.get("html_url"),
"avatar": item.get("avatar_url"),
"type": item.get("type")
})
return {"results": items, "total_count": result.get("total_count", 0)}
return result
def get_github_user(username: str) -> dict:
"""
Get GitHub user profile information
Args:
username: GitHub username
"""
return _safe_get(f"https://api.github.com/users/{username}")
def get_stackoverflow_questions(tag: str = None, limit: int = 5) -> dict:
"""
Get recent Stack Overflow questions
Args:
tag: Filter by tag (e.g., 'python', 'javascript')
limit: Number of questions
"""
url = f"https://api.stackexchange.com/2.3/questions?order=desc&sort=votes&pagesize={limit}&site=stackoverflow"
if tag:
url += f"&tagged={tag}"
result = _safe_get(url)
if "items" in result:
questions = []
for q in result["items"]:
questions.append({
"title": q.get("title"),
"link": q.get("link"),
"score": q.get("score"),
"answer_count": q.get("answer_count"),
"view_count": q.get("view_count"),
"tags": q.get("tags", []),
"asked": datetime.fromtimestamp(q.get("creation_date", 0)).isoformat() if q.get("creation_date") else ""
})
return {"questions": questions}
return result
# ============================================================
# DICTIONARY
# ============================================================
def define_word(word: str) -> dict:
"""
Get the definition of a word
Args:
word: The word to define
"""
result = _safe_get(f"https://api.dictionaryapi.dev/api/v2/entries/en/{word.lower()}")
if isinstance(result, list) and result:
entry = result[0]
meanings = []
for meaning in entry.get("meanings", []):
definitions = [d.get("definition", "") for d in meaning.get("definitions", [])[:3]]
meanings.append({
"part_of_speech": meaning.get("partOfSpeech"),
"definitions": definitions
})
phonetics = entry.get("phonetics", [])
audio = next((p.get("audio") for p in phonetics if p.get("audio")), None)
return {
"word": entry.get("word"),
"phonetic": entry.get("phonetic"),
"audio": audio,
"meanings": meanings,
"origin": entry.get("etymology", [""])[0] if entry.get("etymology") else ""
}
return {"word": word, "error": "Word not found", "suggestions": result}
# ============================================================
# ENVIRONMENT & WEATHER
# ============================================================
def get_weather_forecast(latitude: float = 51.5074, longitude: float = -0.1278, days: int = 7) -> dict:
"""
Get weather forecast for any location worldwide using Open-Meteo (no API key needed)
Args:
latitude: Location latitude
longitude: Location longitude
days: Number of forecast days (1-16)
"""
url = (f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}"
f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,windspeed_10m_max,"
f"sunrise,sunset,weathercode&hourly=temperature_2m,relativehumidity_2m,apparent_temperature,"
f"precipitation,weathercode,cloudcover,windspeed_10m"
f"&timezone=auto&forecast_days={min(days, 16)}")
result = _safe_get(url)
if "daily" in result:
daily = result["daily"]
forecast = []
for i in range(len(daily.get("time", []))):
forecast.append({
"date": daily["time"][i],
"temp_max_c": daily["temperature_2m_max"][i],
"temp_min_c": daily["temperature_2m_min"][i],
"precipitation_mm": daily["precipitation_sum"][i],
"wind_max_kmh": daily.get("windspeed_10m_max", [None]*len(daily["time"]))[i],
"sunrise": daily.get("sunrise", [None]*len(daily["time"]))[i] if daily.get("sunrise") else None,
"sunset": daily.get("sunset", [None]*len(daily["time"]))[i] if daily.get("sunset") else None,
})
current = result.get("hourly", {})
current_idx = 0 if current.get("time") else None
return {
"location": {
"latitude": result.get("latitude"),
"longitude": result.get("longitude"),
"timezone": result.get("timezone"),
"elevation": result.get("elevation")
},
"current_hour": {
"temperature_c": current.get("temperature_2m", [None])[current_idx] if current_idx is not None else None,
"humidity_percent": current.get("relativehumidity_2m", [None])[current_idx] if current_idx is not None else None,
"feels_like_c": current.get("apparent_temperature", [None])[current_idx] if current_idx is not None else None,
} if current_idx is not None else None,
"daily_forecast": forecast,
"weather_codes": {
0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
45: "Fog", 48: "Depositing rime fog",
51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle",
61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain",
71: "Slight snow", 73: "Moderate snow", 75: "Heavy snow",
77: "Snow grains", 80: "Slight rain showers", 81: "Moderate rain showers",
82: "Violent rain showers", 95: "Thunderstorm", 96: "Thunderstorm with hail"
}
}
return result
def get_weather_by_city(city: str) -> dict:
"""
Get weather for a city by name (uses geocoding first)
Args:
city: City name (e.g., 'London', 'New York', 'Tokyo')
"""
# First geocode the city
geo = _safe_get(f"https://geocoding-api.open-meteo.com/v1/search?name={city}&count=1&language=en&format=json")
if "results" in geo and geo["results"]:
location = geo["results"][0]
lat = location.get("latitude")
lon = location.get("longitude")
name = location.get("name")
country = location.get("country")
weather = get_weather_forecast(lat, lon, days=7)
weather["searched_city"] = city
weather["resolved_location"] = f"{name}, {country}"
return weather
return {"error": f"Could not find city: {city}"}
def get_air_quality(latitude: float = 51.5074, longitude: float = -0.1278) -> dict:
"""
Get current air quality data
Args:
latitude: Location latitude
longitude: Location longitude
"""
url = (f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={latitude}&longitude={longitude}"
f"&current=us_aqi,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,ozone"
f"&timezone=auto")
result = _safe_get(url)
if "current" in result:
c = result["current"]
aqi = c.get("us_aqi")
quality = "Good" if aqi <= 50 else "Moderate" if aqi <= 100 else "Unhealthy for Sensitive" if aqi <= 150 else "Unhealthy" if aqi <= 200 else "Very Unhealthy" if aqi <= 300 else "Hazardous"
return {
"aqi_us": aqi,
"quality": quality,
"pm2_5": c.get("pm2_5"),
"pm10": c.get("pm10"),
"co": c.get("carbon_monoxide"),
"no2": c.get("nitrogen_dioxide"),
"o3": c.get("ozone"),
"time": c.get("time")
}
return result
def get_iss_location() -> dict:
"""Get current location of the International Space Station"""
result = _safe_get("http://api.open-notify.org/iss-now.json")
if "iss_position" in result:
lat = float(result["iss_position"].get("latitude", 0))
lon = float(result["iss_position"].get("longitude", 0))
# Get geographic location name
geo = _safe_get(f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json")
return {
"latitude": lat,
"longitude": lon,
"timestamp": result.get("timestamp"),
"over_location": geo.get("display_name", "Unknown location (likely over ocean)"),
"timezone": geo.get("address", {}).get("country", "Unknown")
}
return result
def get_astronauts_in_space() -> dict:
"""Get list of astronauts currently in space"""
return _safe_get("http://api.open-notify.org/astros.json")
def get_nasa_apod() -> dict:
"""
Get NASA's Astronomy Picture of the Day
"""
# Try without API key first (rate limited)
result = _safe_get("https://api.nasa.gov/planetary/apod")
if "code" in result and result.get("code") == 403:
return {"error": "NASA API key required for repeated use", "info": "Visit https://api.nasa.gov to get a free API key"}
return result
def get_space_x_launches(limit: int = 5, upcoming: bool = False) -> dict:
"""
Get SpaceX launch data
Args:
limit: Number of launches
upcoming: If True, show upcoming launches. If False, show past launches.
"""
if upcoming:
result = _safe_get("https://api.spacexdata.com/v4/launches/upcoming")
else:
result = _safe_get(f"https://api.spacexdata.com/v4/launches/past?limit={limit}&order=desc")
if isinstance(result, list):
launches = []
for launch in result[:limit]:
launches.append({
"name": launch.get("name"),
"date": launch.get("date_utc"),
"success": launch.get("success"),
"details": (launch.get("details") or "")[:200],
"rocket": launch.get("rocket"),
"launchpad": launch.get("launchpad"),
"links": {
"webcast": launch.get("links", {}).get("webcast"),
"article": launch.get("links", {}).get("article"),
"wikipedia": launch.get("links", {}).get("wikipedia")
}
})
return {"launches": launches}
return result
# ============================================================
# FOOD & DRINK
# ============================================================
def search_meal(name: str = None, ingredient: str = None, category: str = None) -> dict:
"""
Search for meal recipes
Args:
name: Meal name to search for
ingredient: Filter by main ingredient
category: Category like 'Seafood', 'Vegetarian', 'Dessert', 'Chicken'
"""
if name:
result = _safe_get(f"https://www.themealdb.com/api/json/v1/1/search.php?s={name}")
elif ingredient:
result = _safe_get(f"https://www.themealdb.com/api/json/v1/1/filter.php?i={ingredient}")
elif category:
result = _safe_get(f"https://www.themealdb.com/api/json/v1/1/filter.php?c={category}")
else:
result = _safe_get("https://www.themealdb.com/api/json/v1/1/random.php")
meals = result.get("meals", [])
if meals and name: # Full details available
m = meals[0]
ingredients = []
for i in range(1, 21):
ing = m.get(f"strIngredient{i}")
measure = m.get(f"strMeasure{i}")
if ing and ing.strip():
ingredients.append(f"{measure} {ing}".strip())
return {
"name": m.get("strMeal"),
"category": m.get("strCategory"),
"area": m.get("strArea"),
"instructions": m.get("strInstructions", "")[:500],
"image": m.get("strMealThumb"),
"youtube": m.get("strYoutube"),
"source": m.get("strSource"),
"ingredients": ingredients,
}
elif meals:
return {"meals": [{"name": m.get("strMeal"), "id": m.get("idMeal"), "image": m.get("strMealThumb")} for m in meals[:10]]}
return result
def get_random_meal() -> dict:
"""Get a random meal recipe with full details"""
return search_meal()
def search_cocktail(name: str = None, ingredient: str = None) -> dict:
"""
Search cocktail recipes
Args:
name: Cocktail name
ingredient: Filter by ingredient (e.g., 'vodka', 'gin', 'rum')
"""
if name:
result = _safe_get(f"https://www.thecocktaildb.com/api/json/v1/1/search.php?s={name}")
elif ingredient:
result = _safe_get(f"https://www.thecocktaildb.com/api/json/v1/1/filter.php?i={ingredient}")
else:
result = _safe_get("https://www.thecocktaildb.com/api/json/v1/1/random.php")
drinks = result.get("drinks", [])
if drinks and name:
d = drinks[0]
ingredients = []
for i in range(1, 16):
ing = d.get(f"strIngredient{i}")
measure = d.get(f"strMeasure{i}")
if ing and ing.strip():
ingredients.append(f"{measure} {ing}".strip())
return {
"name": d.get("strDrink"),
"category": d.get("strCategory"),
"alcoholic": d.get("strAlcoholic"),
"glass": d.get("strGlass"),
"instructions": d.get("strInstructions", "")[:500],
"image": d.get("strDrinkThumb"),
"ingredients": ingredients,
}
elif drinks:
return {"drinks": [{"name": d.get("strDrink"), "id": d.get("idDrink"), "image": d.get("strDrinkThumb")} for d in drinks[:10]]}
return result
def get_random_cocktail() -> dict:
"""Get a random cocktail recipe"""
return search_cocktail()
def get_random_coffee_image() -> dict:
"""Get a random coffee image"""
return _safe_get("https://coffee.alexflipnote.dev/random.json")
# ============================================================
# GAMES
# ============================================================
def get_pokemon(name_or_id: str = "1") -> dict:
"""
Get Pokemon data by name or Pokedex number
Args:
name_or_id: Pokemon name (e.g., 'pikachu') or ID number
"""
result = _safe_get(f"https://pokeapi.co/api/v2/pokemon/{name_or_id.lower()}")
if "name" in result:
types = [t.get("type", {}).get("name", "") for t in result.get("types", [])]
abilities = [a.get("ability", {}).get("name", "") for a in result.get("abilities", [])]
stats = {s.get("stat", {}).get("name", ""): s.get("base_stat") for s in result.get("stats", [])}
return {
"name": result.get("name", "").title(),
"id": result.get("id"),
"height_dm": result.get("height"),
"weight_hg": result.get("weight"),
"types": types,
"abilities": abilities,
"stats": stats,
"image_front": result.get("sprites", {}).get("other", {}).get("official-artwork", {}).get("front_default"),
"image_back": result.get("sprites", {}).get("back_default"),
"base_experience": result.get("base_experience"),
}
return result
def get_random_pokemon() -> dict:
"""Get a random Pokemon"""
random_id = random.randint(1, 1010)
return get_pokemon(str(random_id))
def get_pokemon_by_type(pokemon_type: str) -> dict:
"""
Get Pokemon by type
Args:
pokemon_type: Pokemon type (e.g., 'fire', 'water', 'grass', 'electric')
"""
result = _safe_get(f"https://pokeapi.co/api/v2/type/{pokemon_type.lower()}")
if "pokemon" in result:
pokemon_list = [p.get("pokemon", {}).get("name", "").title() for p in result["pokemon"][:20]]
return {
"type": pokemon_type.title(),
"pokemon_count": len(result["pokemon"]),
"examples": pokemon_list
}
return result
def get_dnd_class(class_name: str = None) -> dict:
"""
Get D&D 5e class information
Args:
class_name: Class name (barbarian, bard, cleric, druid, fighter, monk, paladin, ranger, rogue, sorcerer, warlock, wizard)
"""
if class_name:
return _safe_get(f"https://www.dnd5eapi.co/api/classes/{class_name.lower()}")
return _safe_get("https://www.dnd5eapi.co/api/classes")
def get_dnd_monster(name_or_index: str) -> dict:
"""
Get D&D 5e monster information
Args:
name_or_index: Monster name or index
"""
return _safe_get(f"https://www.dnd5eapi.co/api/monsters/{name_or_index.lower()}")
def get_dnd_spell(name_or_index: str) -> dict:
"""
Get D&D 5e spell information
Args:
name_or_index: Spell name or index
"""
return _safe_get(f"https://www.dnd5eapi.co/api/spells/{name_or_index.lower()}")
def get_chess_profile(username: str) -> dict:
"""
Get Chess.com player profile
Args:
username: Chess.com username
"""
result = _safe_get(f"https://api.chess.com/pub/player/{username.lower()}")
if "username" in result:
return {
"username": result.get("username"),
"player_id": result.get("player_id"),
"title": result.get("title"),
"status": result.get("status"),
"name": result.get("name"),
"avatar": result.get("avatar"),
"location": result.get("location"),
"country": result.get("country"),
"joined": datetime.fromtimestamp(result.get("joined", 0)).isoformat() if result.get("joined") else None,
"last_online": datetime.fromtimestamp(result.get("last_online", 0)).isoformat() if result.get("last_online") else None,
"followers": result.get("followers"),
"is_streamer": result.get("is_streamer"),
}
return result
def draw_cards(count: int = 1) -> dict:
"""
Draw cards from a deck
Args:
count: Number of cards to draw (1-52)
"""
# First get a deck
deck = _safe_get("https://deckofcardsapi.com/api/deck/new/shuffle/?deck_count=1")
if "deck_id" in deck:
deck_id = deck["deck_id"]
result = _safe_get(f"https://deckofcardsapi.com/api/deck/{deck_id}/draw/?count={min(count, 52)}")
if "cards" in result:
return {
"cards": [{"value": c.get("value"), "suit": c.get("suit"), "image": c.get("image")} for c in result["cards"]],
"remaining": result.get("remaining")
}
return deck
# ============================================================
# GEOCODING & LOCATION
# ============================================================
def geocode_location(query: str) -> dict:
"""
Convert address/place name to coordinates
Args:
query: Address or place name
"""
result = _safe_get(f"https://nominatim.openstreetmap.org/search?q={query}&format=json&limit=1")
if isinstance(result, list) and result:
loc = result[0]
return {
"name": loc.get("display_name"),
"latitude": float(loc.get("lat", 0)),
"longitude": float(loc.get("lon", 0)),
"type": loc.get("type"),
"importance": loc.get("importance"),
"osm_id": loc.get("osm_id")
}
return {"error": "Location not found"}
def reverse_geocode(latitude: float, longitude: float) -> dict:
"""
Convert coordinates to address
Args:
latitude: Latitude
longitude: Longitude
"""
result = _safe_get(f"https://nominatim.openstreetmap.org/reverse?lat={latitude}&lon={longitude}&format=json")
if "display_name" in result:
return {
"address": result.get("display_name"),
"address_details": result.get("address"),
"type": result.get("type"),
"osm_id": result.get("osm_id")
}
return result
def get_my_ip() -> dict:
"""Get your public IP address and basic geolocation"""
return _safe_get("https://ipapi.co/json")
# ============================================================
# JOKES & ENTERTAINMENT
# ============================================================
def get_joke(category: str = "Any", safe_mode: bool = True) -> dict:
"""
Get a random joke
Args:
category: 'Any', 'Programming', 'Misc', 'Dark', 'Pun', 'Spooky', 'Christmas'
safe_mode: If True, exclude explicit jokes
"""
flags = "&blacklistFlags=nsfw,religious,political,racist,sexist,explicit" if safe_mode else ""
result = _safe_get(f"https://v2.jokeapi.dev/joke/{category}?type=single{flags}")
if "joke" in result:
return {"joke": result["joke"], "category": result.get("category"), "safe": result.get("safe")}
elif "setup" in result and "delivery" in result:
return {"setup": result["setup"], "delivery": result["delivery"], "category": result.get("category")}
return result
def get_chuck_norris_joke(category: str = None) -> dict:
"""
Get a Chuck Norris joke
Args:
category: Optional category (animal, career, celebrity, dev, fashion, food, history, money, movie, music, political, religion, science, sport, travel)
"""
if category:
result = _safe_get(f"https://api.chucknorris.io/jokes/random?category={category}")
else:
result = _safe_get("https://api.chucknorris.io/jokes/random")
if "value" in result:
return {"joke": result["value"], "url": result.get("url"), "categories": result.get("categories", [])}
return result
def get_chuck_norris_categories() -> dict:
"""Get available Chuck Norris joke categories"""
return _safe_get("https://api.chucknorris.io/jokes/categories")
def get_random_meme(subreddit: str = None) -> dict:
"""
Get a random meme
Args:
subreddit: Specific subreddit (e.g., 'memes', 'dankmemes', 'wholesomememes')
"""
if subreddit:
result = _safe_get(f"https://meme-api.com/gimme/{subreddit}")
else:
result = _safe_get("https://meme-api.com/gimme")
if "url" in result:
return {
"title": result.get("title"),
"url": result.get("url"),
"author": result.get("author"),
"subreddit": result.get("subreddit"),
"ups": result.get("ups"),
"permalink": result.get("postLink")
}
return result
def get_rick_and_morty_character(name_or_id: str = "1") -> dict:
"""
Get Rick and Morty character info
Args:
name_or_id: Character ID number or name
"""
if name_or_id.isdigit():
result = _safe_get(f"https://rickandmortyapi.com/api/character/{name_or_id}")
else:
search = _safe_get(f"https://rickandmortyapi.com/api/character/?name={name_or_id}")
if "results" in search and search["results"]:
result = search["results"][0]
else:
return search
if "name" in result:
return {
"name": result.get("name"),
"status": result.get("status"),
"species": result.get("species"),
"type": result.get("type") or "None",
"gender": result.get("gender"),
"origin": result.get("origin", {}).get("name"),
"location": result.get("location", {}).get("name"),
"image": result.get("image"),
"episodes_appeared": len(result.get("episode", []))
}
return result
def get_random_activity(participants: int = None, type: str = None) -> dict:
"""
Get a random activity suggestion
Args:
participants: Number of participants (1-8)
type: Activity type (education, recreational, social, diy, charity, cooking, relaxation, music, busywork)
"""
params = []
if participants:
params.append(f"participants={participants}")
if type:
params.append(f"type={type}")
query = "&" + "&".join(params) if params else ""
return _safe_get(f"https://www.boredapi.com/api/activity{query}")
def get_useless_fact() -> dict:
"""Get a random useless but interesting fact"""
return _safe_get("https://uselessfacts.jsph.pl/api/v2/facts/random")
# ============================================================
# MUSIC
# ============================================================
def get_song_lyrics(artist: str, title: str) -> dict:
"""
Get song lyrics
Args:
artist: Song artist name
title: Song title
"""
result = _safe_get(f"https://api.lyrics.ovh/v1/{artist}/{title}")
if "lyrics" in result:
return {
"artist": artist,
"title": title,
"lyrics": result["lyrics"][:1000] if len(result["lyrics"]) > 1000 else result["lyrics"]
}
return {"error": "Lyrics not found", "artist": artist, "title": title}
def search_lastfm(artist: str = None, method: str = "artist.search") -> dict:
"""
Search Last.fm for music
Args:
artist: Artist name
method: 'artist.search', 'artist.getinfo', 'artist.gettoptracks', 'chart.gettopartists'
"""
# Using a demo key - users should get their own for production
api_key = os.getenv("LASTFM_API_KEY", "demo")
if method == "artist.search":
url = f"https://ws.audioscrobbler.com/2.0/?method=artist.search&artist={artist}&api_key={api_key}&format=json"
elif method == "artist.getinfo":
url = f"https://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist={artist}&api_key={api_key}&format=json"
elif method == "artist.gettoptracks":
url = f"https://ws.audioscrobbler.com/2.0/?method=artist.gettoptracks&artist={artist}&api_key={api_key}&format=json"
elif method == "chart.gettopartists":
url = f"https://ws.audioscrobbler.com/2.0/?method=chart.gettopartists&api_key={api_key}&format=json"
else:
return {"error": f"Unknown method: {method}"}
return _safe_get(url)
# ============================================================
# NEWS
# ============================================================
def get_hacker_news(story_type: str = "top", limit: int = 5) -> dict:
"""
Get top stories from Hacker News
Args:
story_type: 'top', 'new', 'best', 'ask', 'show', 'job'
limit: Number of stories
"""
ids = _safe_get(f"https://hacker-news.firebaseio.com/v0/{story_type}stories.json")
if isinstance(ids, list):
stories = []
for story_id in ids[:limit]:
story = _safe_get(f"https://hacker-news.firebaseio.com/v0/item/{story_id}.json")
if story:
stories.append({
"title": story.get("title"),
"url": story.get("url"),
"score": story.get("score"),
"author": story.get("by"),
"comments": story.get("descendants"),
"time": datetime.fromtimestamp(story.get("time", 0)).isoformat() if story.get("time") else ""
})
return {"stories": stories}
return ids
def get_space_news(limit: int = 5) -> dict:
"""
Get latest space-related news
Args:
limit: Number of articles
"""
result = _safe_get(f"https://api.spaceflightnewsapi.net/v4/articles/?limit={limit}")
if "results" in result:
articles = []
for article in result["results"]:
articles.append({
"title": article.get("title"),
"summary": article.get("summary", "")[:200] if article.get("summary") else "",
"url": article.get("url"),
"published": article.get("published_at"),
"source": article.get("news_site"),
"image": article.get("image_url")
})
return {"articles": articles, "count": len(articles)}
return result
# ============================================================
# QUOTES
# ============================================================
def get_breaking_bad_quote(count: int = 1) -> dict:
"""
Get quotes from Breaking Bad
Args:
count: Number of quotes
"""
result = _safe_get(f"https://api.breakingbadquotes.xyz/v1/quotes/{count}")
if isinstance(result, list):
return {"quotes": result}
return result
def get_game_of_thrones_quote() -> dict:
"""Get a random Game of Thrones quote"""
result = _safe_get("https://api.gameofthronesquotes.xyz/v1/random")
if isinstance(result, dict) and "sentence" in result:
return {
"quote": result.get("sentence"),
"character": result.get("character", {}).get("name"),
"house": result.get("character", {}).get("house", {}).get("name")
}
return result
def get_zen_quote() -> dict:
"""Get a random inspirational zen quote"""
result = _safe_get("https://zenquotes.io/api/random")
if isinstance(result, list) and result:
q = result[0]
return {"quote": q.get("q"), "author": q.get("a"), "html": q.get("h")}
return result
def get_ron_swanson_quote(count: int = 1) -> dict:
"""
Get Ron Swanson quotes
Args:
count: Number of quotes (1-50)
"""
result = _safe_get(f"https://ron-swanson-quotes.herokuapp.com/v2/quotes/{count}")
if isinstance(result, list):
return {"quotes": result}
return result
# ============================================================
# SPORTS
# ============================================================
def get_football_standings(league_code: str = "PL") -> dict:
"""
Get football league standings
Args:
league_code: League code (PL=Premier League, BL1=Bundesliga, SA=Serie A, PD=La Liga, FL1=Ligue 1, CL=Champions League)
"""
# Using football-data.org demo - users need their own API key for production
api_key = os.getenv("FOOTBALL_DATA_KEY", "")
headers = {"X-Auth-Token": api_key} if api_key else {}
result = _safe_get(f"https://api.football-data.org/v4/competitions/{league_code}/standings", headers=headers)
if "standings" in result:
table = result["standings"][0].get("table", [])
standings = []
for team in table[:20]:
standings.append({
"position": team.get("position"),
"team": team.get("team", {}).get("name"),
"played": team.get("playedGames"),
"won": team.get("won"),
"draw": team.get("draw"),
"lost": team.get("lost"),
"points": team.get("points"),
"goals_for": team.get("goalsFor"),
"goals_against": team.get("goalsAgainst"),
"goal_difference": team.get("goalDifference"),
})
return {
"league": result.get("competition", {}).get("name"),
"season": result.get("season", {}).get("startDate"),
"standings": standings
}
return result
def get_nba_games(date: str = None) -> dict:
"""
Get NBA games for a specific date or today
Args:
date: Date in YYYY-MM-DD format. Leave empty for today.
"""
if not date:
date = datetime.now().strftime("%Y-%m-%d")
result = _safe_get(f"https://www.balldontlie.io/api/v1/games?dates[]={date}")
if "data" in result:
games = []
for game in result["data"]:
games.append({
"home_team": game.get("home_team", {}).get("full_name"),
"away_team": game.get("visitor_team", {}).get("full_name"),
"home_score": game.get("home_team_score"),
"away_score": game.get("visitor_team_score"),
"status": game.get("status"),
"time": game.get("time"),
"date": game.get("date"),
"season": game.get("season"),
"period": game.get("period"),
})
return {"date": date, "games": games, "count": len(games)}
return result
def get_f1_results(season: int = None, round_num: int = None) -> dict:
"""
Get Formula 1 race results
Args:
season: Year (e.g., 2024). Leave empty for current season.
round_num: Race round number. Leave empty for season standings.
"""
if season and round_num:
url = f"https://ergast.com/api/f1/{season}/{round_num}/results.json"
elif season:
url = f"https://ergast.com/api/f1/{season}/driverStandings.json"
else:
url = "https://ergast.com/api/f1/current/driverStandings.json"
result = _safe_get(url)
if "MRData" in result and "StandingsTable" in result["MRData"]:
standings_lists = result["MRData"]["StandingsTable"].get("StandingsLists", [])
if standings_lists:
standings = []
for standing in standings_lists[0].get("DriverStandings", []):
driver = standing.get("Driver", {})
constructors = standing.get("Constructors", [{}])
standings.append({
"position": standing.get("position"),
"points": standing.get("points"),
"wins": standing.get("wins"),
"driver": f"{driver.get('givenName', '')} {driver.get('familyName', '')}",
"number": driver.get("permanentNumber"),
"nationality": driver.get("nationality"),
"constructor": constructors[0].get("name") if constructors else ""
})
return {"season": season or "current", "standings": standings}
if "MRData" in result and "RaceTable" in result["MRData"]:
races = result["MRData"]["RaceTable"].get("Races", [])
if races:
race = races[0]
results = []
for r in race.get("Results", []):
results.append({
"position": r.get("position"),
"driver": f"{r.get('Driver', {}).get('givenName', '')} {r.get('Driver', {}).get('familyName', '')}",
"constructor": r.get("Constructor", {}).get("name"),
"time": r.get("Time", {}).get("time") if r.get("Time") else r.get("status"),
"points": r.get("points"),
})
return {
"race": race.get("raceName"),
"circuit": race.get("Circuit", {}).get("circuitName"),
"date": race.get("date"),
"results": results
}
return result
def get_city_bikes(city: str = None) -> dict:
"""
Get bike sharing stations for a city
Args:
city: City name. Leave empty for list of all networks.
"""
if city:
networks = _safe_get("https://api.citybik.es/v2/networks")
if "networks" in networks:
for network in networks["networks"]:
if city.lower() in network.get("location", {}).get("city", "").lower():
return _safe_get(f"https://api.citybik.es/v2/networks/{network.get('id')}")
return {"error": f"No bike sharing found for {city}"}
return _safe_get("https://api.citybik.es/v2/networks")
# ============================================================
# TEST DATA
# ============================================================
def generate_random_user(seed: str = None) -> dict:
"""
Generate a random fake user profile
Args:
seed: Optional seed for reproducible results
"""
url = "https://randomuser.me/api/1.4/"
if seed:
url += f"?seed={seed}"
result = _safe_get(url)
if "results" in result and result["results"]:
user = result["results"][0]
return {
"name": f"{user.get('name', {}).get('first', '')} {user.get('name', {}).get('last', '')}",
"gender": user.get("gender"),
"email": user.get("email"),
"phone": user.get("phone"),
"cell": user.get("cell"),
"location": f"{user.get('location', {}).get('city', '')}, {user.get('location', {}).get('country', '')}",
"age": user.get("dob", {}).get("age"),
"picture": user.get("picture", {}).get("large"),
"username": user.get("login", {}).get("username"),
"uuid": user.get("login", {}).get("uuid"),
}
return result
def generate_fake_data(type: str = "users", count: int = 1) -> dict:
"""
Generate fake data for testing
Args:
type: Data type - 'users', 'addresses', 'banks', 'beers', 'credit_cards', 'products'
count: Number of items (max 100)
"""
result = _safe_get(f"https://fakerapi.it/api/v2/{type}?_quantity={min(count, 100)}")
return result
def get_random_user(count: int = 1) -> dict:
"""
Get random user data
Args:
count: Number of users (1-5000)
"""
return _safe_get(f"https://randomuser.me/api/?results={min(count, 100)}")
# ============================================================
# TEXT UTILITIES
# ============================================================
def translate_text(text: str, target_lang: str = "es", source_lang: str = "en") -> dict:
"""
Translate text using LibreTranslate (free, no API key needed for small usage)
Args:
text: Text to translate
target_lang: Target language code (es, fr, de, it, pt, ru, ja, zh, ar, hi, etc.)
source_lang: Source language code (auto-detected if not specified)
"""
# Try multiple LibreTranslate instances
instances = [
"https://libretranslate.de",
"https://libretranslate.com",
"https://translate.argosopentech.com",
]
for base_url in instances:
try:
result = _safe_post(
f"{base_url}/translate",
json_data={
"q": text,
"source": source_lang if source_lang != "auto" else "auto",
"target": target_lang,
"format": "text"
},
timeout=10
)
if "translatedText" in result:
return {
"original": text,
"translated": result["translatedText"],
"source_language": result.get("detectedLanguage", {}).get("language", source_lang) if "detectedLanguage" in result else source_lang,
"target_language": target_lang
}
except:
continue
return {"error": "Translation service unavailable", "original": text}
def analyze_sentiment(text: str) -> dict:
"""
Analyze sentiment of text
Args:
text: Text to analyze
"""
result = _safe_post("https://text-processing.com/api/sentiment/", data={"text": text})
if "label" in result:
return {
"sentiment": result.get("label"),
"confidence": result.get("probability", {}).get(result.get("label")),
"probabilities": result.get("probability", {})
}
return result
def detect_language(text: str) -> dict:
"""
Detect the language of text
Args:
text: Text to analyze
"""
result = _safe_post("https://libretranslate.de/detect", json_data={"q": text})
if isinstance(result, list) and result:
return {
"language": result[0].get("language"),
"confidence": result[0].get("confidence")
}
return result
# ============================================================
# URL SHORTENING
# ============================================================
def shorten_url(long_url: str) -> dict:
"""
Shorten a URL
Args:
long_url: The URL to shorten
"""
result = _safe_post("https://cleanuri.com/api/v1/shorten", data={"url": long_url})
if "result_url" in result:
return {"original": long_url, "short_url": result["result_url"]}
return result
# ============================================================
# HOLIDAYS
# ============================================================
def get_public_holidays(country_code: str = "US", year: int = None) -> dict:
"""
Get public holidays for a country
Args:
country_code: 2-letter country code (US, GB, CA, AU, DE, FR, JP, etc.)
year: Year (default: current year)
"""
if not year:
year = datetime.now().year
return _safe_get(f"https://date.nager.at/api/v3/publicholidays/{year}/{country_code.upper()}")
def get_country_info(country_code: str) -> dict:
"""
Get information about a country including holiday info
Args:
country_code: 2-letter country code
"""
return _safe_get(f"https://date.nager.at/api/v3/countryinfo/{country_code.upper()}")
def get_available_countries() -> dict:
"""Get list of countries with holiday data available"""
return _safe_get("https://date.nager.at/api/v3/availablecountries")
# ============================================================
# SCIENCE
# ============================================================
def get_element(atomic_number: int = None, symbol: str = None) -> dict:
"""
Get periodic table element data
Args:
atomic_number: Atomic number (1-118)
symbol: Element symbol (H, He, Li, etc.)
"""
if symbol:
result = _safe_get(f"https://periodic-table-elements-info.herokuapp.com/element/atomicSymbol/{symbol.upper()}")
elif atomic_number:
result = _safe_get(f"https://periodic-table-elements-info.herokuapp.com/element/atomicNumber/{atomic_number}")
else:
return {"error": "Please provide atomic_number or symbol"}
if "atomicNumber" in result:
return {
"name": result.get("name"),
"symbol": result.get("atomicSymbol"),
"atomic_number": result.get("atomicNumber"),
"atomic_mass": result.get("atomicMass"),
"category": result.get("groupBlock"),
"period": result.get("period"),
"group": result.get("group"),
"electron_configuration": result.get("electronicConfiguration"),
"discovered_by": result.get("discoveredBy"),
"named_by": result.get("namedBy"),
"summary": result.get("summary", "")[:300] if result.get("summary") else "",
"density": result.get("density"),
"melting_point": result.get("meltingPoint"),
"boiling_point": result.get("boilingPoint"),
}
return result
def get_number_fact(number: int = None, type: str = "trivia") -> dict:
"""
Get an interesting fact about a number
Args:
number: The number (leave empty for random)
type: 'trivia', 'math', 'year', or 'date'
"""
num = str(number) if number else "random"
result = requests.get(f"http://numbersapi.com/{num}/{type}", timeout=10)
if result.status_code == 200:
return {"number": number or "random", "type": type, "fact": result.text}
return {"error": "Could not fetch number fact"}
def get_random_number_fact() -> dict:
"""Get a random interesting number fact"""
return get_number_fact()
# ============================================================
# CODE/PROGRAMMING
# ============================================================
def get_codeforces_user(handle: str) -> dict:
"""
Get Codeforces user profile
Args:
handle: Codeforces handle/username
"""
result = _safe_get(f"https://codeforces.com/api/user.info?handles={handle}")
if "result" in result and result["result"]:
user = result["result"][0]
return {
"handle": user.get("handle"),
"rating": user.get("rating"),
"max_rating": user.get("maxRating"),
"rank": user.get("rank"),
"max_rank": user.get("maxRank"),
"contribution": user.get("contribution"),
"friend_count": user.get("friendOfCount"),
"registration_time": datetime.fromtimestamp(user.get("registrationTimeSeconds", 0)).isoformat() if user.get("registrationTimeSeconds") else None,
"last_online": datetime.fromtimestamp(user.get("lastOnlineTimeSeconds", 0)).isoformat() if user.get("lastOnlineTimeSeconds") else None,
}
return result
def get_codeforces_contests() -> dict:
"""Get list of Codeforces contests"""
return _safe_get("https://codeforces.com/api/contest.list")
# ============================================================
# TV & MOVIES
# ============================================================
def search_tv_show(query: str) -> dict:
"""
Search for TV shows
Args:
query: Show name
"""
result = _safe_get(f"https://api.tvmaze.com/search/shows?q={query}")
if isinstance(result, list):
shows = []
for item in result[:5]:
show = item.get("show", {})
shows.append({
"name": show.get("name"),
"premiered": show.get("premiered"),
"status": show.get("status"),
"language": show.get("language"),
"genres": show.get("genres", []),
"summary": (show.get("summary") or "").replace("<p>", "").replace("</p>", "").replace("<b>", "").replace("</b>", "")[:200],
"rating": show.get("rating", {}).get("average"),
"image": show.get("image", {}).get("medium") if show.get("image") else None,
"network": show.get("network", {}).get("name") if show.get("network") else show.get("webChannel", {}).get("name")
})
return {"shows": shows}
return result
def get_tv_schedule(country: str = "US", date: str = None) -> dict:
"""
Get TV schedule for a country
Args:
country: 2-letter country code
date: Date in YYYY-MM-DD format
"""
if date:
url = f"https://api.tvmaze.com/schedule?country={country}&date={date}"
else:
url = f"https://api.tvmaze.com/schedule?country={country}"
return _safe_get(url)
# ============================================================
# UNIVERSITIES
# ============================================================
def search_universities(name: str = None, country: str = None) -> dict:
"""
Search for universities
Args:
name: University name to search
country: Filter by country
"""
if name and country:
url = f"http://universities.hipolabs.com/search?name={name}&country={country}"
elif name:
url = f"http://universities.hipolabs.com/search?name={name}"
elif country:
url = f"http://universities.hipolabs.com/search?country={country}"
else:
return {"error": "Please provide name or country"}
result = _safe_get(url)
if isinstance(result, list):
return {"universities": [{"name": u.get("name"), "country": u.get("country"), "domains": u.get("domains"), "websites": u.get("web_pages")} for u in result[:20]], "count": len(result)}
return result
# ============================================================
# COLORS
# ============================================================
def get_random_color() -> dict:
"""Get a random color with details"""
result = _safe_get("https://www.thecolorapi.com/random")
if "name" in result:
return {
"hex": result.get("hex", {}).get("value"),
"rgb": result.get("rgb", {}).get("value"),
"hsl": result.get("hsl", {}).get("value"),
"hsv": result.get("hsv", {}).get("value"),
"cmyk": result.get("cmyk", {}).get("value"),
"name": result.get("name", {}).get("value"),
"contrast": result.get("contrast", {}).get("value"),
"image": result.get("image", {}).get("bare")
}
return result
def get_color_by_hex(hex_code: str) -> dict:
"""
Get color details by hex code
Args:
hex_code: Hex color code (with or without #)
"""
hex_clean = hex_code.lstrip("#")
result = _safe_get(f"https://www.thecolorapi.com/id?hex={hex_clean}")
return result
# ============================================================
# QR CODE
# ============================================================
def generate_qr_code(data: str, size: int = 200) -> dict:
"""
Generate a QR code for any text/URL
Args:
data: Text or URL to encode
size: Image size in pixels
"""
encoded_data = requests.utils.quote(data)
url = f"https://api.qrserver.com/v1/create-qr-code/?size={size}x{size}&data={encoded_data}"
return {
"qr_code_url": url,
"data": data,
"size": size
}
# ============================================================
# FACTS & TRIVIA
# ============================================================
def get_cat_fact() -> dict:
"""Get a random cat fact"""
return _safe_get("https://catfact.ninja/fact")
def get_dog_fact() -> dict:
"""Get a random dog fact"""
result = _safe_get("https://dog-api.kinduff.com/api/facts")
if "facts" in result:
return {"fact": result["facts"][0] if result["facts"] else ""}
return result
def get_trivia_question(amount: int = 1, category: int = None, difficulty: str = None, type: str = None) -> dict:
"""
Get trivia questions
Args:
amount: Number of questions (1-50)
category: Category ID (9=General Knowledge, 10=Books, 11=Film, 12=Music, 14=TV, 15=Video Games, 17=Science, 18=Computers, 21=Sports, 22=Geography, 23=History, 27=Animals)
difficulty: 'easy', 'medium', 'hard'
type: 'multiple' or 'boolean'
"""
params = [f"amount={min(amount, 50)}"]
if category:
params.append(f"category={category}")
if difficulty:
params.append(f"difficulty={difficulty}")
if type:
params.append(f"type={type}")
url = "https://opentdb.com/api.php?" + "&".join(params)
result = _safe_get(url)
if "results" in result:
questions = []
for q in result["results"]:
questions.append({
"category": q.get("category"),
"type": q.get("type"),
"difficulty": q.get("difficulty"),
"question": q.get("question"),
"correct_answer": q.get("correct_answer"),
"incorrect_answers": q.get("incorrect_answers", [])
})
return {"questions": questions, "response_code": result.get("response_code")}
return result
# ============================================================
# REDDIT
# ============================================================
def get_reddit_posts(subreddit: str = "all", limit: int = 5, sort: str = "hot") -> dict:
"""
Get posts from a subreddit
Args:
subreddit: Subreddit name
limit: Number of posts (max 25)
sort: 'hot', 'new', 'top', 'rising'
"""
headers = {"User-Agent": "HermesAgent/1.0"}
result = _safe_get(f"https://www.reddit.com/r/{subreddit}/{sort}.json?limit={min(limit, 25)}", headers=headers)
if "data" in result and "children" in result["data"]:
posts = []
for post in result["data"]["children"]:
p = post.get("data", {})
posts.append({
"title": p.get("title"),
"author": p.get("author"),
"subreddit": p.get("subreddit"),
"score": p.get("score"),
"comments": p.get("num_comments"),
"url": p.get("url"),
"permalink": f"https://reddit.com{p.get('permalink')}" if p.get("permalink") else None,
"is_self": p.get("is_self"),
"selftext": p.get("selftext", "")[:300] if p.get("selftext") else "",
"created": datetime.fromtimestamp(p.get("created_utc", 0)).isoformat() if p.get("created_utc") else ""
})
return {"posts": posts, "subreddit": subreddit}
return result
# ============================================================
# TRAFFIC & TRANSPORT
# ============================================================
def get_random_highway_webcam(country: str = "US") -> dict:
"""
Get random highway webcam image (US only)
Args:
country: Country code (only US supported)
"""
# This is a simplified version - real implementation would use a traffic API
return {"note": "Traffic webcam requires a specialized API key. Try using map services or government traffic APIs."}
# ============================================================
# WORLD BANK
# ============================================================
def get_world_bank_indicator(country_code: str = "US", indicator: str = "NY.GDP.MKTP.CD", date: str = "2022") -> dict:
"""
Get World Bank economic indicators
Args:
country_code: 2-letter country code or 'WLD' for world
indicator: Indicator code (NY.GDP.MKTP.CD=GDP, SP.POP.TOTL=Population, etc.)
date: Year or range (e.g., '2020:2022')
"""
result = _safe_get(f"https://api.worldbank.org/v2/country/{country_code}/indicator/{indicator}?date={date}&format=json")
if isinstance(result, list) and len(result) > 1 and result[1]:
data = result[1][0]
return {
"indicator": indicator,
"country": data.get("country", {}).get("value"),
"country_code": data.get("country", {}).get("id"),
"value": data.get("value"),
"date": data.get("date"),
}
return result
def get_world_bank_countries() -> dict:
"""Get list of countries from World Bank"""
return _safe_get("https://api.worldbank.org/v2/country?format=json&per_page=300")
# ============================================================
# HEALTH
# ============================================================
def get_drug_info(search: str) -> dict:
"""
Search for FDA drug information
Args:
search: Drug name or active ingredient
"""
return _safe_get(f"https://api.fda.gov/drug/label.json?search={search}&limit=1")
def get_covid_global() -> dict:
"""Get global COVID-19 statistics"""
result = _safe_get("https://disease.sh/v3/covid-19/all")
if "cases" in result:
return {
"total_cases": result.get("cases"),
"total_deaths": result.get("deaths"),
"total_recovered": result.get("recovered"),
"active_cases": result.get("active"),
"today_cases": result.get("todayCases"),
"today_deaths": result.get("todayDeaths"),
"today_recovered": result.get("todayRecovered"),
"tests": result.get("tests"),
"affected_countries": result.get("affectedCountries"),
"updated": datetime.fromtimestamp(result.get("updated", 0)/1000).isoformat() if result.get("updated") else ""
}
return result
# ============================================================
# FUNCTION REGISTRY FOR HERMES AGENT
# ============================================================
ALL_FUNCTIONS = [
# Animals
get_random_dog, get_dog_breeds, get_random_cat, get_random_fox,
get_random_duck, get_shibe,
# Anime
search_anime, get_anime_details, get_top_anime, get_current_season_anime,
get_random_anime_quote,
# Art
search_artworks, search_met_museum,
# Books
search_books, get_book_by_isbn, get_random_quote, get_quote_of_the_day,
get_random_gutenberg_book,
# Calendar
get_public_holidays, get_country_info, get_available_countries,
# Crypto
get_crypto_price, get_trending_crypto, get_global_crypto_data,
get_bitcoin_data, convert_crypto,
# Currency
convert_currency, get_exchange_rates,
# Development
github_search, get_github_user, get_stackoverflow_questions,
# Dictionary
define_word,
# Environment/Weather
get_weather_forecast, get_weather_by_city, get_air_quality,
get_iss_location, get_astronauts_in_space, get_nasa_apod,
get_space_x_launches,
# Food
search_meal, get_random_meal, search_cocktail, get_random_cocktail,
get_random_coffee_image,
# Games
get_pokemon, get_random_pokemon, get_pokemon_by_type,
get_dnd_class, get_dnd_monster, get_dnd_spell,
get_chess_profile, draw_cards,
# Geocoding
geocode_location, reverse_geocode, get_my_ip,
# Jokes
get_joke, get_chuck_norris_joke, get_chuck_norris_categories,
get_random_meme, get_rick_and_morty_character,
get_random_activity, get_useless_fact,
# Music
get_song_lyrics, search_lastfm,
# News
get_hacker_news, get_space_news,
# Quotes
get_breaking_bad_quote, get_game_of_thrones_quote, get_zen_quote,
get_ron_swanson_quote,
# Sports
get_football_standings, get_nba_games, get_f1_results, get_city_bikes,
# Test Data
generate_random_user, generate_fake_data, get_random_user,
# Text
translate_text, analyze_sentiment, detect_language,
# URL
shorten_url,
# Science
get_element, get_number_fact, get_random_number_fact,
# Code
get_codeforces_user, get_codeforces_contests,
# TV/Movies
search_tv_show, get_tv_schedule,
# Universities
search_universities,
# Colors
get_random_color, get_color_by_hex,
# QR
generate_qr_code,
# Facts
get_cat_fact, get_dog_fact, get_trivia_question,
# Reddit
get_reddit_posts,
# World Bank
get_world_bank_indicator, get_world_bank_countries,
# Health
get_drug_info, get_covid_global,
]
def get_function_by_name(name: str):
"""Get a function by its name"""
for func in ALL_FUNCTIONS:
if func.__name__ == name:
return func
return None
def get_all_function_names() -> List[str]:
"""Get list of all available function names"""
return [func.__name__ for func in ALL_FUNCTIONS]
def get_function_schemas() -> List[Dict]:
"""
Generate OpenAI-compatible function schemas for all functions
This uses the function docstrings to create schemas
"""
import inspect
schemas = []
for func in ALL_FUNCTIONS:
sig = inspect.signature(func)
doc = inspect.getdoc(func) or ""
# Parse parameters
params = {}
required = []
for name, param in sig.parameters.items():
param_type = "string"
param_default = param.default if param.default is not inspect.Parameter.empty else None
param_annotation = param.annotation if param.annotation is not inspect.Parameter.empty else None
if param_annotation == int or param_annotation == float:
param_type = "number"
elif param_annotation == bool:
param_type = "boolean"
param_info = {"type": param_type, "description": f"Parameter {name}"}
if param_default is not None:
param_info["default"] = param_default
else:
required.append(name)
params[name] = param_info
schema = {
"type": "function",
"function": {
"name": func.__name__,
"description": doc.split("\n")[0] if doc else f"Execute {func.__name__}",
"parameters": {
"type": "object",
"properties": params,
"required": required if required else list(params.keys())
}
}
}
schemas.append(schema)
return schemas