Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/scripts/sync_pricing_to_general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""
Sync model IDs from a pricing JSON file to the corresponding general JSON file.
For each model present in pricing but missing in general, adds a minimal stub at the end.
Usage: sync_pricing_to_general.py <pricing-file> [general-file]
If general-file is omitted, inferred from pricing path (e.g. pricing/google.json -> general/google.json).
"""

import json
import sys
from pathlib import Path

GENERAL_RESERVED = {"name", "description", "default"}
# Only max_tokens; exclude top_k, top_p, log_p, etc. from minimal stub
MINIMAL_STUB = {
"params": [{"key": "max_tokens", "maxValue": 64000}],
"type": {"primary": "chat", "supported": ["image", "pdf", "doc", "tools"]},
"removeParams": [ "top_p"]
}


def get_general_paths(pricing_path: Path, general_path_arg: Path | None) -> list[Path]:
"""Resolve which general file(s) to sync to. OpenAI pricing syncs to both openai and open-ai."""
if general_path_arg is not None:
return [general_path_arg]
basename = pricing_path.stem # e.g. "openai"
if basename == "openai":
return [Path("general/openai.json"), Path("general/open-ai.json")]
return [Path("general") / pricing_path.name]


def main() -> int:
if len(sys.argv) < 2:
print("Usage: sync_pricing_to_general.py <pricing-file> [general-file]", file=sys.stderr)
return 1

pricing_path = Path(sys.argv[1])
general_path_arg = Path(sys.argv[2]) if len(sys.argv) > 2 else None

if not pricing_path.exists():
print(f"::error file={pricing_path}::Pricing file not found", file=sys.stderr)
return 1

general_paths = get_general_paths(pricing_path, general_path_arg)
pricing = json.loads(pricing_path.read_text())
pricing_models = set(pricing.keys())

for general_path in general_paths:
if not general_path.exists():
print(f"::notice::No general file at {general_path}, skipping")
continue

general = json.loads(general_path.read_text())
general_models = set(k for k in general.keys() if k not in GENERAL_RESERVED)
missing = sorted(pricing_models - general_models)

if not missing:
print(f"All pricing models already present in {general_path}")
continue

for model_id in missing:
general[model_id] = dict(MINIMAL_STUB)

ordered = {k: general[k] for k in general}
with open(general_path, "w") as f:
json.dump(ordered, f, indent=2)
f.write("\n")

print(f"Added missing models to {general_path}:")
for m in missing:
print(f" - {m}")

return 0


if __name__ == "__main__":
sys.exit(main())
65 changes: 65 additions & 0 deletions .github/workflows/sync-pricing-to-general.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# On every PR that touches pricing files, ensure each pricing provider's models
# exist in the corresponding general/*.json; add any missing models with a minimal stub.
name: Sync pricing models to general

on:
pull_request:
paths:
- 'pricing/**'

permissions:
contents: write
pull-requests: write

jobs:
sync:
name: Sync missing models to general
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get changed pricing files
id: changed
run: |
FILES=$(git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}" -- 'pricing/*.json' || true)
if [[ -z "$FILES" ]]; then
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
echo "" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "No pricing files changed"
exit 0
fi
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "Changed pricing files:"
echo "$FILES"

- name: Sync each changed pricing file to general
if: steps.changed.outputs.paths != ''
run: |
for f in ${{ steps.changed.outputs.paths }}; do
[[ -z "$f" ]] && continue
python3 .github/scripts/sync_pricing_to_general.py "$f" || true
done

- name: Check for uncommitted changes
id: status
if: steps.changed.outputs.paths != ''
run: |
git diff --quiet general/ && echo "changed=false" >> "$GITHUB_OUTPUT" || echo "changed=true" >> "$GITHUB_OUTPUT"
git status --short general/

- name: Commit and push added models
if: steps.changed.outputs.paths != '' && steps.status.outputs.changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add general/
git commit -m "chore: add missing pricing models to general configs [sync-pricing-to-general]"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
167 changes: 164 additions & 3 deletions pricing/azure-openai.json
Original file line number Diff line number Diff line change
Expand Up @@ -2483,11 +2483,172 @@
"gpt-image-1": {
"pricing_config": {
"pay_as_you_go": {
"request_token": {
"price": 0.0005
"image": {
"default": {
"default": {
"price": 16.7
},
"1024x1024": {
"price": 16.7
},
"1024x1536": {
"price": 25
},
"1536x1024": {
"price": 25
}
},
"high": {
"default": {
"price": 16.7
},
"1024x1024": {
"price": 16.7
},
"1024x1536": {
"price": 25
},
"1536x1024": {
"price": 25
}
},
"medium": {
"default": {
"price": 4.2
},
"1024x1024": {
"price": 4.2
},
"1024x1536": {
"price": 6.3
},
"1536x1024": {
"price": 6.3
}
},
"low": {
"default": {
"price": 1.1
},
"1024x1024": {
"price": 1.1
},
"1024x1536": {
"price": 1.6
},
"1536x1024": {
"price": 1.6
}
}
},
"response_token": {
"request_image_token": {
"price": 0.001
},
"response_image_token": {
"price": 0.004
},
"request_text_token": {
"price": 0.0005
},
"cached_image_input_token": {
"price": 0.00025
},
"cache_read_image_input_token": {
"price": 0.00025
},
"cached_text_input_token": {
"price": 0.000125
},
"cache_read_text_input_token": {
"price": 0.000125
}
}
}
},
"gpt-image-1.5": {
"pricing_config": {
"pay_as_you_go": {
"image": {
"default": {
"default": {
"price": 13.3
},
"1024x1024": {
"price": 13.3
},
"1024x1536": {
"price": 20
},
"1536x1024": {
"price": 20
}
},
"high": {
"default": {
"price": 13.3
},
"1024x1024": {
"price": 13.3
},
"1024x1536": {
"price": 20
},
"1536x1024": {
"price": 20
}
},
"medium": {
"default": {
"price": 3.4
},
"1024x1024": {
"price": 3.4
},
"1024x1536": {
"price": 5
},
"1536x1024": {
"price": 5
}
},
"low": {
"default": {
"price": 0.9
},
"1024x1024": {
"price": 0.9
},
"1024x1536": {
"price": 1.3
},
"1536x1024": {
"price": 1.3
}
}
},
"request_image_token": {
"price": 0.0008
},
"response_image_token": {
"price": 0.0032
},
"request_text_token": {
"price": 0.0005
},
"response_text_token": {
"price": 0.001
},
"cached_image_input_token": {
"price": 0.0002
},
"cache_read_image_input_token": {
"price": 0.0002
},
"cached_text_input_token": {
"price": 0.000125
},
"cache_read_text_input_token": {
"price": 0.000125
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions pricing/openai.json
Original file line number Diff line number Diff line change
Expand Up @@ -2842,8 +2842,14 @@
"cached_image_input_token": {
"price": 0.00025
},
"cache_read_image_input_token": {
"price": 0.00025
},
"cached_text_input_token": {
"price": 0.000125
},
"cache_read_text_input_token": {
"price": 0.000125
}
}
}
Expand Down Expand Up @@ -3326,8 +3332,14 @@
"cached_image_input_token": {
"price": 0.0002
},
"cache_read_image_input_token": {
"price": 0.0002
},
"cached_text_input_token": {
"price": 0.000125
},
"cache_read_text_input_token": {
"price": 0.000125
}
}
}
Expand Down Expand Up @@ -3408,8 +3420,14 @@
"cached_image_input_token": {
"price": 0.0002
},
"cache_read_image_input_token": {
"price": 0.0002
},
"cached_text_input_token": {
"price": 0.000125
},
"cache_read_text_input_token": {
"price": 0.000125
}
}
}
Expand Down
Loading