Skip to content

Commit d762542

Browse files
author
guanchen.lin
committed
fix: refine price index change feed
1 parent 6aecaf3 commit d762542

4 files changed

Lines changed: 34 additions & 15 deletions

File tree

src/app/[locale]/reports/api-price-index/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export default async function ApiPriceIndexPage({
131131
<p className="mt-3 leading-7 text-zinc-600 dark:text-zinc-400">
132132
{locale === 'zh'
133133
? '每个主模型只保留当前最低价渠道。美元值仅用于排序,账单仍以供应商显示的原始币种为准。'
134-
: 'Each primary model is represented by its lowest current channel. The USD value is only for ranking; billing remains in the provider’s displayed currency.'}
134+
: 'Each model identifier is represented by its lowest current channel. The USD value is only for ranking; billing remains in the provider’s displayed currency.'}
135135
</p>
136136
</div>
137137
<div className="mt-6 overflow-x-auto rounded-md border bg-white dark:bg-zinc-900">
@@ -172,8 +172,8 @@ export default async function ApiPriceIndexPage({
172172
</h2>
173173
<p className="mt-3 leading-7 text-zinc-600 dark:text-zinc-400">
174174
{locale === 'zh'
175-
? '以下记录来自价格历史表,仅在抓取器发现显著变化时写入。'
176-
: 'These records come from the price history log, written when the collector detects a material change.'}
175+
? '以下为价格历史表中每个渠道最近一次显著价格变化。'
176+
: 'These records show the latest material change for each channel in the price history log.'}
177177
</p>
178178
</div>
179179
{snapshot.recentChanges.length > 0 ? (

src/lib/api-price-index.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,17 +86,25 @@ export async function getPriceIndexSnapshot(): Promise<PriceIndexSnapshot> {
8686
WHERE m.type ILIKE '%llm%' AND cp.input_price_per_1m > 0
8787
`,
8888
sql<ChangeRow[]>`
89-
SELECT m.name AS model_name, m.slug AS model_slug,
90-
p.name AS provider_name, p.slug AS provider_slug,
91-
ph.old_input_price, ph.new_input_price,
92-
ph.old_output_price, ph.new_output_price,
93-
ph.change_percent, ph.currency, ph.recorded_at
94-
FROM price_history ph
95-
JOIN api_channel_prices cp ON cp.id = ph.channel_price_id
96-
JOIN models m ON m.id = cp.model_id
97-
JOIN providers p ON p.id = cp.provider_id
98-
WHERE m.type ILIKE '%llm%'
99-
ORDER BY ph.recorded_at DESC
89+
SELECT model_name, model_slug, provider_name, provider_slug,
90+
old_input_price, new_input_price, old_output_price,
91+
new_output_price, change_percent, currency, recorded_at
92+
FROM (
93+
SELECT DISTINCT ON (ph.channel_price_id)
94+
m.name AS model_name, m.slug AS model_slug,
95+
p.name AS provider_name, p.slug AS provider_slug,
96+
ph.old_input_price, ph.new_input_price,
97+
ph.old_output_price, ph.new_output_price,
98+
ph.change_percent, ph.currency, ph.recorded_at,
99+
ph.channel_price_id
100+
FROM price_history ph
101+
JOIN api_channel_prices cp ON cp.id = ph.channel_price_id
102+
JOIN models m ON m.id = cp.model_id
103+
JOIN providers p ON p.id = cp.provider_id
104+
WHERE m.type ILIKE '%llm%'
105+
ORDER BY ph.channel_price_id, ph.recorded_at DESC
106+
) latest_channel_changes
107+
ORDER BY recorded_at DESC
100108
LIMIT 12
101109
`,
102110
]);

src/lib/model-names.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ test('formats common model slugs as readable product names', () => {
77
assert.equal(formatModelName('claude-opus-4.8'), 'Claude Opus 4.8');
88
assert.equal(formatModelName('glm-5.2-(free)'), 'GLM 5.2 (Free)');
99
assert.equal(formatModelName('qwen3.5-397b-a17b'), 'Qwen3.5 397B A17B');
10+
assert.equal(formatModelName('zai-glm-5-2'), 'Z.ai GLM 5.2');
11+
assert.equal(formatModelName('gpt-oss-120b'), 'GPT OSS 120B');
12+
assert.equal(formatModelName('qwen3-vl-flash'), 'Qwen3 VL Flash');
1013
});
1114

1215
test('preserves already-readable numeric and mixed-case labels', () => {

src/lib/model-names.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ const TOKEN_LABELS: Record<string, string> = {
1616
mistral: 'Mistral',
1717
mixtral: 'Mixtral',
1818
openai: 'OpenAI',
19+
oss: 'OSS',
1920
qwen: 'Qwen',
21+
vl: 'VL',
22+
zai: 'Z.ai',
2023
};
2124

2225
function formatToken(token: string): string {
@@ -39,8 +42,13 @@ export function formatModelName(value: string): string {
3942
const trimmed = value.trim();
4043
if (!trimmed) return value;
4144

42-
return trimmed
45+
const normalized = trimmed
4346
.replace(/_/g, '-')
47+
.replace(/\b(glm|gpt)-(\d+)-(\d+)(?=$|-)/gi, '$1-$2.$3')
48+
.replace(/\b((?:claude-)?(?:opus|sonnet|haiku))-(\d+)-(\d+)(?=$|-)/gi, '$1-$2.$3')
49+
.replace(/\b(k\d+)-(\d+)(?=$|-)/gi, '$1.$2');
50+
51+
return normalized
4452
.split('-')
4553
.filter(Boolean)
4654
.map(formatToken)

0 commit comments

Comments
 (0)