SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
6.2 KB · 116 lines python
Raw Blame History
1#!/usr/bin/env python32"""Cheap live probes for the OpenAI model catalogue (re-runnable).341. GET /v1/models/{id} for representative ids (free) — do docs-only ids resolve? do live-only ids have metadata?52. Minimal POST /v1/responses ("Reply with OK.", max_output_tokens 16) against the newest text models6   to record LIVE_VERIFIED vs error and the `model` echoed in the response (reveals the snapshot).78Every call is logged to reports/live-requests.jsonl by scripts/live.py. Raw bodies -> tmp-live/ (gitignored),9sanitized summary -> sources/openai/live-model-probes.json (consumed by scripts/build_openai_models.py).1011Usage: python3 scripts/probe_openai_models.py [--skip-post]12"""13from __future__ import annotations1415import json16import sys17from datetime import datetime, timezone18from pathlib import Path1920sys.path.insert(0, str(Path(__file__).resolve().parent.parent))21from scripts.live import openai_request, interesting_headers, save_sanitized, mask  # noqa: E4022223ROOT = Path(__file__).resolve().parent.parent24OUT = ROOT / "sources/openai/live-model-probes.json"25RAW = ROOT / "tmp-live/openai-model-probes"2627GET_IDS = [28    # newest live ids29    "gpt-5.6-luna", "gpt-6-astra", "gpt-image-2.5-flare", "gpt-live-1",30    # docs-only ids31    "gpt-5.6-cyber", "gpt-daybreak-blue-latest", "gpt-oss-120b", "dall-e-3", "computer-use-preview",32    "codex-mini-latest", "o1-mini", "chatgpt-4o-latest", "gpt-rosalind-research", "gpt-5.5-cyber",33    # alias documented in prose only34    "gpt-5.6",35    # live-only ids (no model page)36    "gpt-5-search-api", "gpt-3.5-turbo-16k", "tts-1-1106",37    # documented as shut down 2026-07-23 but still listed38    "gpt-5-codex", "gpt-5.1-codex", "o3-deep-research",39]4041# (model, reasoning effort) — cheapest settings the docs allow. Astra does not support `none`.42POST_MODELS = [43    ("gpt-5.6-luna", "none"), ("gpt-5.6-sol", "none"), ("gpt-5.6-terra", "none"),44    ("gpt-6-astra", "low"), ("gpt-5.5", "none"), ("gpt-5.4-mini", "none"),45]46# standard USD per 1M tokens (input, cached_input, output) from pricing.md — for cost estimates only47PRICE = {48    "gpt-5.6-luna": (0.20, 0.02, 1.20), "gpt-5.6-sol": (4.0, 0.4, 20.0), "gpt-5.6-terra": (2.0, 0.2, 12.0),49    "gpt-6-astra": (10.0, 1.0, 50.0), "gpt-5.5": (5.0, 0.5, 30.0), "gpt-5.4-mini": (0.75, 0.075, 4.5),50}515253def main() -> None:54    skip_post = "--skip-post" in sys.argv55    RAW.mkdir(parents=True, exist_ok=True)56    result = {"probed_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), "get_models": {}, "responses": {},57              "observed_headers": [], "estimated_cost_usd": 0.0}5859    for mid in GET_IDS:60        st, body, hdrs = openai_request("GET", f"/v1/models/{mid}", note=f"model probe GET {mid}")61        save_sanitized(body, RAW / f"get-{mid}.json")62        entry = {"status": st}63        if isinstance(body, dict):64            if st == 200:65                entry.update({k: body.get(k) for k in ("id", "object", "created", "owned_by", "shutdown_date") if k in body})66            elif "error" in body:67                err = body["error"]68                entry.update({"error_type": err.get("type"), "error_code": err.get("code"), "error_message": mask(str(err.get("message")))[:300]})69        result["get_models"][mid] = entry70        print(f"GET  /v1/models/{mid:<28} -> {st} {entry.get('error_code') or entry.get('owned_by') or ''}")7172    if not skip_post:73        for mid, effort in POST_MODELS:74            payload = {"model": mid, "input": "Reply with OK.", "max_output_tokens": 16, "reasoning": {"effort": effort}}75            st, body, hdrs = openai_request("POST", "/v1/responses", payload, note=f"model probe POST {mid} effort={effort}")76            save_sanitized(body, RAW / f"post-{mid}.json")77            entry = {"status": st, "request": payload}78            cost = 0.079            if isinstance(body, dict):80                if st == 200:81                    usage = body.get("usage") or {}82                    cached = (usage.get("input_tokens_details") or {}).get("cached_tokens", 0)83                    reasoning = (usage.get("output_tokens_details") or {}).get("reasoning_tokens", 0)84                    text = ""85                    for item in body.get("output", []):86                        for c in item.get("content", []) or []:87                            if c.get("type") == "output_text":88                                text += c.get("text", "")89                    entry.update({"model_echo": body.get("model"), "status_field": body.get("status"),90                                  "incomplete_reason": (body.get("incomplete_details") or {}).get("reason"),91                                  "service_tier": body.get("service_tier"), "usage": usage, "reasoning_tokens": reasoning,92                                  "output_text": text[:64]})93                    p = PRICE.get(mid)94                    if p:95                        cost = ((usage.get("input_tokens", 0) - cached) * p[0] + cached * p[1] + usage.get("output_tokens", 0) * p[2]) / 1e696                elif "error" in body:97                    err = body["error"]98                    entry.update({"error_type": err.get("type"), "error_code": err.get("code"), "error_param": err.get("param"),99                                  "error_message": mask(str(err.get("message")))[:300]})100            entry["est_cost_usd"] = round(cost, 6)101            result["estimated_cost_usd"] = round(result["estimated_cost_usd"] + cost, 6)102            rl = {k: v for k, v in interesting_headers(hdrs).items() if k.lower().startswith("x-ratelimit")}103            if rl:104                result["observed_headers"].append({"date": result["probed_at"][:10], "request": f"POST /v1/responses model={mid}",105                                                   "headers": rl, "note": "observed for OUR key — account-specific, do not generalize"})106            result["responses"][mid] = entry107            print(f"POST /v1/responses {mid:<16} -> {st} echo={entry.get('model_echo')} {entry.get('error_code') or ''} "108                  f"out={entry.get('output_text','')!r} reasoning_tokens={entry.get('reasoning_tokens')} cost=${cost:.5f}")109110    save_sanitized(result, OUT)111    print(f"\nsaved {OUT.relative_to(ROOT)}; estimated total cost ${result['estimated_cost_usd']:.4f}")112113114if __name__ == "__main__":115    main()116