How 5ire’s Usage Analytics Feature Tracks API Calls and Token Consumption

The 5ire application instruments every chat session with model-specific token counters, persists the data to a local SQLite database, and aggregates costs by provider and model for real-time analytics.

The 5ire open-source chat client provides built-in usage analytics to help users monitor their AI spending. According to the nanbingxyz/5ire repository, the usage analytics feature tracks API calls and token consumption through a five-stage pipeline that spans token counting, database persistence, and statistical aggregation.

Token Counting with Model-Specific Helpers

Every API call begins with token counting to measure input and output usage. When a user submits a prompt, the application calls useToken().countInput(), and after receiving the model’s reply, it calls countOutput().

In src/hooks/useToken.ts, the hook selects the appropriate tokenizer based on the active model. The implementation delegates to model-specific utilities defined in src/utils/token.ts, including countGPTTokens, countTokensOfGemini, countTokensOfMoonshot, and countTokenOfLlama.

// Token counting during chat sessions (src/hooks/useToken.ts)
const inputTokens = await useToken().countInput(prompt);
const outputTokens = await useToken().countOutput(reply);

These helpers normalize token calculation across OpenAI, Gemini, Moonshot, and Llama models, ensuring accurate consumption metrics regardless of the provider.

Persisting Usage Data to SQLite

After token counts are calculated, the chat component persists the record to local storage. The useUsageStore in src/stores/useUsageStore.ts exposes a create() method that writes a row into the SQLite usages table.

The chat page at src/renderer/pages/chat/index.tsx triggers this persistence immediately after the model finishes generating a response:

// Recording usage after each chat response (src/renderer/pages/chat/index.tsx)
useUsageStore.getState().create({
  provider: providerCtx.name,
  model: modelCtx.label,
  inputTokens,
  outputTokens,
});

Database Schema

The usages table is defined in src/main/sqlite.ts (lines 33‑44) during application startup. It stores the provider name, model label, token counts, per-token pricing for cost analysis, and a Unix timestamp:

-- SQLite schema for usage tracking (src/main/sqlite.ts)
CREATE TABLE IF NOT EXISTS "usages" (
  "id" text(31),
  "provider" text,
  "model" text,
  "InputTokens" integer,
  "outputTokens" integer,
  "inputPrice" number,
  "outputPrice" NUMBER,
  "createdAt" integer,
  PRIMARY KEY ("id")
);

Aggregating Statistics and Rendering the UI

The Usage page queries aggregated statistics via the statistics(start, end) method in useUsageStore. This method executes a SQL query that sums inputTokens and outputTokens, then calculates monetary cost by applying the stored per-token prices.

// Aggregating usage by date range (src/stores/useUsageStore.ts)
await window.electron.db.all(`
  SELECT provider, model,
    sum(inputTokens) inputTokens,
    sum(outputTokens) outputTokens,
    round(sum(inputTokens * inputPrice / 1000), 4) AS inputCost,
    round(sum(outputTokens * outputPrice / 1000), 4) AS outputCost
  FROM usages
  WHERE createdAt >= ? AND createdAt <= ?
  GROUP BY provider, model
`, [startDateUnix, endDateUnix]);

The React page at src/renderer/pages/usage/index.tsx loads these aggregates within a useEffect hook, groups the rows by provider, and passes the data to a Grid component for visualization. Users can select start and end dates, and the UI automatically refreshes the charts and tables to reflect the filtered range.

// Loading and displaying stats in the UI (src/renderer/pages/usage/index.tsx)
const rows = await useUsageStore.getState().statistics(startDateUnix, endDateUnix);
const $statistics = groupBy(rows, 'provider');
setStatistics($statistics);

Summary

  • Token counting happens via the useToken hook, which delegates to model-specific helpers like countGPTTokens and countTokensOfGemini in src/utils/token.ts.
  • Usage records are stored in a local SQLite usages table defined in src/main/sqlite.ts, capturing provider, model, token counts, and per-token pricing.
  • Persistence is triggered by the chat component at src/renderer/pages/chat/index.tsx calling useUsageStore.getState().create() after each model response.
  • Aggregation is performed by the statistics() method in src/stores/useUsageStore.ts, which groups data by provider and model and calculates costs per 1,000 tokens.
  • Visualization is handled by the Usage page at src/renderer/pages/usage/index.tsx, which renders date-filtered analytics using React state and grid components.

Frequently Asked Questions

How does 5ire calculate token counts for different AI providers?

The application uses the useToken hook in src/hooks/useToken.ts to select the appropriate tokenizer. It delegates to provider-specific functions—countGPTTokens for OpenAI models, countTokensOfGemini for Google, countTokensOfMoonshot, and countTokenOfLlama—ensuring accurate counts regardless of the underlying API.

Where does 5ire store usage analytics data?

All usage data is written to a local SQLite database. The usages table, created during app startup in src/main/sqlite.ts, stores each API call’s provider, model, input and output token counts, per-token prices, and timestamp.

How does 5ire calculate the monetary cost of API calls?

Cost calculation happens during SQL aggregation. The statistics() method in src/stores/useUsageStore.ts runs a query that sums (inputTokens * inputPrice / 1000) and (outputTokens * outputPrice / 1000), rounding to four decimal places to produce the final input and output costs per provider-model combination.

Can users filter usage analytics by specific time periods?

Yes. The Usage page accepts start and end date parameters, converts them to Unix timestamps, and passes them to useUsageStore.getState().statistics(startDateUnix, endDateUnix). The underlying SQL query filters the usages table using createdAt >= ? AND createdAt <= ?, allowing users to view analytics for any custom date range.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →