Skip to content

AI

AiTokenUsageView

Bit.BlazorUI.AI

BitAiTokenUsageView is a compact readout of what a generation cost: its tokens, its money and its speed - the throughput in tokens per second and, on request, the time to the first token. Every figure is optional, because providers report different subsets of them and a row of blanks is worse than a short row: a figure the usage or the metadata does not carry is left out rather than shown empty. The breakdown of the tokens (input, output, cached and reasoning) is the native tooltip of the readout, and visually hidden text of it for the keyboard and screen readers. A message shows one under itself and a run view in its header when BitAiUiOptions.ShowUsage is on.

Notes

To use this component, you need to install the Bit.BlazorUI.AI(opens in a new tab) nuget package, as described in the Optional steps of the Getting started page.

The readout takes a BitAiTokenUsage - the Usage of a message's BitAiGenerationMetadata, the TotalUsage of a conversation, or the Usage of an agent run - and, for the speed and the latency, the BitAiGenerationMetadata itself. A transport reports them as BitAiUsageUpdatedEvents and BitAiMetadataEvents; the session times the generation. Its words and number formats come from the string table (BitAiStrings.Tokens, FormatTokens, TokensPerSecond, FormatDuration, UsageLine, TimeToFirstToken, and InputTokens, OutputTokens, CachedTokens and ReasoningTokens for the lines of the breakdown), in the culture of the page, which a BitAiOptionsProvider localizes; each figure reads in the direction its own words are written in, a right-to-left row included. A cost is written to the minor unit of its currency, and a cost of less than that unit - less than a cent - with two decimals more. Accessibility: the breakdown of the tokens is visually hidden text of the readout as well as its tooltip, which the keyboard, a touch screen and a screen reader never reach, and the latency is named (TimeToFirstToken) for a screen reader. See it under every message of the Models and usage scenario.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

Hand it a Usage: it shows the total of the input and output tokens, shortened (1.6k), and lists them one by one in its tooltip - point at it.

1.6k tokensInput: 1,240 Output: 386

Cost

A usage with a Cost shows it in its Currency (USD when there is none): $, € and £ by their symbols, any other ISO 4217 code by its code. It is written to the minor unit of its currency - two decimals for the dollar, none for the yen - and a fraction of that unit, what most single requests cost, keeps two decimals more rather than reading as nothing.

1.6k tokensInput: 1,240 Output: 386 $0.0095 206.5k tokensInput: 182,000 Output: 24,500 $0.91 311k tokensInput: 250,000 Output: 61,000 €1.25 1.3M tokensInput: 1,250,000 Output: 92,000 JPY 420

Speed & latency

Given the Metadata of the generation, the readout adds its throughput - the output tokens per second of streaming, after the first token - and, with ShowLatency, the time to the first token. ShowSpeed false leaves the throughput off.

1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/s 1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms 1.6k tokensInput: 1,240 Output: 386 $0.0095Time to first token 400ms

Breakdown

The tooltip has a line for every kind of token the provider reported: input, output, cached input and hidden reasoning - and so has the visually hidden text a screen reader reads after the total. A title splatted onto the readout replaces the tooltip.

14.3k tokensInput: 12,400 Output: 1,860 Cached: 9,800 Reasoning: 1,100 $0.03 14.3k tokensInput: 12,400 Output: 1,860 Cached: 9,800 Reasoning: 1,100 $0.03

A live conversation

Real accounting from a scripted transport of this site: every turn reports its tokens and cost, priced with the rates of the model, and the session times it. Each answer shows its own usage with its speed and latency, and the conversation its TotalUsage, which adds the turns field by field.



Disabled

A disabled readout is drawn in the disabled color, every figure alike - for a message of a conversation that is no longer active, say. It still shows every figure and keeps its tooltip.

1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms

Cascading parameters

BitParams with a BitAiTokenUsageViewParams sets which figures every readout inside it shows, and its look - the readouts of the messages of a chat included - and a readout's own value still wins (the last shows its speed).

1.6k tokensInput: 1,240 Output: 386 $0.0095Time to first token 400ms 1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms

Style & Class

Style and Class reach the root, Styles and Classes each figure - the tokens, the cost, the speed and the latency. The public --bit-AiTokenUsageView-* variables re-skin the readouts from :root, an ancestor or Style.

1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/s 1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms 1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/s

RTL

In right-to-left text the figures are laid out from right to left, whether the direction comes from Dir or from a dir attribute around the readout.

1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms
1.6k tokensInput: 1,240 Output: 386 $0.009580.4 tok/sTime to first token 400ms

CSS variables

The public custom properties this component reads off its root, for what no parameter covers.

Every variable is read with a fallback and never declared by the component, so it inherits like any other custom property: set one on :root (or in a [bit-theme] block) to restyle every instance, on any ancestor to restyle the ones inside it, or on the Style of one instance to restyle it - and any instance nested inside it, which inherits the value too; a parameter changes one alone, as does the real CSS property on the instance's Style / Styles when that property does not inherit (opacity: 1 keeps one disabled instance undimmed without undimming a disabled one inside it), while an inherited one such as color or font-family also reaches the nested instances that do not set it themselves. Leave a variable unset and the component falls back to the theme token beside it.

