diff --git a/frontend-modern/src/api/ai.ts b/frontend-modern/src/api/ai.ts index 3779d81..f0f9643 100644 --- a/frontend-modern/src/api/ai.ts +++ b/frontend-modern/src/api/ai.ts @@ -7,6 +7,7 @@ import type { AIExecuteRequest, AIExecuteResponse, AIStreamEvent, + AICostSummary, } from '@/types/ai'; export class AIAPI { @@ -44,6 +45,11 @@ export class AIAPI { return apiFetchJSON(`${this.baseUrl}/ai/models`) as Promise<{ models: { id: string; name: string; description?: string }[]; error?: string }>; } + // Get AI cost/usage summary + static async getCostSummary(days = 30): Promise { + return apiFetchJSON(`${this.baseUrl}/ai/cost/summary?days=${days}`) as Promise; + } + // Start OAuth flow for Claude Pro/Max subscription // Returns the authorization URL to redirect the user to static async startOAuth(): Promise<{ auth_url: string; state: string }> { diff --git a/frontend-modern/src/components/AI/AICostDashboard.tsx b/frontend-modern/src/components/AI/AICostDashboard.tsx new file mode 100644 index 0000000..817824c --- /dev/null +++ b/frontend-modern/src/components/AI/AICostDashboard.tsx @@ -0,0 +1,176 @@ +import { Component, Show, createSignal, onMount, For } from 'solid-js'; +import { Card } from '@/components/shared/Card'; +import { SectionHeader } from '@/components/shared/SectionHeader'; +import { AIAPI } from '@/api/ai'; +import { formatNumber } from '@/utils/format'; +import { logger } from '@/utils/logger'; +import { notificationStore } from '@/stores/notifications'; +import type { AICostSummary } from '@/types/ai'; +import { PROVIDER_NAMES } from '@/types/ai'; + +export const AICostDashboard: Component = () => { + const [days, setDays] = createSignal(30); + const [loading, setLoading] = createSignal(false); + const [summary, setSummary] = createSignal(null); + + const loadSummary = async (rangeDays: number) => { + setLoading(true); + try { + const data = await AIAPI.getCostSummary(rangeDays); + setSummary(data); + } catch (err) { + logger.error('[AICostDashboard] Failed to load cost summary:', err); + notificationStore.error('Failed to load AI cost summary'); + setSummary(null); + } finally { + setLoading(false); + } + }; + + onMount(() => { + loadSummary(days()); + }); + + const handleRangeClick = (rangeDays: number) => { + setDays(rangeDays); + loadSummary(rangeDays); + }; + + return ( + +
+
+
+ + + +
+ +
+ + + + +
+
+
+ +
+ +
Loading usage…
+
+ + +
No usage data yet.
+
+ + + {(data) => ( + <> +
+
+
Input tokens
+
+ {formatNumber(data().totals.input_tokens)} +
+
+
+
Output tokens
+
+ {formatNumber(data().totals.output_tokens)} +
+
+
+
Total tokens
+
+ {formatNumber(data().totals.total_tokens)} +
+
+
+ +
+ + + + + + + + + + + + + {(pm) => ( + + + + + + + + )} + + +
ProviderModelInputOutputTotal
+ {PROVIDER_NAMES[pm.provider as keyof typeof PROVIDER_NAMES] || pm.provider} + + {pm.model} + + {formatNumber(pm.input_tokens)} + + {formatNumber(pm.output_tokens)} + + {formatNumber(pm.total_tokens)} +
+
+ + )} +
+
+
+ ); +}; + +export default AICostDashboard; diff --git a/frontend-modern/src/components/Settings/Settings.tsx b/frontend-modern/src/components/Settings/Settings.tsx index d8fddc1..0e6368a 100644 --- a/frontend-modern/src/components/Settings/Settings.tsx +++ b/frontend-modern/src/components/Settings/Settings.tsx @@ -28,6 +28,7 @@ import { UnifiedAgents } from './UnifiedAgents'; import APITokenManager from './APITokenManager'; import { OIDCPanel } from './OIDCPanel'; import { AISettings } from './AISettings'; +import { AICostDashboard } from '@/components/AI/AICostDashboard'; import { QuickSecuritySetup } from './QuickSecuritySetup'; import { SecurityPostureSummary } from './SecurityPostureSummary'; import { @@ -4966,7 +4967,10 @@ const Settings: Component = (props) => { {/* AI Assistant Tab */} - +
+ + +
{/* API Access */} diff --git a/frontend-modern/src/types/ai.ts b/frontend-modern/src/types/ai.ts index 68bb181..abc7011 100644 --- a/frontend-modern/src/types/ai.ts +++ b/frontend-modern/src/types/ai.ts @@ -169,3 +169,26 @@ export interface AIStreamCompleteData { output_tokens: number; tool_calls?: AIToolExecution[]; } + +// AI cost/usage summary types +export interface AICostProviderModelSummary { + provider: string; + model: string; + input_tokens: number; + output_tokens: number; + total_tokens: number; +} + +export interface AICostDailySummary { + date: string; + input_tokens: number; + output_tokens: number; + total_tokens: number; +} + +export interface AICostSummary { + days: number; + provider_models: AICostProviderModelSummary[]; + daily_totals: AICostDailySummary[]; + totals: AICostProviderModelSummary; +}