Allow running without models.json

This commit is contained in:
shroominic
2025-06-09 23:23:01 +02:00
parent 8df4d10054
commit 873ad7d419
4 changed files with 42 additions and 7 deletions
+3 -1
View File
@@ -17,8 +17,10 @@ COST_PER_REQUEST="10"
COST_PER_1K_INPUT_TOKENS = "0"
COST_PER_1K_OUTPUT_TOKENS = "0"
# If set to true, make sure model pricings are defined in models.json
# If set to true, pricing is loaded from the file specified by MODELS_PATH
# Defaults to "models.json" and falls back to "models.example.json" if missing
MODEL_BASED_PRICING = "false"
# MODELS_PATH="models.json"
# Time in seconds between each automatically refunding funds to users whose API keys have expired
# Setting this to "0" disables automatic refunds
+6 -2
View File
@@ -1,4 +1,8 @@
# proxy
a reverse proxy that you can plug in front of any openai compatible api endpoint
to handle payments using the cashu protocol (Bitcoin L3)
a reverse proxy that you can plug in front of any OpenAI compatible API
endpoint to handle payments using the Cashu protocol (Bitcoin L3).
Model pricing information is loaded from ``models.json`` by default. If that
file is not present, the bundled ``models.example.json`` will be used. You can
specify a custom path with the ``MODELS_PATH`` environment variable.
+2 -2
View File
@@ -105,7 +105,7 @@ async def pay_for_request(
request: Request | None,
request_body: bytes | None = None,
) -> None:
if MODEL_BASED_PRICING and os.path.exists("models.json"):
if MODEL_BASED_PRICING and MODELS:
if request_body:
body = json.loads(request_body)
else:
@@ -180,7 +180,7 @@ async def adjust_payment_for_tokens(
MSATS_PER_1K_INPUT_TOKENS = COST_PER_1K_INPUT_TOKENS
MSATS_PER_1K_OUTPUT_TOKENS = COST_PER_1K_OUTPUT_TOKENS
if MODEL_BASED_PRICING and os.path.exists("models.json"):
if MODEL_BASED_PRICING and MODELS:
response_model = response_data.get("model", "")
if response_model not in [model.id for model in MODELS]:
raise HTTPException(
+31 -2
View File
@@ -1,5 +1,7 @@
import asyncio
import json
import os
from pathlib import Path
from pydantic.v1 import BaseModel
from .price import sats_usd_ask_price
@@ -44,8 +46,35 @@ class Model(BaseModel):
MODELS: list[Model] = []
with open("models.json", "r") as f:
MODELS = [Model(**model) for model in json.load(f)["models"]]
def load_models() -> list[Model]:
"""Load model definitions from a JSON file.
The file path can be specified via the ``MODELS_PATH`` environment variable.
If ``models.json`` is not found, the bundled ``models.example.json`` is used
as a fallback. If neither file exists or an error occurs while loading, an
empty list is returned.
"""
models_path = Path(os.environ.get("MODELS_PATH", "models.json"))
if not models_path.exists():
example = Path(__file__).resolve().parent.parent / "models.example.json"
if example.exists():
models_path = example
else:
return []
try:
with models_path.open("r") as f:
data = json.load(f)
except Exception as e: # pragma: no cover - log and continue
print(f"Error loading models from {models_path}: {e}")
return []
return [Model(**model) for model in data.get("models", [])]
MODELS = load_models()
async def update_sats_pricing() -> None: