@linxiraos/pi-stats 1.1.26 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +12 -5
  2. package/build.ts +4 -0
  3. package/dist/client/favicon.ico +0 -0
  4. package/dist/client/index.css +1 -1
  5. package/dist/client/index.html +1 -0
  6. package/dist/client/index.js +96 -96
  7. package/dist/types/aggregator.d.ts +4 -1
  8. package/dist/types/client/api.d.ts +5 -1
  9. package/dist/types/client/app/nav.d.ts +5 -2
  10. package/dist/types/client/data/formatters.d.ts +7 -2
  11. package/dist/types/client/data/live.d.ts +16 -11
  12. package/dist/types/client/data/query-store.d.ts +39 -0
  13. package/dist/types/client/data/query.d.ts +10 -5
  14. package/dist/types/client/data/range.d.ts +4 -3
  15. package/dist/types/client/i18n/format.d.ts +9 -0
  16. package/dist/types/client/i18n/index.d.ts +18 -0
  17. package/dist/types/client/i18n/messages/charts.d.ts +8 -0
  18. package/dist/types/client/i18n/messages/common.d.ts +153 -0
  19. package/dist/types/client/i18n/messages/costs.d.ts +92 -0
  20. package/dist/types/client/i18n/messages/en.d.ts +1255 -0
  21. package/dist/types/client/i18n/messages/errors.d.ts +78 -0
  22. package/dist/types/client/i18n/messages/frustration.d.ts +191 -0
  23. package/dist/types/client/i18n/messages/gain.d.ts +54 -0
  24. package/dist/types/client/i18n/messages/models.d.ts +94 -0
  25. package/dist/types/client/i18n/messages/nav.d.ts +46 -0
  26. package/dist/types/client/i18n/messages/overview.d.ts +80 -0
  27. package/dist/types/client/i18n/messages/projects.d.ts +84 -0
  28. package/dist/types/client/i18n/messages/providers.d.ts +142 -0
  29. package/dist/types/client/i18n/messages/requests.d.ts +72 -0
  30. package/dist/types/client/i18n/messages/tools.d.ts +119 -0
  31. package/dist/types/client/i18n/messages/traces.d.ts +144 -0
  32. package/dist/types/client/i18n/messages/ui.d.ts +44 -0
  33. package/dist/types/client/i18n/messages/zh-CN.d.ts +13 -0
  34. package/dist/types/client/i18n/types.d.ts +15 -0
  35. package/dist/types/client/traces/Minimap.d.ts +2 -0
  36. package/dist/types/client/traces/TimelineCanvas.d.ts +29 -8
  37. package/dist/types/client/traces/TranscriptList.d.ts +3 -1
  38. package/dist/types/db.d.ts +14 -21
  39. package/dist/types/embedded-client.d.ts +5 -0
  40. package/dist/types/frustration.d.ts +18 -9
  41. package/dist/types/live.d.ts +5 -3
  42. package/dist/types/locale.d.ts +16 -0
  43. package/dist/types/parser.d.ts +0 -17
  44. package/dist/types/rollup.d.ts +9 -1
  45. package/dist/types/server.d.ts +6 -0
  46. package/dist/types/shared-types.d.ts +7 -0
  47. package/dist/types/trace.d.ts +18 -6
  48. package/dist/types/types.d.ts +13 -1
  49. package/dist/types/user-metrics.d.ts +23 -1
  50. package/package.json +5 -5
  51. package/src/aggregator.ts +31 -11
  52. package/src/client/api.ts +40 -5
  53. package/src/client/app/LiveChip.tsx +14 -13
  54. package/src/client/app/Shell.tsx +19 -13
  55. package/src/client/app/ThemeToggle.tsx +4 -3
  56. package/src/client/app/nav.ts +19 -16
  57. package/src/client/data/formatters.ts +80 -13
  58. package/src/client/data/live.tsx +85 -45
  59. package/src/client/data/query-store.ts +108 -0
  60. package/src/client/data/query.ts +47 -56
  61. package/src/client/data/range.ts +34 -14
  62. package/src/client/data/series.ts +7 -1
  63. package/src/client/favicon.ico +0 -0
  64. package/src/client/i18n/format.ts +28 -0
  65. package/src/client/i18n/index.ts +53 -0
  66. package/src/client/i18n/messages/charts.ts +8 -0
  67. package/src/client/i18n/messages/common.ts +157 -0
  68. package/src/client/i18n/messages/costs.ts +104 -0
  69. package/src/client/i18n/messages/en.ts +40 -0
  70. package/src/client/i18n/messages/errors.ts +80 -0
  71. package/src/client/i18n/messages/frustration.ts +198 -0
  72. package/src/client/i18n/messages/gain.ts +54 -0
  73. package/src/client/i18n/messages/models.ts +94 -0
  74. package/src/client/i18n/messages/nav.ts +46 -0
  75. package/src/client/i18n/messages/overview.ts +90 -0
  76. package/src/client/i18n/messages/projects.ts +84 -0
  77. package/src/client/i18n/messages/providers.ts +165 -0
  78. package/src/client/i18n/messages/requests.ts +73 -0
  79. package/src/client/i18n/messages/tools.ts +120 -0
  80. package/src/client/i18n/messages/traces.ts +160 -0
  81. package/src/client/i18n/messages/ui.ts +46 -0
  82. package/src/client/i18n/messages/zh-CN.ts +43 -0
  83. package/src/client/i18n/types.ts +19 -0
  84. package/src/client/index.tsx +4 -0
  85. package/src/client/routes/CostsRoute.tsx +61 -48
  86. package/src/client/routes/ErrorsRoute.tsx +71 -47
  87. package/src/client/routes/FrustrationRoute.tsx +131 -116
  88. package/src/client/routes/GainRoute.tsx +42 -30
  89. package/src/client/routes/ModelsRoute.tsx +90 -73
  90. package/src/client/routes/OverviewRoute.tsx +109 -63
  91. package/src/client/routes/ProjectsRoute.tsx +73 -46
  92. package/src/client/routes/ProvidersRoute.tsx +151 -114
  93. package/src/client/routes/RequestsRoute.tsx +69 -46
  94. package/src/client/routes/ToolsRoute.tsx +108 -94
  95. package/src/client/routes/TracesRoute.tsx +25 -23
  96. package/src/client/styles.css +5 -2
  97. package/src/client/traces/AggregatesPanel.tsx +19 -8
  98. package/src/client/traces/Minimap.tsx +65 -27
  99. package/src/client/traces/SpanDrawer.tsx +46 -21
  100. package/src/client/traces/SummaryStrip.tsx +27 -11
  101. package/src/client/traces/TimelineCanvas.tsx +245 -116
  102. package/src/client/traces/TraceView.tsx +51 -36
  103. package/src/client/traces/TranscriptList.tsx +20 -11
  104. package/src/client/traces/traces.css +26 -0
  105. package/src/client/ui/JsonBlock.tsx +3 -2
  106. package/src/client/ui/Modal.tsx +3 -2
  107. package/src/client/ui/RequestDrawer.tsx +33 -30
  108. package/src/client/ui/SearchInput.tsx +2 -1
  109. package/src/client/ui/States.tsx +3 -2
  110. package/src/client/ui/Table.tsx +7 -3
  111. package/src/db.ts +150 -135
  112. package/src/embedded-client.ts +9 -0
  113. package/src/frustration.ts +9 -30
  114. package/src/index.ts +2 -1
  115. package/src/live.ts +36 -11
  116. package/src/locale.ts +29 -0
  117. package/src/parser.ts +37 -72
  118. package/src/port-conflict.ts +1 -1
  119. package/src/prompts/judge/frustration.json +19 -0
  120. package/src/rollup.ts +41 -20
  121. package/src/server.ts +67 -27
  122. package/src/shared-types.ts +7 -0
  123. package/src/trace.ts +54 -40
  124. package/src/types.ts +13 -1
  125. package/src/user-metrics.ts +220 -6
