diff --git a/frontend/src/utils/__tests__/billingMode.spec.ts b/frontend/src/utils/__tests__/billingMode.spec.ts new file mode 100644 index 0000000000..d7009b0eea --- /dev/null +++ b/frontend/src/utils/__tests__/billingMode.spec.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest' +import { + BILLING_MODE_IMAGE, + BILLING_MODE_TOKEN, + BILLING_MODE_VIDEO, + getDisplayBillingMode, + isImageUsage +} from '../billingMode' + +describe('billingMode helpers', () => { + it('prefers explicit video mode over image_count', () => { + expect( + getDisplayBillingMode({ image_count: 1, billing_mode: BILLING_MODE_VIDEO }) + ).toBe(BILLING_MODE_VIDEO) + expect(isImageUsage({ image_count: 1, billing_mode: BILLING_MODE_VIDEO })).toBe(false) + }) + + it('infers image when image_count set and mode missing', () => { + expect(getDisplayBillingMode({ image_count: 2, billing_mode: null })).toBe(BILLING_MODE_IMAGE) + }) + + it('keeps token mode even with image_count', () => { + expect( + getDisplayBillingMode({ image_count: 1, billing_mode: BILLING_MODE_TOKEN }) + ).toBe(BILLING_MODE_TOKEN) + }) +}) diff --git a/frontend/src/utils/billingMode.ts b/frontend/src/utils/billingMode.ts index 1ba03ed377..628441fb72 100644 --- a/frontend/src/utils/billingMode.ts +++ b/frontend/src/utils/billingMode.ts @@ -32,6 +32,10 @@ export function isImageUsage(row: Pick | null | undefined): string | null | undefined { + // Explicit video/token modes always win over image_count heuristics. + if (row?.billing_mode === BILLING_MODE_VIDEO || row?.billing_mode === BILLING_MODE_TOKEN) { + return row.billing_mode + } if ((row?.image_count ?? 0) > 0 && !row?.billing_mode) { return BILLING_MODE_IMAGE } diff --git a/frontend/src/views/user/UsageView.vue b/frontend/src/views/user/UsageView.vue index aa788a2b04..d836936a5a 100644 --- a/frontend/src/views/user/UsageView.vue +++ b/frontend/src/views/user/UsageView.vue @@ -231,7 +231,7 @@ import Icon from '@/components/icons/Icon.vue' import UserErrorRequestsTable from '@/components/user/UserErrorRequestsTable.vue' import { getPersistedPageSize } from '@/composables/usePersistedPageSize' import { formatReasoningEffort } from '@/utils/format' -import { BILLING_MODE_IMAGE, getBillingModeLabel } from '@/utils/billingMode' +import { getBillingModeLabel, getDisplayBillingMode as resolveDisplayBillingMode } from '@/utils/billingMode' import { resolveUsageRequestType, requestTypeToLegacyStream } from '@/utils/usageRequestType' import type { ApiKey, @@ -605,10 +605,7 @@ const getRequestTypeExportText = (log: UsageLog): string => { const getDisplayBillingMode = ( row: Pick | null | undefined -): string | null | undefined => { - if ((row?.image_count ?? 0) > 0) return BILLING_MODE_IMAGE - return row?.billing_mode -} +): string | null | undefined => resolveDisplayBillingMode(row) const escapeCSVValue = (value: unknown): string => { if (value == null) return ''