-
Notifications
You must be signed in to change notification settings - Fork 649
feat: user dashboard #1354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: user dashboard #1354
Changes from all commits
3841add
8bb57ed
47f8dd0
c21433a
ba8d467
ed336bf
24ebd1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Plan | ||
|
|
||
| ## Data Model | ||
|
|
||
| - Add `deepchat_usage_stats` keyed by `message_id`. | ||
| - Store final per-message usage snapshots: | ||
| - session, provider, model | ||
| - input/output/total tokens | ||
| - cached input tokens | ||
| - estimated USD cost | ||
| - local usage date | ||
| - source (`backfill` or `live`) | ||
|
|
||
| ## Backfill | ||
|
|
||
| - Trigger in `AFTER_START` with a non-blocking hook. | ||
| - Scan only `deepchat_messages` joined with `deepchat_sessions`. | ||
| - Use message metadata provider/model first, then session fallback. | ||
| - Persist backfill status in config under `dashboardStatsBackfillV1`. | ||
| - Re-running is safe because stats rows are upserted by `message_id`. | ||
|
|
||
| ## Live Recording | ||
|
|
||
| - Extend stream usage metadata with optional `cached_tokens`. | ||
| - Persist cached input tokens into assistant message metadata. | ||
| - Upsert stats from `DeepChatMessageStore.finalizeAssistantMessage` and `setMessageError`. | ||
|
|
||
| ## Dashboard Query | ||
|
|
||
| - Expose `newAgentPresenter.getUsageDashboard()`. | ||
| - Aggregate summary, 365-day calendar, provider breakdown, and model breakdown from `deepchat_usage_stats`. | ||
|
|
||
| ## UI | ||
|
|
||
| - Add `DashboardSettings.vue` as a scrollable settings page. | ||
| - Keep the visual language aligned with the current project theme. | ||
| - Show loading, empty, running backfill, and failed backfill states. | ||
| - Render four summary cards only; remove the cache hit rate card from the dashboard overview. | ||
| - Adopt the official `shadcn-vue chart` component with `Unovis` for dashboard chart rendering. | ||
| - Rebuild the overview layout as `1 large + 3 small`, with total tokens as the hero chart. | ||
| - Replace the total-token number card with a donut-based hero chart that visualizes input/output ratio. | ||
| - Visualize cached input tokens with a compact horizontal stacked bar for cached versus uncached input. | ||
| - Visualize estimated cost with a 30-day area chart while keeping the total cost as the primary value. | ||
| - Reuse `recordingStartedAt` to render a locale-specific, number-first "days with DeepChat" summary card in the renderer. | ||
| - Keep provider/model ranking queries unchanged, but render them as horizontal token bar charts with internal scrolling. | ||
| - Translate changed dashboard copy per locale instead of falling back to English sentence structure. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Settings Dashboard | ||
|
|
||
| ## Goal | ||
|
|
||
| Add a dedicated dashboard page under settings to show token usage, cached token usage, estimated cost, and a GitHub-like contribution calendar. | ||
|
|
||
| ## User Stories | ||
|
|
||
| - As a user, I want to see my total token usage, cached token usage, and estimated cost in one place. | ||
| - As an existing user, I want the dashboard to initialize from the current `deepchat_messages` table once, without scanning legacy tables. | ||
| - As a user, I want the dashboard to keep growing from newly recorded usage without repeatedly recomputing from old chat tables. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| - A new settings route named `settings-dashboard` is available after provider settings. | ||
| - The dashboard reads from a dedicated `deepchat_usage_stats` table only. | ||
| - Existing users get a one-time background backfill from current `deepchat_messages`. | ||
| - Historical backfill sets cached input tokens to `0`. | ||
| - New assistant message finalization and error finalization upsert usage rows into `deepchat_usage_stats`. | ||
| - Price estimation uses current provider pricing first and falls back to `aihubmix` for the same model id when needed. | ||
| - The page contains four overview cards arranged as `1 large + 3 small`: a total-token hero chart, a cached-token ratio card, an estimated-cost trend card, and a days-with-DeepChat card. | ||
| - The total-token hero chart uses the shared `shadcn-vue chart + Unovis` visual language, keeps the donut semantics for input/output composition, and shows exact values plus percentages. | ||
| - The cached-token card uses the same chart system to visualize cached versus uncached input tokens and shows exact values plus percentages. | ||
| - The estimated-cost card uses the same chart system to show the total estimated cost plus a lightweight 30-day area trend. | ||
| - The "days with DeepChat" card is derived from the earliest recorded usage date and rendered in a number-first, locale-specific layout. | ||
| - The page contains a 365-day contribution calendar and provider/model breakdowns. | ||
| - Provider and model breakdown cards render horizontal token bar charts with internal scrolling without growing the full page indefinitely. | ||
|
|
||
| ## Non-Goals | ||
|
|
||
| - No backfill from legacy `messages` or `conversations` tables. | ||
| - No delete-triggered rollback of accumulated usage stats. | ||
| - No additional day-level rollup table in v1. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Tasks | ||
|
|
||
| 1. Add shared dashboard types and cached token usage plumbing. | ||
| 2. Add `deepchat_usage_stats` table and wire it into `SQLitePresenter`. | ||
| 3. Record live usage stats on assistant finalize and error finalize. | ||
| 4. Implement one-time historical backfill and dashboard query methods in `NewAgentPresenter`. | ||
| 5. Add settings route, dashboard page, and i18n strings. | ||
| 6. Add focused main/renderer tests and run format, i18n, and lint. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { LifecycleHook, LifecycleContext } from '@shared/presenter' | ||
| import { LifecyclePhase } from '@shared/lifecycle' | ||
| import { presenter } from '@/presenter' | ||
|
|
||
| export const usageStatsBackfillHook: LifecycleHook = { | ||
| name: 'usage-stats-backfill', | ||
| phase: LifecyclePhase.AFTER_START, | ||
| priority: 21, | ||
| critical: false, | ||
| execute: async (_context: LifecycleContext) => { | ||
| if (!presenter) { | ||
| throw new Error('usageStatsBackfillHook: Presenter not initialized') | ||
| } | ||
|
|
||
| const newAgentPresenter = presenter.newAgentPresenter as unknown as { | ||
| startUsageStatsBackfill?: () => Promise<void> | ||
| } | ||
| if (!newAgentPresenter.startUsageStatsBackfill) { | ||
| return | ||
| } | ||
|
|
||
| void newAgentPresenter.startUsageStatsBackfill().catch((error) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In the AFTER_START phase, this launches Useful? React with 👍 / 👎. |
||
| console.error('usageStatsBackfillHook: failed to start usage stats backfill:', error) | ||
| }) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.