@@ -13,11 +13,14 @@ export declare function withStatsSyncLock<T>(dbPath: string, fn: () => Promise<T
13
13
  * `current` is the number of files completed (skipped + parsed),
14
14
  * `total` is the size of the work set. `processed` is the running total
15
15
  * of inserted rows. Parsed files are reported only after their batch commits.
16
+ * `changes` is the running total of stored rows the sync inserted, updated or
17
+ * deleted (0 while every transcript is unchanged).
16
18
  */
17
19
  export interface SyncProgress {
18
20
  current: number;
19
21
  total: number;
20
22
  processed: number;
23
+ changes: number;
21
24
  sessionFile: string;
22
25
  }
23
26
  export interface SyncOptions {
@@ -37,7 +40,7 @@ export interface SyncOptions {
37
40
  }
38
41
  /**
39
42
  * Smoke test: spawns one sync worker, pings it, asserts the pong response,
40
- * then terminates. Used by `omp --smoke-test` so the install-method CI jobs
43
+ * then terminates. Used by `zetacode --smoke-test` so the install-method CI jobs
41
44
  * catch the silent worker-load failure that hit compiled binaries in #1011
42
45
  * and #1027 — neither `--version` nor `stats --summary` exercises the worker
43
46
  * spawn path on a fresh install (no session files = early return), so a
@@ -25,7 +25,11 @@ export declare function getProviderDashboardStats(range?: TimeRange, signal?: Ab
25
25
  /** Subscription-window insights (all providers) plus utilization series for `provider` only. */
26
26
  export declare function getProviderWindowStats(range: TimeRange, provider: string | null, signal?: AbortSignal): Promise<ProviderWindowStats>;
27
27
  export declare function getSessions(limit?: number, q?: string, signal?: AbortSignal): Promise<SessionSummary[]>;
28
- export declare function getSessionTrace(file: string, signal?: AbortSignal): Promise<SessionTrace>;
28
+ /**
29
+ * Pass the last trace for `file` as `previous` to revalidate it: an unchanged
30
+ * trace resolves to that same object without downloading or parsing the body.
31
+ */
32
+ export declare function getSessionTrace(file: string, signal?: AbortSignal, previous?: SessionTrace): Promise<SessionTrace>;
29
33
  /** Fetch one full journal entry for the span drawer. Entries are opaque JSON. */
30
34
  export declare function getSessionEntryDetail(file: string, id: string, signal?: AbortSignal): Promise<{
31
35
  entry: unknown;
@@ -1,14 +1,17 @@
1
1
  import { type LucideIcon } from "lucide-react";
2
+ import type { MessageKey } from "../i18n/index.js";
2
3
  export type DashboardSection = "overview" | "models" | "providers" | "costs" | "requests" | "errors" | "traces" | "tools" | "frustration" | "projects" | "gain";
3
4
  export interface NavItem {
4
5
  id: DashboardSection;
5
- label: string;
6
+ /** Message key of the sidebar label; render through `t`. */
7
+ labelKey: MessageKey;
6
8
  icon: LucideIcon;
7
9
  /** Second key of the `g <key>` jump shortcut. */
8
10
  hotkey: string;
9
11
  }
10
12
  export interface NavGroup {
11
- heading: string;
13
+ /** Message key of the group heading; render through `t`. */
14
+ headingKey: MessageKey;
12
15
  items: readonly NavItem[];
13
16
  }
14
17
  /** Sidebar structure; the order here is the order on screen. */
@@ -14,12 +14,17 @@ export declare function isUnpricedMessage(message: Pick<MessageStats, "provider"
14
14
  /** Format one request's cost, distinguishing unpriced usage from free usage. */
15
15
  export declare function formatMessageCost(message: Pick<MessageStats, "provider" | "usage" | "costUnpriced">, digits?: number): string;
16
16
  export declare function formatPercent(value: number, digits?: number): string;
17
+ /** Show small nonzero failure rates without rounding them to zero. */
18
+ export declare function formatErrorRate(value: number): string;
17
19
  export declare function formatDurationMs(value: number | null, digits?: number): string;
18
20
  /** Wall-clock length: seconds below a minute, then `17m 41s` / `2h 05m`. */
19
21
  export declare function formatElapsed(ms: number): string;
20
22
  export declare function formatTokensPerSecond(value: number | null): string;
21
- export declare function formatRelativeTime(timestamp: number): string;
22
- /** Absolute local date and time to the second ("Sep 28, 14:03:22"). */
23
+ /** "2 minutes ago" / "2 分钟前" — the ladder picks the largest unit the delta reaches. */
24
+ export declare function formatRelativeTime(timestamp: number, now?: number): string;
25
+ /** Local month/day plus minute ("Sep 28 14:03" / "9月28日 14:03") for chart range captions. */
26
+ export declare function formatDateTimeShort(timestamp: number): string;
27
+ /** Absolute local date and time to the second ("Sep 28, 14:03:22" / "9月28日 14:03:22"). */
23
28
  export declare function formatTimestamp(timestamp: number): string;
24
29
  /** Project folder as stored by ingest (`/work-pi/`), without the slashes. */
25
30
  export declare function formatFolder(folder: string): string;
@@ -3,18 +3,14 @@
3
3
  * version every query revalidates against, background ingest progress, and
4
4
  * the rollup indexing backlog.
5
5
  *
6
- * Any component can `useLive()`; queries (see `useQuery`) refetch whenever
7
- * `version` advances, so rows ingested in the background repaint the active
8
- * page without a manual refresh.
6
+ * The state lives in a module store read through narrow selectors, so a
7
+ * progress tick only re-renders what shows progress: `useLiveVersion()` for
8
+ * queries (see `useQuery`), `useLiveStatus()` for the chrome.
9
9
  */
10
10
  import { type ReactNode } from "react";
11
11
  import type { LiveSyncStatus } from "../types.js";
12
- export interface LiveState {
13
- /**
14
- * Client-side data version; bumps whenever the server's version changes
15
- * (including after reconnecting to a restarted server).
16
- */
17
- version: number;
12
+ /** Ingest status shown by the chrome. */
13
+ export interface LiveStatusView {
18
14
  sync: LiveSyncStatus;
19
15
  /** Hours whose rollups are still being built; wide ranges may be incomplete. */
20
16
  indexingHours: number;
@@ -23,7 +19,16 @@ export interface LiveState {
23
19
  /** Ask the server to ingest new session data now. */
24
20
  requestSync: () => void;
25
21
  }
22
+ /** Current data version, read outside render (e.g. when a fetch starts). */
23
+ export declare function currentLiveVersion(): number;
24
+ /** Owns the `/api/events` stream; mount once at the app root. */
26
25
  export declare function LiveProvider({ children }: {
27
26
  children: ReactNode;
28
- }): import("react").JSX.Element;
29
- export declare function useLive(): LiveState;
27
+ }): ReactNode;
28
+ /** Ingest status for the chrome; data-version bumps alone don't re-render. */
29
+ export declare function useLiveStatus(): LiveStatusView;
30
+ /**
31
+ * Data version for queries. Disabled (hidden) consumers read a constant -1 so
32
+ * live traffic never re-renders them.
33
+ */
34
+ export declare function useLiveVersion(enabled?: boolean): number;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Framework-free query cache behind `useQuery`: per-key cached results in
3
+ * size-bounded buckets, and one shared in-flight request per key that is
4
+ * aborted once its last waiter leaves.
5
+ */
6
+ export interface CacheEntry {
7
+ data: unknown;
8
+ updatedAt: number;
9
+ version: number;
10
+ }
11
+ export interface Inflight {
12
+ promise: Promise<unknown>;
13
+ controller: AbortController;
14
+ /** Queries (and prefetches) waiting on this request. */
15
+ waiters: number;
16
+ }
17
+ /** Handed to every fetcher. */
18
+ export interface QueryFetchContext {
19
+ /** Aborted once no query waits for this request any more. */
20
+ signal: AbortSignal;
21
+ }
22
+ /**
23
+ * Loads one key's data. `previous` is the cached data for this key, for
24
+ * conditional revalidation; `undefined` on first load. It is a separate
25
+ * parameter so fetchers that ignore it still let `T` be inferred from their
26
+ * return type.
27
+ */
28
+ export type QueryFetcher<T> = (context: QueryFetchContext, previous: T | undefined) => Promise<T>;
29
+ export declare function cachedEntry(key: string): CacheEntry | undefined;
30
+ /** The shared request currently running for `key`, if any. */
31
+ export declare function inflightRequest(key: string): Inflight | undefined;
32
+ /**
33
+ * Fetch into the cache (tagged with live data `version`), sharing one request
34
+ * among concurrent callers of the same key. The caller holds one waiter on
35
+ * the returned request; pair with {@link releaseQuery}.
36
+ */
37
+ export declare function loadQuery<T>(key: string, version: number, fetcher: QueryFetcher<T>): Inflight;
38
+ /** Drop one waiter; the last one out aborts the request. */
39
+ export declare function releaseQuery(key: string, request: Inflight): void;
@@ -2,14 +2,19 @@
2
2
  * `useQuery`: cached, live-revalidating data fetching for dashboard pages.
3
3
  *
4
4
  * - Results are cached per key for the page session, so revisiting a page or
5
- * a range renders instantly from memory.
5
+ * a range renders instantly from memory. Multi-MB detail payloads (traces,
6
+ * request details) live in their own small LRUs so they don't pile up.
6
7
  * - A key change keeps the previous key's data on screen (`stale: true`) until
7
8
  * the new data lands, so charts morph instead of flashing skeletons.
8
9
  * - Every cached entry remembers the live data version it was fetched at
9
- * (see `useLive`); when the version advances, enabled queries refetch in the
10
- * background, throttled so a burst of ingest batches costs one request.
11
- * - Identical keys share one in-flight request.
10
+ * (see `useLiveVersion`); when the version advances, enabled queries refetch
11
+ * in the background, throttled so a burst of ingest batches costs one request.
12
+ * - Identical keys share one in-flight request; it is aborted once no query
13
+ * waits for it any more.
14
+ * - Fetchers receive the cached data for their key, so conditional requests
15
+ * can resolve to that same object; an unchanged reference does not re-render.
12
16
  */
17
+ import { type QueryFetcher } from "./query-store.js";
13
18
  export interface QueryOptions {
14
19
  /** Only enabled queries fetch; hidden (kept-alive) pages pass `false`. Default true. */
15
20
  enabled?: boolean;
@@ -32,4 +37,4 @@ export interface QueryResult<T> {
32
37
  }
33
38
  /** Warm the cache for a key the user is likely to open next. No-op if cached for this version. */
34
39
  export declare function prefetchQuery<T>(key: readonly unknown[], fetcher: () => Promise<T>, version: number): void;
35
- export declare function useQuery<T>(key: readonly unknown[], fetcher: () => Promise<T>, options?: QueryOptions): QueryResult<T>;
40
+ export declare function useQuery<T>(key: readonly unknown[], fetcher: QueryFetcher<T>, options?: QueryOptions): QueryResult<T>;
@@ -3,12 +3,13 @@
3
3
  * for the range (mirrors `getTimeRangeConfig` in `aggregator.ts`), tick
4
4
  * formatting, and the contiguous bucket axis charts plot against.
5
5
  */
6
+ import { type MessageKey } from "../i18n/index.js";
6
7
  import type { TimeRange } from "../types.js";
7
8
  export interface RangeMeta {
8
- /** Short selector label ("24h"). */
9
- label: string;
9
+ /** Short selector label ("24h"); translated so the selector reads in the host language. */
10
+ labelKey: MessageKey;
10
11
  /** Prose label for subtitles ("the last 24 hours"). */
11
- windowLabel: string;
12
+ windowKey: MessageKey;
12
13
  /** Span covered by the range; `null` for all time. */
13
14
  spanMs: number | null;
14
15
  /** Bucket size of the server's primary time series for this range. */
@@ -0,0 +1,9 @@
1
+ import type { MessagesByLocale, StatsLocale, TranslationParams } from "./types.js";
2
+ /** Substitute `{name}` placeholders; unknown names are left verbatim so a bug is visible, not silent. */
3
+ export declare function interpolateMessage(message: string, params?: TranslationParams): string;
4
+ /**
5
+ * Resolve a message for `locale`, falling back to English and finally to the
6
+ * key itself. The key fallback is deliberate: a renamed key renders its slug
7
+ * rather than blanking a card, so a missed rename is visible but not fatal.
8
+ */
9
+ export declare function translateMessage(locale: StatsLocale, key: string, messages: MessagesByLocale, params?: TranslationParams): string;
@@ -0,0 +1,18 @@
1
+ import { type MessageKey } from "./messages/en.js";
2
+ import type { StatsLocale, TranslationParams } from "./types.js";
3
+ /** The locale the dashboard renders in. Fixed at boot; there is no in-page switcher. */
4
+ export declare function getLocale(): StatsLocale;
5
+ /** Install a locale by tag (`zh`, `zh-CN`, `zh-Hans`; anything else is English). */
6
+ export declare function setLocale(tag: string | undefined | null): StatsLocale;
7
+ /**
8
+ * The locale to boot with: the host's language when `zeta-c stats` injected it,
9
+ * then the browser's own preference, then English.
10
+ */
11
+ export declare function resolveInitialLocale(): StatsLocale;
12
+ /**
13
+ * Translate `key` in the active locale; `{name}` placeholders substitute from
14
+ * `params`. The key type is the English catalogue, so an unknown key is a
15
+ * compile error rather than a silently blank card.
16
+ */
17
+ export declare function t(key: MessageKey, params?: TranslationParams): string;
18
+ export type { MessageKey, StatsLocale, TranslationParams };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Charts copy. Keys are slugs (`charts.<name>`); the English string is the
3
+ * source of truth and `zh-CN` overrides it.
4
+ */
5
+ export declare const charts: {
6
+ readonly en: {};
7
+ readonly "zh-CN": {};
8
+ };
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Cross-page vocabulary. Every route derives its column headers and card
3
+ * labels from here when the term matches, so one glossary drives the whole
4
+ * dashboard (Providers is 服务商 everywhere, Tokens is Token everywhere).
5
+ *
6
+ * `shell.*` covers the frame: top bar, live chip, theme toggle.
7
+ */
8
+ export declare const common: {
9
+ readonly en: {
10
+ readonly "common.provider": "Provider";
11
+ readonly "common.providers": "Providers";
12
+ readonly "common.model": "Model";
13
+ readonly "common.models": "Models";
14
+ readonly "common.requests": "Requests";
15
+ readonly "common.request": "Request";
16
+ readonly "common.tokens": "Tokens";
17
+ readonly "common.share": "Share";
18
+ readonly "common.cost": "Cost";
19
+ readonly "common.error-rate": "Error rate";
20
+ readonly "common.tokens-per-second": "Tokens/s";
21
+ readonly "common.output-tokens-per-second": "Output tokens/s";
22
+ readonly "common.premium": "Premium";
23
+ readonly "common.premium-requests": "Premium requests";
24
+ readonly "common.duration": "Duration";
25
+ readonly "common.started": "Started";
26
+ readonly "common.request-id": "Request id";
27
+ readonly "common.session-entry": "Session entry";
28
+ readonly "common.entry-id": "Entry id";
29
+ readonly "common.input": "Input";
30
+ readonly "common.output": "Output";
31
+ readonly "common.output-message": "Output message";
32
+ readonly "common.cache-read": "Cache read";
33
+ readonly "common.cache-write": "Cache write";
34
+ readonly "common.project": "Project";
35
+ readonly "common.pages": "Pages";
36
+ readonly "common.filter": "Filter…";
37
+ readonly "common.no-data-in-range": "No data in this range";
38
+ readonly "common.nothing-here-yet": "Nothing here yet";
39
+ readonly "common.show-more": "Show more";
40
+ readonly "common.total": "Total";
41
+ readonly "common.average": "Average";
42
+ readonly "common.unknown": "Unknown";
43
+ readonly "common.root": "(root)";
44
+ readonly "common.other-n": "Other ({count})";
45
+ readonly "common.time-range": "Time range";
46
+ readonly "common.range-1h": "1h";
47
+ readonly "common.range-24h": "24h";
48
+ readonly "common.range-7d": "7d";
49
+ readonly "common.range-30d": "30d";
50
+ readonly "common.range-90d": "90d";
51
+ readonly "common.range-all": "All";
52
+ readonly "common.window-1h": "the last hour";
53
+ readonly "common.window-24h": "the last 24 hours";
54
+ readonly "common.window-7d": "the last 7 days";
55
+ readonly "common.window-30d": "the last 30 days";
56
+ readonly "common.window-90d": "the last 90 days";
57
+ readonly "common.window-all": "all time";
58
+ readonly "common.copy": "Copy";
59
+ readonly "common.copied": "Copied";
60
+ readonly "common.close": "Close";
61
+ readonly "common.cancel": "Cancel";
62
+ readonly "common.aborted": "Aborted";
63
+ readonly "common.failed": "Failed";
64
+ readonly "common.error": "Error";
65
+ readonly "shell.live": "Live";
66
+ readonly "shell.reconnecting": "Reconnecting";
67
+ readonly "shell.syncing": "Syncing";
68
+ readonly "shell.sync-failed": "Sync failed";
69
+ readonly "shell.indexing": "Indexing";
70
+ readonly "shell.lost-connection": "Lost the live connection to the stats server; retrying";
71
+ readonly "shell.ingesting": "Ingesting session files";
72
+ readonly "shell.building-rollups": "Building hourly rollups; older ranges fill in as it goes";
73
+ readonly "shell.sync-now": "Click to sync session files now";
74
+ readonly "shell.just-now": "just now";
75
+ readonly "shell.system-theme": "System theme";
76
+ readonly "shell.dark-theme": "Dark theme";
77
+ readonly "shell.light-theme": "Light theme";
78
+ readonly "shell.range-suffix": "range";
79
+ readonly "shell.jump-hint": "then letter to jump";
80
+ };
81
+ readonly "zh-CN": {
82
+ readonly "common.provider": "服务商";
83
+ readonly "common.providers": "服务商";
84
+ readonly "common.model": "模型";
85
+ readonly "common.models": "模型";
86
+ readonly "common.requests": "请求";
87
+ readonly "common.request": "请求";
88
+ readonly "common.tokens": "Token";
89
+ readonly "common.share": "占比";
90
+ readonly "common.cost": "费用";
91
+ readonly "common.error-rate": "错误率";
92
+ readonly "common.tokens-per-second": "Token/秒";
93
+ readonly "common.output-tokens-per-second": "输出 Token/秒";
94
+ readonly "common.premium": "溢价";
95
+ readonly "common.premium-requests": "溢价请求";
96
+ readonly "common.duration": "耗时";
97
+ readonly "common.started": "开始时间";
98
+ readonly "common.request-id": "请求 ID";
99
+ readonly "common.session-entry": "会话条目";
100
+ readonly "common.entry-id": "条目 ID";
101
+ readonly "common.input": "输入";
102
+ readonly "common.output": "输出";
103
+ readonly "common.output-message": "输出消息";
104
+ readonly "common.cache-read": "缓存读取";
105
+ readonly "common.cache-write": "缓存写入";
106
+ readonly "common.project": "项目";
107
+ readonly "common.pages": "页数";
108
+ readonly "common.filter": "筛选…";
109
+ readonly "common.no-data-in-range": "该时间范围内没有数据";
110
+ readonly "common.nothing-here-yet": "暂无数据";
111
+ readonly "common.show-more": "显示更多";
112
+ readonly "common.total": "合计";
113
+ readonly "common.average": "平均";
114
+ readonly "common.unknown": "未知";
115
+ readonly "common.root": "(根目录)";
116
+ readonly "common.other-n": "其他({count})";
117
+ readonly "common.time-range": "时间范围";
118
+ readonly "common.range-1h": "1 小时";
119
+ readonly "common.range-24h": "24 小时";
120
+ readonly "common.range-7d": "7 天";
121
+ readonly "common.range-30d": "30 天";
122
+ readonly "common.range-90d": "90 天";
123
+ readonly "common.range-all": "全部";
124
+ readonly "common.window-1h": "最近 1 小时";
125
+ readonly "common.window-24h": "最近 24 小时";
126
+ readonly "common.window-7d": "最近 7 天";
127
+ readonly "common.window-30d": "最近 30 天";
128
+ readonly "common.window-90d": "最近 90 天";
129
+ readonly "common.window-all": "全部时间";
130
+ readonly "common.copy": "复制";
131
+ readonly "common.copied": "已复制";
132
+ readonly "common.close": "关闭";
133
+ readonly "common.cancel": "取消";
134
+ readonly "common.aborted": "已中止";
135
+ readonly "common.failed": "失败";
136
+ readonly "common.error": "错误";
137
+ readonly "shell.live": "实时";
138
+ readonly "shell.reconnecting": "重新连接中";
139
+ readonly "shell.syncing": "同步中";
140
+ readonly "shell.sync-failed": "同步失败";
141
+ readonly "shell.indexing": "建立索引";
142
+ readonly "shell.lost-connection": "与统计服务的实时连接已断开,正在重试";
143
+ readonly "shell.ingesting": "正在导入会话文件";
144
+ readonly "shell.building-rollups": "正在构建小时汇总;更早的时间范围会逐步补全";
145
+ readonly "shell.sync-now": "点击立即同步会话文件";
146
+ readonly "shell.just-now": "刚刚";
147
+ readonly "shell.system-theme": "跟随系统";
148
+ readonly "shell.dark-theme": "深色主题";
149
+ readonly "shell.light-theme": "浅色主题";
150
+ readonly "shell.range-suffix": "范围";
151
+ readonly "shell.jump-hint": "再按字母跳转";
152
+ };
153
+ };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Costs copy. Keys are slugs (`costs.<name>`); the English string is the
3
+ * source of truth and `zh-CN` overrides it.
4
+ */
5
+ export declare const costs: {
6
+ readonly en: {
7
+ readonly "costs.title": "Costs";
8
+ readonly "costs.description": "What {window} of usage would cost at public API rates. Subscription usage without a public price is counted as unpriced, not free.";
9
+ readonly "costs.no-usage-in-range": "No usage in this range";
10
+ readonly "costs.empty-hint": "Pick a wider range in the top bar.";
11
+ readonly "costs.daily-estimate": "Daily estimate";
12
+ readonly "costs.daily-by-model": "Per UTC day, stacked by model";
13
+ readonly "costs.daily-by-component": "Per UTC day, stacked by billing component";
14
+ readonly "costs.split-by": "Split by";
15
+ readonly "costs.by-model": "By model";
16
+ readonly "costs.by-component": "By component";
17
+ readonly "costs.no-priced-usage": "No priced usage in this range";
18
+ readonly "costs.unpriced-requests": "Unpriced requests";
19
+ readonly "costs.where-it-went": "Where it went";
20
+ readonly "costs.estimate-by-component": "Estimate by billing component";
21
+ readonly "costs.unpriced-note-one": "{count} unpriced subscription request is not included.";
22
+ readonly "costs.unpriced-note-n": "{count} unpriced subscription requests are not included.";
23
+ readonly "costs.by-model-description": "Estimate per model with its input, output and cache split";
24
+ readonly "costs.estimate": "Estimate";
25
+ readonly "costs.estimate-title": "API-equivalent estimate at public rates";
26
+ readonly "costs.split": "Split";
27
+ readonly "costs.split-title": "Input · output · cache read · cache write";
28
+ readonly "costs.per-request": "Per request";
29
+ readonly "costs.per-request-title": "Estimate ÷ priced requests";
30
+ readonly "costs.unpriced": "Unpriced";
31
+ readonly "costs.unpriced-column-title": "Requests with no public-equivalent price";
32
+ readonly "costs.api-equivalent-estimate": "API-equivalent estimate";
33
+ readonly "costs.api-estimate-title": "What this usage would cost at public API rates";
34
+ readonly "costs.requests-n": "{count} requests";
35
+ readonly "costs.average-per-day": "Average per day";
36
+ readonly "costs.average-per-day-title": "Estimate ÷ days with any usage";
37
+ readonly "costs.active-days-one": "over {count} active day";
38
+ readonly "costs.active-days-n": "over {count} active days";
39
+ readonly "costs.top-model": "Top model";
40
+ readonly "costs.top-model-hint": "{cost} · {share} of estimate";
41
+ readonly "costs.nothing-priced-yet": "Nothing priced yet";
42
+ readonly "costs.per-priced-request": "Per priced request";
43
+ readonly "costs.per-priced-request-title": "Estimate ÷ requests that have a public price";
44
+ readonly "costs.priced-n": "{count} priced";
45
+ readonly "costs.unpriced-title": "Subscription usage with no public-equivalent price; excluded from the estimate";
46
+ readonly "costs.unpriced-hint": "excluded from the estimate";
47
+ readonly "costs.all-priced": "all usage priced";
48
+ };
49
+ readonly "zh-CN": {
50
+ readonly "costs.title": "费用";
51
+ readonly "costs.description": "按公开 API 费率计算,{window}的用量需要多少费用。没有公开价格的订阅用量计为未定价,而不是免费。";
52
+ readonly "costs.no-usage-in-range": "此时间范围内没有用量";
53
+ readonly "costs.empty-hint": "请在顶栏选择更宽的时间范围。";
54
+ readonly "costs.daily-estimate": "每日估算";
55
+ readonly "costs.daily-by-model": "按 UTC 日统计,按模型堆叠";
56
+ readonly "costs.daily-by-component": "按 UTC 日统计,按计费组件堆叠";
57
+ readonly "costs.split-by": "拆分依据";
58
+ readonly "costs.by-model": "按模型";
59
+ readonly "costs.by-component": "按组件";
60
+ readonly "costs.no-priced-usage": "此时间范围内没有已定价的用量";
61
+ readonly "costs.unpriced-requests": "未定价请求";
62
+ readonly "costs.where-it-went": "费用去向";
63
+ readonly "costs.estimate-by-component": "按计费组件估算";
64
+ readonly "costs.unpriced-note-one": "{count} 个未定价的订阅请求未计入。";
65
+ readonly "costs.unpriced-note-n": "{count} 个未定价的订阅请求未计入。";
66
+ readonly "costs.by-model-description": "按模型估算,并附输入、输出与缓存的拆分";
67
+ readonly "costs.estimate": "估算";
68
+ readonly "costs.estimate-title": "按公开费率计算的 API 等效估算";
69
+ readonly "costs.split": "拆分";
70
+ readonly "costs.split-title": "输入 · 输出 · 缓存读取 · 缓存写入";
71
+ readonly "costs.per-request": "单次请求";
72
+ readonly "costs.per-request-title": "估算值 ÷ 已定价请求数";
73
+ readonly "costs.unpriced": "未定价";
74
+ readonly "costs.unpriced-column-title": "没有公开等效价格的请求";
75
+ readonly "costs.api-equivalent-estimate": "API 等效估算";
76
+ readonly "costs.api-estimate-title": "此用量按公开 API 费率计算需要多少费用";
77
+ readonly "costs.requests-n": "{count} 个请求";
78
+ readonly "costs.average-per-day": "日均";
79
+ readonly "costs.average-per-day-title": "估算值 ÷ 有用量的天数";
80
+ readonly "costs.active-days-one": "共 {count} 个活跃日";
81
+ readonly "costs.active-days-n": "共 {count} 个活跃日";
82
+ readonly "costs.top-model": "费用最高的模型";
83
+ readonly "costs.top-model-hint": "{cost} · 占估算值的 {share}";
84
+ readonly "costs.nothing-priced-yet": "暂无已定价用量";
85
+ readonly "costs.per-priced-request": "单个已定价请求";
86
+ readonly "costs.per-priced-request-title": "估算值 ÷ 有公开价格的请求数";
87
+ readonly "costs.priced-n": "已定价 {count} 个";
88
+ readonly "costs.unpriced-title": "没有公开等效价格的订阅用量;不计入估算";
89
+ readonly "costs.unpriced-hint": "不计入估算";
90
+ readonly "costs.all-priced": "全部用量均已定价";
91
+ };
92
+ };