mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-01 00:27:30 +00:00
fix(frontend): display image_output_tokens breakdown in usage pages
When image generation models are billed by token (channel pricing mode=token), the usage pages previously showed only image count format instead of detailed token breakdown. This fixes the display to properly show image output tokens separately from text output tokens.
This commit is contained in:
@@ -17,3 +17,24 @@ export function getBillingModeBadgeClass(mode: string | null | undefined): strin
|
||||
default: return 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300'
|
||||
}
|
||||
}
|
||||
|
||||
interface ImageBillingRow {
|
||||
image_count: number
|
||||
billing_mode?: string | null
|
||||
total_cost: number
|
||||
}
|
||||
|
||||
export function isImageUsage(row: Pick<ImageBillingRow, 'image_count' | 'billing_mode'> | null | undefined): boolean {
|
||||
return (row?.image_count ?? 0) > 0 && row?.billing_mode !== BILLING_MODE_TOKEN
|
||||
}
|
||||
|
||||
export function getDisplayBillingMode(row: Pick<ImageBillingRow, 'billing_mode' | 'image_count'> | null | undefined): string | null | undefined {
|
||||
return row?.billing_mode
|
||||
}
|
||||
|
||||
export function imageUnitPrice(row: Pick<ImageBillingRow, 'image_count' | 'total_cost'> | null): number {
|
||||
if (!row || row.image_count <= 0) return 0
|
||||
const total = row.total_cost ?? 0
|
||||
const price = total / row.image_count
|
||||
return Number.isFinite(price) ? price : 0
|
||||
}
|
||||
|
||||
@@ -2,6 +2,28 @@ import type { UsageLog } from '@/types'
|
||||
|
||||
type Translate = (key: string) => string
|
||||
|
||||
// --- Image output token / cost helpers ---
|
||||
|
||||
type ImageOutputTokenRow = Pick<UsageLog, 'output_tokens' | 'image_output_tokens'>
|
||||
type ImageOutputCostRow = Pick<UsageLog, 'image_output_cost'>
|
||||
|
||||
/** Whether the row contains any image-output tokens. */
|
||||
export const hasImageOutputTokens = (row: ImageOutputTokenRow | null | undefined): boolean =>
|
||||
(row?.image_output_tokens ?? 0) > 0
|
||||
|
||||
/**
|
||||
* Text-only output tokens (total output minus image-output).
|
||||
* Returns 0 when no text tokens exist.
|
||||
*/
|
||||
export const textOutputTokens = (row: ImageOutputTokenRow | null | undefined): number =>
|
||||
Math.max(0, (row?.output_tokens ?? 0) - (row?.image_output_tokens ?? 0))
|
||||
|
||||
/** Whether the row has a non-zero image-output cost. */
|
||||
export const hasImageOutputCost = (row: ImageOutputCostRow | null | undefined): boolean =>
|
||||
(row?.image_output_cost ?? 0) > 0
|
||||
|
||||
// --- Image size / billing helpers ---
|
||||
|
||||
const knownImageSizeSources = new Set(['output', 'input', 'default', 'legacy'])
|
||||
const knownImageBillingSizes = new Set(['1K', '2K', '4K', 'mixed'])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user