Skip to content

Commit f3f8a6c

Browse files
committed
feat: update pricing columns
1 parent 513d797 commit f3f8a6c

6 files changed

Lines changed: 36 additions & 44 deletions

File tree

scripts/build-search-index.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,17 @@ async function getModelArtifactSearchItems() {
184184
const tariffs = model.tariffs || [];
185185
const pricingRows = [];
186186
const realtime = tariffs.find((t) => t.api_key_purpose === "realtime");
187-
const batch1h = tariffs.find((t) => t.api_key_purpose === "batch" && t.completion_window?.includes("1h"));
187+
const asyncTariff = tariffs.find((t) => t.api_key_purpose === "batch" && t.completion_window?.includes("1h"));
188188
const batch24h = tariffs.find((t) => t.api_key_purpose === "batch" && t.completion_window?.includes("24h"));
189189

190190
if (realtime) {
191191
pricingRows.push(`Realtime: ${formatPricePer1M(realtime.input_price_per_token)} input / ${formatPricePer1M(realtime.output_price_per_token)} output`);
192192
}
193-
if (batch1h) {
194-
pricingRows.push(`High (1h): ${formatPricePer1M(batch1h.input_price_per_token)} input / ${formatPricePer1M(batch1h.output_price_per_token)} output`);
193+
if (asyncTariff) {
194+
pricingRows.push(`Async: ${formatPricePer1M(asyncTariff.input_price_per_token)} input / ${formatPricePer1M(asyncTariff.output_price_per_token)} output`);
195195
}
196196
if (batch24h) {
197-
pricingRows.push(`Standard (24h): ${formatPricePer1M(batch24h.input_price_per_token)} input / ${formatPricePer1M(batch24h.output_price_per_token)} output`);
197+
pricingRows.push(`Batch (24h): ${formatPricePer1M(batch24h.input_price_per_token)} input / ${formatPricePer1M(batch24h.output_price_per_token)} output`);
198198
}
199199

200200
return {

src/components/ContentInjector.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { useEffect, useRef } from 'react'
1212
* - {{selectedModel.id}} - Selected model ID
1313
* - {{selectedModel.name}} - Selected model name
1414
* - {{selectedModel.description}} - Selected model description
15-
* - {{selectedModel.pricing.batch1h.input}} - Model 1hr SLA batch input price per token
16-
* - {{selectedModel.pricing.batch1h.output}} - Model 1hr SLA batch output price per token
15+
* - {{selectedModel.pricing.async.input}} - Model async batch input price per token
16+
* - {{selectedModel.pricing.async.output}} - Model async batch output price per token
1717
* - {{selectedModel.pricing.batch24h.input}} - Model 24hr SLA batch input price per token
1818
* - {{selectedModel.pricing.batch24h.output}} - Model 24hr SLA batch output price per token
1919
* - {{selectedModel.pricing.realtime.input}} - Model realtime input price per token
@@ -68,16 +68,16 @@ export default function ContentInjector() {
6868
`<span style="color:#98C379">${selectedModel.name || selectedModel.id}</span>`
6969
)
7070

71-
// Handle pricing placeholders (1hr SLA batch pricing)
72-
const batch1hPricing = selectedModel.pricing?.batch1h
73-
if (batch1hPricing) {
71+
// Handle pricing placeholders (async batch pricing)
72+
const asyncPricing = selectedModel.pricing?.async
73+
if (asyncPricing) {
7474
newHtml = newHtml.replace(
75-
/\{\{selectedModel\.pricing\.batch1h\.input\}\}/g,
76-
String(batch1hPricing.input)
75+
/\{\{selectedModel\.pricing\.async\.input\}\}/g,
76+
String(asyncPricing.input)
7777
)
7878
newHtml = newHtml.replace(
79-
/\{\{selectedModel\.pricing\.batch1h\.output\}\}/g,
80-
String(batch1hPricing.output)
79+
/\{\{selectedModel\.pricing\.async\.output\}\}/g,
80+
String(asyncPricing.output)
8181
)
8282
}
8383

src/components/ModelSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export default function ModelSelector() {
122122
</div>
123123
{models.map((model) => {
124124
const isSelected = selectedModel?.id === model.id
125-
const pricing = model.pricing?.batch24h || model.pricing?.batch1h || model.pricing?.realtime
125+
const pricing = model.pricing?.batch24h || model.pricing?.async || model.pricing?.realtime
126126

127127
return (
128128
<button

src/lib/model-artifacts.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe("renderModelArtifactMarkdown", () => {
2222
description: "Model body content",
2323
pricing: [
2424
{
25-
priority: "High (1h)",
25+
priority: "Async",
2626
inputTokensPer1M: "$0.05",
2727
outputTokensPer1M: "$0.08",
2828
},
@@ -33,7 +33,7 @@ describe("renderModelArtifactMarkdown", () => {
3333
expect(markdown).not.toContain("[Back to inference docs](/inference-api)");
3434
expect(markdown).toContain("![Qwen Test icon](https://example.com/icon.png)");
3535
expect(markdown).toContain("Open this model in the [Playground](https://example.com/playground).");
36-
expect(markdown).toContain("| High (1h) | $0.05 | $0.08 |");
36+
expect(markdown).toContain("| Async | $0.05 | $0.08 |");
3737
expect(markdown).not.toContain("**Model ID:** `Qwen/Test`");
3838
expect(markdown).toContain("**Type:** chat");
3939
expect(markdown).toContain("Model body content");

src/lib/model-artifacts.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,6 @@ function formatPricePer1M(pricePerToken: number): string {
4444
return `$${(pricePerToken * 1_000_000).toFixed(2)}`;
4545
}
4646

47-
function getFromPrice(type: string, pricing: ModelArtifactPricingRow[]): string {
48-
if (pricing.length === 0) return "—";
49-
50-
const useInputPricing = type.toLowerCase() === "embedding";
51-
const cheapestPrice = pricing.reduce((lowest, row) => {
52-
const source = useInputPricing ? row.inputTokensPer1M : row.outputTokensPer1M;
53-
const value = Number(source.replace(/[^0-9.]/g, ""));
54-
return Number.isFinite(value) ? Math.min(lowest, value) : lowest;
55-
}, Number.POSITIVE_INFINITY);
56-
57-
if (!Number.isFinite(cheapestPrice)) return "—";
58-
return `from $${cheapestPrice.toFixed(2)}/M`;
59-
}
60-
6147
function renderProvider(providerName?: string): string {
6248
if (!providerName) return "—";
6349
return providerName || "—";
@@ -74,17 +60,17 @@ function buildPricing(model: Model): ModelArtifactPricingRow[] {
7460
});
7561
}
7662

77-
if (model.pricing.batch1h) {
63+
if (model.pricing.async) {
7864
rows.push({
79-
priority: "High (1h)",
80-
inputTokensPer1M: formatPricePer1M(model.pricing.batch1h.input),
81-
outputTokensPer1M: formatPricePer1M(model.pricing.batch1h.output),
65+
priority: "Async",
66+
inputTokensPer1M: formatPricePer1M(model.pricing.async.input),
67+
outputTokensPer1M: formatPricePer1M(model.pricing.async.output),
8268
});
8369
}
8470

8571
if (model.pricing.batch24h) {
8672
rows.push({
87-
priority: "Standard (24h)",
73+
priority: "Batch (24h)",
8874
inputTokensPer1M: formatPricePer1M(model.pricing.batch24h.input),
8975
outputTokensPer1M: formatPricePer1M(model.pricing.batch24h.output),
9076
});
@@ -123,17 +109,23 @@ export async function getModelArtifact(slug: string): Promise<ModelArtifact | nu
123109
export async function getModelsIndexMarkdown(): Promise<string> {
124110
const artifacts = await getModelArtifacts();
125111

112+
const formatTierCell = (artifact: ModelArtifact, priority: string): string => {
113+
const row = artifact.pricing.find((p) => p.priority === priority);
114+
if (!row) return "—";
115+
return `${row.inputTokensPer1M} in / ${row.outputTokensPer1M} out`;
116+
};
117+
126118
const overviewTable = [
127-
"| Model | Provider | Type | Pricing |",
128-
"|-------|----------|------|---------|",
119+
"| Model | Provider | Type | Realtime | Async | Batch (24h) |",
120+
"|-------|----------|------|----------|-------|-------------|",
129121
...artifacts.map((artifact) => {
130-
return `| [${artifact.name}](${getModelArtifactPath(artifact.slug)}) | ${renderProvider(artifact.providerName)} | ${artifact.type} | ${getFromPrice(artifact.type, artifact.pricing)} |`;
122+
return `| [${artifact.name}](${getModelArtifactPath(artifact.slug)}) | ${renderProvider(artifact.providerName)} | ${artifact.type} | ${formatTierCell(artifact, "Realtime")} | ${formatTierCell(artifact, "Async")} | ${formatTierCell(artifact, "Batch (24h)")} |`;
131123
}),
132124
].join("\n");
133125

134126
return `Doubleword Batch API is priced per model based on token usage. Costs are calculated separately for input tokens (the content you send) and output tokens (the content generated by the model).
135127
136-
The table below outlines the models we have available and their pricing. If you are interested in understanding pricing for a model not listed below or if you'd like to request a new model - please reach out to support@doubleword.ai.
128+
The table below outlines the models we have available and their pricing per 1M tokens. If you are interested in understanding pricing for a model not listed below or if you'd like to request a new model - please reach out to support@doubleword.ai.
137129
138130
## Model Catalog
139131

src/lib/models.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface Model {
1818
type: string
1919
capabilities: string[]
2020
pricing: {
21-
batch1h: ModelPricing | null // 1 hour SLA batch
21+
async: ModelPricing | null // Async batch
2222
batch24h: ModelPricing | null // 24 hour SLA batch
2323
realtime: ModelPricing | null // Real-time API
2424
}
@@ -103,7 +103,7 @@ function transformModels(
103103
rawModels: RawModel[],
104104
): Model[] {
105105
return rawModels.map((m) => {
106-
const batch1hTariff = m.tariffs?.find(t => t.api_key_purpose === 'batch' && t.completion_window?.includes('1h'))
106+
const asyncTariff = m.tariffs?.find(t => t.api_key_purpose === 'batch' && t.completion_window?.includes('1h'))
107107
const batch24hTariff = m.tariffs?.find(t => t.api_key_purpose === 'batch' && t.completion_window?.includes('24h'))
108108
const realtimeTariff = m.tariffs?.find(t => t.api_key_purpose === 'realtime')
109109
const providerObject =
@@ -119,9 +119,9 @@ function transformModels(
119119
type: formatModelType(m.metadata?.display_category || m.overwrite_type || m.model_type),
120120
capabilities: m.capabilities || [],
121121
pricing: {
122-
batch1h: batch1hTariff ? {
123-
input: parseFloat(batch1hTariff.input_price_per_token),
124-
output: parseFloat(batch1hTariff.output_price_per_token),
122+
async: asyncTariff ? {
123+
input: parseFloat(asyncTariff.input_price_per_token),
124+
output: parseFloat(asyncTariff.output_price_per_token),
125125
} : null,
126126
batch24h: batch24hTariff ? {
127127
input: parseFloat(batch24hTariff.input_price_per_token),

0 commit comments

Comments
 (0)