Skip to content

Repository files navigation

bud-model-catalog

Multi-source LLM model catalog with cost-accurate pricing. Fetches model metadata from LiteLLM and truefoundry/models, merges them with cost-accurate pricing, filters deprecated models, and returns a unified catalog keyed by TensorZero provider/model.

Covers text, embedding, image and voice models — speech-to-text and text-to-speech entries from Deepgram, ElevenLabs, AssemblyAI, AWS Polly and Groq are included, priced per second or per character.

Install

pip install bud-model-catalog

Quick Start

from bud_model_catalog import CatalogClient

client = CatalogClient()
result = client.fetch_catalog_sync()

# Inspect merge statistics
print(result.stats)
# MergeStats(total_litellm=847, total_output=812, matched=342, ...)

# Look up a specific model's pricing
model = result.models["openai/gpt-4o"]
print(f"Input:  ${model['input_cost_per_token']}/token")
print(f"Output: ${model['output_cost_per_token']}/token")

Voice Models

Speech models are keyed like any other entry and carry mode plus duration- or character-based costs:

result = client.fetch_catalog_sync()

stt = result.models["deepgram/nova-3"]
print(stt["mode"])                     # audio_transcription
print(stt["input_cost_per_second"])    # 7.167e-05

tts = result.models["elevenlabs/eleven_multilingual_v2"]
print(tts["mode"])                     # audio_speech
print(tts["input_cost_per_character"]) # 0.0001

# All voice models across providers
voice = {
    key: m for key, m in result.models.items()
    if m.get("mode") in ("audio_transcription", "audio_speech")
}

Only providers that upstream actually publishes are included. Vendors served elsewhere (Cartesia, LMNT, Murf, PlayHT, Speechmatics, …) have no entries in either source and so do not appear in the catalog.

Async Usage

import asyncio
from bud_model_catalog import CatalogClient, CatalogConfig

async def main():
    config = CatalogConfig(include_deprecated=True, timeout=60)
    client = CatalogClient(config)
    result = await client.fetch_catalog()

    # Filter to a single provider
    anthropic_models = {
        key: model for key, model in result.models.items()
        if key.startswith("anthropic/")
    }
    for key, model in list(anthropic_models.items())[:3]:
        print(f"{key}: ${model.get('input_cost_per_token', 'N/A')}/token")

asyncio.run(main())

Jupyter / Notebook

fetch_catalog_sync() works inside Jupyter's running event loop:

# In a Jupyter notebook cell:
from bud_model_catalog import CatalogClient

client = CatalogClient()
result = client.fetch_catalog_sync()  # works inside Jupyter's event loop
print(f"{len(result.models)} models loaded")

# Or use await directly in a notebook cell:
result = await client.fetch_catalog()

Convenience Function

from bud_model_catalog import fetch_catalog

# One-shot fetch (no ETag caching across calls)
result = await fetch_catalog()

Configuration

All options are passed via CatalogConfig:

Field Type Default Description
litellm_url str GitHub raw URL URL to the LiteLLM model prices JSON
ai_models_url str GitHub archive URL URL to the truefoundry/models ZIP archive
timeout int 30 HTTP request timeout in seconds (must be > 0)
include_deprecated bool False Whether to include deprecated models in output
max_retries int 2 Maximum retry attempts per HTTP request (with exponential backoff)
cache bool True Enable ETag-based conditional GET caching across calls
from bud_model_catalog import CatalogConfig

config = CatalogConfig(
    timeout=60,
    include_deprecated=True,
    max_retries=3,
    cache=True,
)

Validation is enforced at construction time:

CatalogConfig(timeout=-1)   # ValueError: timeout must be positive
CatalogConfig(litellm_url="not-a-url")  # ValueError: must be an HTTP(S) URL

Error Handling

from bud_model_catalog import CatalogClient, CatalogConfig, SourceFetchError

try:
    result = CatalogClient().fetch_catalog_sync()
except SourceFetchError as e:
    print(f"Failed to fetch data: {e}")
  • SourceFetchError — raised when LiteLLM fetch fails (HTTP error, invalid JSON, timeout)
  • ai-models failures are handled gracefully — the SDK falls back to LiteLLM-only costs

API Reference

CatalogClient

Main entry point for fetching the catalog.

  • CatalogClient(config=None) — create a client with optional CatalogConfig
  • await client.fetch_catalog() — async fetch, returns CatalogResult
  • client.fetch_catalog_sync() — blocking sync wrapper (works in Jupyter, async frameworks, and plain scripts)

CatalogResult

Pydantic model returned from fetch operations.

  • models: dict[str, dict] — merged model catalog keyed by {provider}/{model}
  • stats: MergeStats — merge statistics
  • litellm_fetched_at: datetime — timestamp of LiteLLM fetch
  • ai_models_fetched_at: datetime | None — timestamp of ai-models fetch (None if failed/skipped)

MergeStats

  • total_litellm — total models from LiteLLM source
  • total_output — models in final output
  • matched — models matched with ai-models data
  • unmatched — models without ai-models match
  • deprecated_removed — models filtered as deprecated
  • cost_fields_updated — individual cost field values updated from ai-models

Logging

The SDK uses Python's logging module. Enable output to see fetch/merge details:

import logging
logging.basicConfig(level=logging.INFO)

Key log messages:

  • INFO — fetch counts, merge statistics, cache hits
  • WARNING — ai-models fallback, malformed YAML files skipped, retry attempts

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest -v

# Lint
ruff check src/ tests/

About

Multi-source LLM model catalog with cost-accurate pricing. Fetches model metadata from LiteLLM and truefoundry/models, merges them with cost-accurate pricing, filters deprecated models, and returns a unified catalog.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages