Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/server/providers/dashscope-cn-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,39 @@ describe('DashScope China native source parsing', () => {
'unreadable RMB token quote: 13元 未知后缀:1.3元',
)
})
it('bills 原价N元 (限时X折) at the fold of list price, with no invented end', () => {
const cell = '原价2元 (限时2.5折)'
const quoted = (
input: string,
output = '原价6元 (限时2.5折)',
): CnDoc => ({
...prices,
text: `## 文本生成-第三方模型\n<Tabs><Tab title="华北2(北京)"><table><tr><th>模型 ID(Model ID)</th><th>输入单价(每百万Token)</th><th>输出单价(每百万Token)</th></tr><tr><td>antdigital/Ling-3.1-flash</td><td>${input}</td><td>${output}</td></tr></table></Tab></Tabs>`,
})
const [row] = cnPriceModels(quoted(cell))
const card = rateCardSchema.parse(row!.pricing)
expect(row!.rawId).toBe('antdigital/Ling-3.1-flash')
expect(cardCurrency(card)).toBe('CNY')
expect(card.source.expiresAt).toBeUndefined()
expect(
price(card, {}, { input_tokens: 1_000_000, output_tokens: 0 }),
).toBeCloseTo(0.5)
expect(
price(card, {}, { input_tokens: 0, output_tokens: 1_000_000 }),
).toBeCloseTo(1.5)
const eight = rateCardSchema.parse(
cnPriceModels(quoted('原价2元 (限时8折)', '8元'))[0]!.pricing,
)
expect(
price(eight, {}, { input_tokens: 1_000_000, output_tokens: 0 }),
).toBeCloseTo(1.6)
expect(() => cnPriceModels(quoted('原价2元 (限时优惠)'))).toThrow(
'unreadable RMB token quote: 原价2元 (限时优惠)',
)
expect(() =>
cnPriceModels(quoted('原价2元 (限时2.5折至2026-12-31)')),
).toThrow('unreadable RMB token quote: 原价2元 (限时2.5折至2026-12-31)')
})
it('reads a price cell that tiers itself by prompt size', () => {
const tiered = (input: string, output: string): CnDoc => ({
...prices,
Expand Down
22 changes: 17 additions & 5 deletions src/server/providers/dashscope-cn-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,27 @@ interface YuanQuote {
}
/**
* A plain cell is `<n>元`. It may also state the cache-hit input rate:
* `13元 缓存命中输入:1.3元`. Any other suffix throws.
* `13元 缓存命中输入:1.3元`.
*
* `原价2元 (限时2.5折)` states a list price and the share billed while
* the promo runs (N折 = N/10 of list, so 2.5折 of 2元 is 0.5元). The cell
* names no end, so the card carries no `expiresAt` (#552). Any other promo
* wording throws.
*/
function plainQuote(text: string): YuanQuote {
const match =
/^(\d+(?:\.\d+)?)元(?:\s+缓存命中输入:(\d+(?:\.\d+)?)元)?$/.exec(text)
if (!match) fail(`unreadable RMB token quote: ${text}`)
const quote: YuanQuote = { rate: yuanPerMillion(match[1]!) }
if (match[2] !== undefined) quote.cacheRead = yuanPerMillion(match[2])
return quote
if (match) {
const quote: YuanQuote = { rate: yuanPerMillion(match[1]!) }
if (match[2] !== undefined) quote.cacheRead = yuanPerMillion(match[2])
return quote
}
const promo = /^原价(\d+(?:\.\d+)?)元\s*(限时(\d+(?:\.\d+)?)折)$/.exec(text)
if (!promo) fail(`unreadable RMB token quote: ${text}`)
const fold = Number(promo[2])
// 10折 is the list price. Above that, or a zero fold, is not this wording.
if (!(fold > 0) || fold > 10) fail(`unreadable RMB token quote: ${text}`)
return { rate: yuanPerMillion(String(Number(promo[1]) * (fold / 10))) }
}
/**
* One quote per prompt-size floor. A cell may tier itself, as MiniMax-M3's
Expand Down
Loading