From fd5f6bf0df31940fde04545a4ccb0609e7a5064e Mon Sep 17 00:00:00 2001 From: 1bcMax Date: Mon, 19 Oct 2026 23:27:37 -0500 Subject: [PATCH] fix(estimate): mirror @blockrun/mcp media prices from the live 2026-10-20 catalogue - image: add nano-banana-2, seedream-5-pro, gpt-image-2.5-flare/-sunburst, grok-imagine-image-2.0; grok-imagine-image-pro $0.07 -> $0.05; large-tier rules now match image.ts (nano-banana-pro steps at 4096, seedream on the smaller side, 2.5 pair $0.56 above 1024). - video: add grok-imagine-video-1.5, seedance-2.0-mini and seedance-2.5; replace the stale Seedance rates with the charged per-second figures (GET /v1/models, 720p baseline); drop the image-to-video discount that no longer exists; price grok per resolution and Seedance by resolution factor. - speech: add bytedance/seed-audio-1.0 display rate. - announce-cost skill: price tables updated to the same figures. --- lib/estimate.js | 73 +++++++++++++++++++++++++---------- skills/announce-cost/SKILL.md | 36 ++++++++++------- 2 files changed, 75 insertions(+), 34 deletions(-) diff --git a/lib/estimate.js b/lib/estimate.js index ee15639..14de8b9 100644 --- a/lib/estimate.js +++ b/lib/estimate.js @@ -9,44 +9,71 @@ // Prices MIRROR the live @blockrun/mcp tables (src/tools/{image,video,music, // speech,realface}.ts). Keep them in sync when the MCP catalog changes. -// Per-image USD by model. Base = 1024x1024; larger renders cost more on the -// models in IMAGE_LARGE (matches image.ts GENERATE_MODEL_COST / LARGE_SIZE_COST). +// Per-image USD by model. Base = 1024x1024 list price; larger renders cost +// more on the models in IMAGE_LARGE (matches image.ts GENERATE_MODEL_COST / +// LARGE_SIZE_COST / LARGE_SIZE_THRESHOLD / LARGE_SIZE_MIN_DIM_MODELS). +// Refreshed against @blockrun/mcp and the live catalog on 2026-10-20. const IMAGE = { "zai/cogview-4": 0.015, "xai/grok-imagine-image": 0.02, "openai/gpt-image-1": 0.02, + "xai/grok-imagine-image-2.0": 0.04, + "bytedance/seedream-5-pro": 0.045, "google/nano-banana": 0.05, + "xai/grok-imagine-image-pro": 0.05, "openai/gpt-image-2": 0.06, - "xai/grok-imagine-image-pro": 0.07, + "google/nano-banana-2": 0.09, "google/nano-banana-pro": 0.10, + "openai/gpt-image-2.5-flare": 0.28, + "openai/gpt-image-2.5-sunburst": 0.28, }; const IMAGE_DEFAULT = 0.06; // openai/gpt-image-2 (the MCP default) const IMAGE_LARGE = { "openai/gpt-image-1": 0.04, "openai/gpt-image-2": 0.12, + "openai/gpt-image-2.5-flare": 0.56, + "openai/gpt-image-2.5-sunburst": 0.56, "google/nano-banana-pro": 0.15, // 4096px tier + "bytedance/seedream-5-pro": 0.09, // both sides > 1024 }; +// Where each model's large tier starts, in max(w,h); 1024 when unlisted. +const IMAGE_LARGE_THRESHOLD = { + "google/nano-banana-pro": 2048, // same price through 2048x2048 +}; +// Seedream's large tier is keyed on the SMALLER side, not the larger one. +const IMAGE_LARGE_MIN_DIM = new Set(["bytedance/seedream-5-pro"]); -// Per-second USD by video model — text-to-video rate, and the cheaper -// image-to-video tier when a seed image / RealFace asset is supplied -// (matches video.ts VIDEO_PRICE_PER_SECOND / _IMAGE). +// Per-second USD by video model, as CHARGED (margin included) at the model's +// default resolution, and per resolution where the model prices it. Seedance +// is token-priced upstream; these are the per-second figures GET /v1/models +// publishes at the 720p baseline, rounded UP to 4dp. Image-to-video costs +// the same as text-to-video on every model (video.ts). const VIDEO_RATE = { "xai/grok-imagine-video": 0.05, - "bytedance/seedance-1.5-pro": 0.092, - "bytedance/seedance-2.0-fast": 0.238, - "bytedance/seedance-2.0": 0.298, - "azure/sora-2": 0.10, + "xai/grok-imagine-video-1.5": 0.08, + "bytedance/seedance-1.5-pro": 0.0708, + "bytedance/seedance-2.0-mini": 0.0798, + "bytedance/seedance-2.0-fast": 0.1652, + "bytedance/seedance-2.0": 0.2271, + "bytedance/seedance-2.5": 0.3156, + "azure/sora-2": 0.105, }; -const VIDEO_RATE_IMAGE = { - "bytedance/seedance-2.0-fast": 0.140, - "bytedance/seedance-2.0": 0.183, +// Grok bills per resolution, no margin (video.ts GROK_PRICE_PER_SECOND). +const VIDEO_RATE_BY_RES = { + "xai/grok-imagine-video": { "480p": 0.05, "720p": 0.07 }, + "xai/grok-imagine-video-1.5": { "480p": 0.08, "720p": 0.14, "1080p": 0.25 }, }; +// Seedance token cost scales with resolution (video.ts RESOLUTION_TOKEN_FACTOR). +const SEEDANCE_RES_FACTOR = { "480p": 0.5, "720p": 1, "1080p": 2.25, "4K": 9 }; const VIDEO_DEFAULT_RATE = 0.05; // xai/grok-imagine-video (the MCP default) const VIDEO_DEFAULT_SECS = { // per-model default duration "xai/grok-imagine-video": 8, + "xai/grok-imagine-video-1.5": 8, "bytedance/seedance-1.5-pro": 5, + "bytedance/seedance-2.0-mini": 5, "bytedance/seedance-2.0-fast": 5, "bytedance/seedance-2.0": 5, + "bytedance/seedance-2.5": 5, "azure/sora-2": 4, }; @@ -58,15 +85,19 @@ const SPEECH_RATE = { "elevenlabs/turbo-v2.5": 0.05, "elevenlabs/multilingual-v2": 0.10, "elevenlabs/v3": 0.10, + "bytedance/seed-audio-1.0": 0.30, // display rate; bills per output second }; const SPEECH_DEFAULT_RATE = 0.05; // elevenlabs/flash-v2.5 (the MCP default) const SOUND_EFFECT_COST = 0.0525; -// A dimension >1024 pushes gpt-image-* / nano-banana-pro into the large tier. -function isLargerThanBase(size) { +// Whether `size` is in `model`'s large tier (see IMAGE_LARGE_THRESHOLD / +// IMAGE_LARGE_MIN_DIM). Unparseable sizes price at the base. +function isLargerThanBase(model, size) { const m = /^\s*(\d+)\s*[x×]\s*(\d+)\s*$/i.exec(size || ""); if (!m) return false; - return Math.max(Number(m[1]), Number(m[2])) > 1024; + const threshold = IMAGE_LARGE_THRESHOLD[model] ?? 1024; + const pick = IMAGE_LARGE_MIN_DIM.has(model) ? Math.min : Math.max; + return pick(Number(m[1]), Number(m[2])) > threshold; } // Map a full MCP tool name (mcp____blockrun_) to the bare tool. @@ -81,16 +112,18 @@ function estimate(toolName, input = {}) { case "image": { const model = input.model || "openai/gpt-image-2"; let usd = IMAGE[model] ?? IMAGE_DEFAULT; - if (IMAGE_LARGE[model] && isLargerThanBase(input.size)) usd = IMAGE_LARGE[model]; + if (IMAGE_LARGE[model] && isLargerThanBase(model, input.size)) usd = IMAGE_LARGE[model]; return { usd, label: `image · ${model}` }; } case "video": { const model = input.model || "xai/grok-imagine-video"; const hasImage = Boolean(input.image_url || input.real_face_asset_id); - const rate = (hasImage ? VIDEO_RATE_IMAGE[model] : undefined) - ?? VIDEO_RATE[model] ?? VIDEO_DEFAULT_RATE; + const res = input.resolution; + let rate = VIDEO_RATE[model] ?? VIDEO_DEFAULT_RATE; + if (res && VIDEO_RATE_BY_RES[model]?.[res]) rate = VIDEO_RATE_BY_RES[model][res]; + else if (res && model.startsWith("bytedance/seedance-") && SEEDANCE_RES_FACTOR[res]) rate *= SEEDANCE_RES_FACTOR[res]; const secs = Number(input.duration_seconds) || VIDEO_DEFAULT_SECS[model] || 8; - return { usd: rate * secs, label: `video · ${model} · ${secs}s${hasImage ? " (i2v)" : ""}` }; + return { usd: rate * secs, label: `video · ${model} · ${secs}s${res ? ` · ${res}` : ""}${hasImage ? " (i2v)" : ""}` }; } case "music": return { usd: MUSIC_COST, label: `music · ${input.model || "minimax/music-2.5+"}` }; diff --git a/skills/announce-cost/SKILL.md b/skills/announce-cost/SKILL.md index 4a5ef64..c67fb47 100644 --- a/skills/announce-cost/SKILL.md +++ b/skills/announce-cost/SKILL.md @@ -24,32 +24,40 @@ If the user asked for several images/clips at once, announce the **total** ## Estimated pricing (USD) -**Image** (`blockrun_image`, 1024² base; `hd`/larger sizes cost more): +**Image** (`blockrun_image`, 1024² base list price; larger sizes cost more where a range is shown): | Model | ~Cost | |-------|-------| | `zai/cogview-4` | $0.015 | | `xai/grok-imagine-image` | $0.02 | | `openai/gpt-image-1` | $0.02–0.04 | +| `xai/grok-imagine-image-2.0` | $0.04 | +| `bytedance/seedream-5-pro` | $0.045–0.09 | | `google/nano-banana` | $0.05 | -| `xai/grok-imagine-image-pro` | $0.07 | +| `xai/grok-imagine-image-pro` | $0.05 | | `openai/gpt-image-2` (default) | $0.06–0.12 | +| `google/nano-banana-2` | $0.09 | | `google/nano-banana-pro` | $0.10–0.15 | +| `openai/gpt-image-2.5-flare` | $0.28–0.56 | +| `openai/gpt-image-2.5-sunburst` | $0.28–0.56 | -**Video** (`blockrun_video`, per second × duration): +**Video** (`blockrun_video`, per second × duration, at the model's default resolution): | Model | ~Cost/sec | |-------|-----------| -| `bytedance/seedance-2.0-fast` | $0.05 | -| `bytedance/seedance-1.5-pro` | $0.09 | -| `bytedance/seedance-2.0` | $0.12 | -| `xai/grok-imagine-video` (default) | $0.10 | -| `azure/sora-2` | $0.10 | - -e.g. `grok-imagine-video` 8s ≈ $0.80; `seedance-2.0-fast` 5s ≈ $0.25. - -**Other:** `blockrun_music` ≈ $0.02/track · `blockrun_speech` TTS ≈ $0.07/1k chars, -sound effect ≈ $0.0525 · `blockrun_realface` enroll/portrait ≈ $0.01 · paid stock -`blockrun_price` ≈ $0.001. +| `xai/grok-imagine-video` (default) | $0.05 (480p) · $0.07 (720p) | +| `xai/grok-imagine-video-1.5` | $0.08 (480p) · $0.14 (720p) · $0.25 (1080p) | +| `bytedance/seedance-1.5-pro` | $0.071 | +| `bytedance/seedance-2.0-mini` | $0.080 | +| `bytedance/seedance-2.0-fast` | $0.165 | +| `bytedance/seedance-2.0` | $0.227 (720p; ~2.25× at 1080p, ~9× at 4K) | +| `bytedance/seedance-2.5` | $0.316 | +| `azure/sora-2` | $0.105 | + +e.g. `grok-imagine-video` 8s ≈ $0.40; `seedance-2.0-fast` 5s ≈ $0.83. + +**Other:** `blockrun_music` ≈ $0.16/track · `blockrun_speech` TTS ≈ $0.05/1k chars +(flash/turbo) or $0.10/1k (multilingual-v2, v3), sound effect ≈ $0.0525 · +`blockrun_realface` enroll/portrait ≈ $0.01 · paid stock `blockrun_price` ≈ $0.001. These are estimates to inform the user; the gateway settles the exact amount.