Python 88.3%
TypeScript 7.6%
Shell 4.1%
1#!/usr/bin/env python32"""Dump the OpenAPI paths + resolved schemas for the platform domain into tmp/platform-spec/.3Usage: python3 tmp/platform_extract.py4"""5import json, re, sys, yaml6from pathlib import Path78ROOT = Path(__file__).resolve().parent.parent9SPEC = ROOT / "sources/openai/openapi/openapi-master.yaml"10OUT = ROOT / "tmp/platform-spec"11OUT.mkdir(parents=True, exist_ok=True)12spec = yaml.safe_load(SPEC.read_text())13schemas = spec["components"]["schemas"]14PREFIXES = ("/files", "/uploads", "/vector_stores", "/batches", "/fine_tuning", "/evals")1516ops = {}17for path, item in spec["paths"].items():18 if not path.startswith(PREFIXES):19 continue20 for method, op in item.items():21 if method not in ("get", "post", "delete", "patch", "put"):22 continue23 ops[f"{method.upper()} {path}"] = op2425def deref(node, depth=0, seen=None):26 """Resolve $ref recursively, keep names in 'x-ref'."""27 seen = seen or set()28 if isinstance(node, dict):29 if "$ref" in node:30 name = node["$ref"].split("/")[-1]31 if name in seen or depth > 12:32 return {"x-ref": name}33 sub = deref(schemas[name], depth + 1, seen | {name})34 if isinstance(sub, dict):35 sub = {"x-ref": name, **sub}36 return sub37 return {k: deref(v, depth + 1, seen) for k, v in node.items()}38 if isinstance(node, list):39 return [deref(v, depth + 1, seen) for v in node]40 return node4142def flatten(schema, prefix="", out=None, required_parent=None, depth=0):43 """Flatten a resolved schema into dotted parameter rows."""44 out = out if out is not None else []45 if not isinstance(schema, dict) or depth > 10:46 return out47 for comb in ("oneOf", "anyOf", "allOf"):48 if comb in schema:49 for alt in schema[comb]:50 flatten(alt, prefix, out, required_parent, depth + 1)51 props = schema.get("properties", {})52 req = set(schema.get("required", []))53 for name, sub in props.items():54 p = f"{prefix}{name}"55 typ = sub.get("type")56 if not typ and ("oneOf" in sub or "anyOf" in sub):57 alts = sub.get("oneOf") or sub.get("anyOf")58 typ = " | ".join(str(a.get("type") or a.get("x-ref") or "object") for a in alts)59 if typ == "array":60 it = sub.get("items", {})61 typ = f"array<{it.get('type') or it.get('x-ref') or 'object'}>"62 row = {63 "parameter": p, "type": typ, "required": name in req,64 "default": sub.get("default"), "minimum": sub.get("minimum"), "maximum": sub.get("maximum"),65 "enum": sub.get("enum"), "description": (sub.get("description") or "")[:600],66 "nullable": sub.get("nullable"), "x-ref": sub.get("x-ref"),67 }68 out.append({k: v for k, v in row.items() if v not in (None, False, "") or k in ("parameter", "type", "required")})69 # nested70 if sub.get("type") == "object" or "properties" in sub or "oneOf" in sub or "anyOf" in sub or "allOf" in sub:71 flatten(sub, p + ".", out, None, depth + 1)72 if sub.get("type") == "array" and isinstance(sub.get("items"), dict):73 flatten(sub["items"], p + "[].", out, None, depth + 1)74 return out7576summary = {}77for key, op in ops.items():78 rec = {"operationId": op.get("operationId"), "summary": op.get("summary"),79 "description": (op.get("description") or "")[:800],80 "params": [], "body_schema": None, "body_content_type": None, "responses": {}}81 for prm in op.get("parameters", []):82 prm = deref(prm)83 sch = prm.get("schema", {})84 rec["params"].append({"name": prm["name"], "in": prm["in"], "required": prm.get("required", False),85 "type": sch.get("type"), "default": sch.get("default"), "enum": sch.get("enum"),86 "description": (prm.get("description") or "")[:400]})87 rb = op.get("requestBody")88 if rb:89 content = rb["content"]90 ct = list(content.keys())[0]91 rec["body_content_type"] = ct92 sch = content[ct]["schema"]93 rec["body_ref"] = sch.get("$ref", "").split("/")[-1] or None94 resolved = deref(sch)95 rec["body_schema"] = resolved96 rec["body_flat"] = flatten(resolved)97 for code, resp in op.get("responses", {}).items():98 c = resp.get("content", {})99 if c:100 ct = list(c.keys())[0]101 s = c[ct]["schema"]102 rec["responses"][code] = {"content_type": ct, "ref": s.get("$ref", "").split("/")[-1] or s.get("type")}103 summary[key] = rec104 fn = re.sub(r"[^A-Za-z0-9]+", "_", key).strip("_")105 (OUT / f"{fn}.json").write_text(json.dumps(rec, indent=1, default=str))106107(OUT / "_index.json").write_text(json.dumps(108 {k: {"operationId": v["operationId"], "summary": v["summary"], "body_ref": v.get("body_ref"),109 "body_ct": v["body_content_type"], "responses": v["responses"], "params": [p["name"] for p in v["params"]]}110 for k, v in summary.items()}, indent=1))111112# Object schemas of interest113OBJ = [s for s in schemas if re.search(r"^(OpenAIFile|Upload|UploadPart|VectorStore|VectorStoreFile|VectorStoreFileBatch|VectorStoreSearchResult|Batch|BatchRequestInput|BatchRequestOutput|FineTuningJob|FineTuningJobEvent|FineTuningJobCheckpoint|FineTuningCheckpointPermission|Grader|Eval|EvalRun|EvalRunOutputItem|FineTuneMethod|FineTuneSupervisedMethod|FineTuneDPOMethod|FineTuneReinforcementMethod|FineTune.*Hyperparameters|StaticChunking|AutoChunking|ChunkingStrategy|ComparisonFilter|CompoundFilter|VectorStoreExpirationAfter|FileExpirationAfter|ListFilesResponse|ListBatchesResponse|CreateEvalRequest|CreateEvalRunRequest|EvalItem|EvalJsonl|EvalStoredCompletions|EvalLogs|EvalCustomDataSourceConfig|EvalResponses|EvalCompletions|FineTuneChatRequestInput|FineTunePreferenceRequestInput|FineTuneReinforcementRequestInput|FineTuneChatCompletionRequestAssistantMessage|RunGrader|ValidateGrader).*", s)]114objs = {}115for name in OBJ:116 r = deref(schemas[name])117 objs[name] = {"schema": r, "flat": flatten(r)}118 fn = re.sub(r"[^A-Za-z0-9]+", "_", name)119 (OUT / f"schema_{fn}.json").write_text(json.dumps(objs[name], indent=1, default=str))120(OUT / "_schemas_index.txt").write_text("\n".join(sorted(OBJ)))121print(len(ops), "ops;", len(OBJ), "schemas ->", OUT)122