BitAiTokenUsageView CSS variables

Name Default value Description
--bit-AiTokenUsageView-color var(--bit-clr-fg-sec) Text of the readout.
--bit-AiTokenUsageView-font-size var(--bit-tpg-fs-xs) Size of the readout.
--bit-AiTokenUsageView-gap spacing(1.5) Room between two figures.

API

Every parameter, public member, sub-class and enum this component exposes.

BitAiTokenUsageView parameters

Name Type Default value Description
Classes BitAiTokenUsageViewClassStyles? null Custom CSS classes for different parts of the token usage view.
Metadata BitAiGenerationMetadata? null The metadata of the generation, which supplies the speed (TokensPerSecond) and the latency (TimeToFirstToken). Without it the readout shows the tokens and the cost alone.
ShowLatency bool false Shows the time to the first token, when the Metadata carries it.
ShowSpeed bool true Shows the throughput in tokens per second, when the Metadata carries what it is computed from (the output tokens, the start and the end of the generation).
Styles BitAiTokenUsageViewClassStyles? null Custom CSS styles for different parts of the token usage view.
Usage BitAiTokenUsage The usage to show (required): its total of tokens (shortened, 1.6k), its cost in its currency, and - as the native tooltip - a line for each kind of token it reports. A figure it does not carry is left out rather than shown empty.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
Disabled bool false Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name.
Id string? null Gets or sets the unique identifier for the component's root element.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitAiTokenUsageViewClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the BitAiTokenUsageView.
Tokens string? null Custom CSS classes/styles for the token count of the BitAiTokenUsageView.
Cost string? null Custom CSS classes/styles for the cost of the BitAiTokenUsageView.
Speed string? null Custom CSS classes/styles for the throughput of the BitAiTokenUsageView.
Latency string? null Custom CSS classes/styles for the time to the first token of the BitAiTokenUsageView.

BitAiTokenUsage properties

The token accounting of one or more generations, a readonly record struct: new BitAiTokenUsage { InputTokens = ..., OutputTokens = ... }. Every field is optional, because providers report different subsets. Usages add up field by field (usage + other), which is how a message totals the requests of a tool loop and a run the requests made within it; a field missing on both sides stays missing, so a total never claims a zero the provider did not report.

Name Type Default value Description
InputTokens long? null The tokens consumed by the prompt.
OutputTokens long? null The tokens produced by the model.
CachedInputTokens long? null The input tokens served from a provider-side prompt cache.
CacheWriteTokens long? null The input tokens written to a provider-side prompt cache.
ReasoningTokens long? null The tokens spent on hidden reasoning, where the provider reports it separately.
Cost decimal? null The cost in the currency named by Currency, when the host can compute it (BitAiModel.EstimateCost prices a usage with the rates of a model).
Currency string? null The ISO 4217 code of the Cost. USD when a cost is present without one.
TotalTokens long? null The input and the output tokens summed, when either is present.
IsEmpty bool true Whether no field carries a value.
operator + BitAiTokenUsage usage + other (or BitAiTokenUsage.Add(usage, other)): adds two usages field by field, keeping a field absent on both sides absent.
Merge BitAiTokenUsage BitAiTokenUsage.Merge(existing, update): overlays a newer snapshot on an older one field by field - a field the update reports replaces the old value, one it omits keeps it. How a message accumulates usage from a provider that reports the input tokens first and the output tokens at the end.

BitAiGenerationMetadata properties

Everything known about how a message was produced, separate from what it says (BitAiMessage.Metadata) - held apart from the message body so that the streaming updates never touch it. A transport reports it as BitAiMetadataEvent and BitAiUsageUpdatedEvent; the session adds the timings. A sealed record.

Name Type Default value Description
ModelId string? null The identifier of the model that produced the message.
ProviderId string? null The identifier of the provider that served the request.
Usage BitAiTokenUsage The token accounting of the generation.
FinishReason BitAiFinishReason BitAiFinishReason.Unknown Why the generation stopped.
StartedAt DateTimeOffset? null When the request was sent.
CompletedAt DateTimeOffset? null When the last event arrived.
TimeToFirstToken TimeSpan? null The time from the request to the first streamed token - the latency the readout shows with ShowLatency.
Duration TimeSpan? null The total wall-clock duration of the generation, when both StartedAt and CompletedAt are known.
TokensPerSecond double? null The output tokens per second over the streaming window (the duration less the time to the first token), or null when it cannot be computed from the reported values - the speed the readout shows.
Temperature double? null The sampling temperature used, when reported.
ContextWindow long? null The size of the context window of the model in tokens, which a BitAiContextMeter reads off a conversation.
Extra IReadOnlyDictionary<string, object?>? null Provider-specific values that do not map onto the fields above.

BitAiFinishReason enum

Name Value Description
Unknown 0 The reason was not reported by the provider.
Stop 1 The model reached a natural end.
Length 2 The output hit the token limit.
ToolCalls 3 The model stopped to call one or more tools.
ContentFilter 4 The provider's safety system stopped the generation.
Cancelled 5 The caller cancelled the generation.
Error 6 The generation failed.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.