Spaces:
Configuration error
Configuration error
Download api_functions.py from D3AMON/hermes-agent: direct link, hf CLI and curl.
- Browser
- Download file 77.8 kB
-
https://huggingface.co/spaces/D3AMON/hermes-agent/resolve/main/api_functions.py
- Command line
-
hf download hf://spaces/D3AMON/hermes-agent/api_functions.py
-
curl -L -o api_functions.py https://huggingface.co/spaces/D3AMON/hermes-agent/resolve/main/api_functions.py
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"¤t=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 | |
| # ============================================================ | |
| # ============================================================ | |
| 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, | |
| 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 | |