diff --git a/src/lib/api/usage.ts b/src/lib/api/usage.ts index c03f11d8e..2e3c5686e 100644 --- a/src/lib/api/usage.ts +++ b/src/lib/api/usage.ts @@ -1,33 +1,24 @@ import { invoke } from "@tauri-apps/api/core"; +import type { + UsageSummary, + DailyStats, + ProviderStats, + ModelStats, + RequestLog, + LogFilters, + ModelPricing, + ProviderLimitStatus, +} from "@/types/usage"; import type { UsageResult } from "@/types"; import type { AppId } from "./types"; -import i18n from "@/i18n"; export const usageApi = { - async query(providerId: string, appId: AppId): Promise { - try { - return await invoke("queryProviderUsage", { - providerId: providerId, - app: appId, - }); - } catch (error: unknown) { - // 提取错误消息:优先使用后端返回的错误信息 - const message = - typeof error === "string" - ? error - : error instanceof Error - ? error.message - : ""; - - // 如果没有错误消息,使用国际化的默认提示 - return { - success: false, - error: message || i18n.t("errors.usage_query_failed"), - }; - } + // Provider usage script methods + query: async (providerId: string, appId: AppId): Promise => { + return invoke("queryProviderUsage", { providerId, app: appId }); }, - async testScript( + testScript: async ( providerId: string, appId: AppId, scriptCode: string, @@ -36,30 +27,89 @@ export const usageApi = { baseUrl?: string, accessToken?: string, userId?: string, - ): Promise { - try { - return await invoke("testUsageScript", { - providerId: providerId, - app: appId, - scriptCode: scriptCode, - timeout: timeout, - apiKey: apiKey, - baseUrl: baseUrl, - accessToken: accessToken, - userId: userId, - }); - } catch (error: unknown) { - const message = - typeof error === "string" - ? error - : error instanceof Error - ? error.message - : ""; + ): Promise => { + return invoke("testUsageScript", { + providerId, + app: appId, + scriptCode, + timeout, + apiKey, + baseUrl, + accessToken, + userId, + }); + }, - return { - success: false, - error: message || i18n.t("errors.usage_query_failed"), - }; - } + // Proxy usage statistics methods + getUsageSummary: async ( + startDate?: number, + endDate?: number, + ): Promise => { + return invoke("get_usage_summary", { startDate, endDate }); + }, + + getUsageTrends: async (days: number): Promise => { + return invoke("get_usage_trends", { days }); + }, + + getProviderStats: async (): Promise => { + return invoke("get_provider_stats"); + }, + + getModelStats: async (): Promise => { + return invoke("get_model_stats"); + }, + + getRequestLogs: async ( + filters: LogFilters, + limit: number = 50, + offset: number = 0, + ): Promise => { + return invoke("get_request_logs", { + providerId: filters.providerId, + model: filters.model, + statusCode: filters.statusCode, + startDate: filters.startDate, + endDate: filters.endDate, + limit, + offset, + }); + }, + + getRequestDetail: async (requestId: string): Promise => { + return invoke("get_request_detail", { requestId }); + }, + + getModelPricing: async (): Promise => { + return invoke("get_model_pricing"); + }, + + updateModelPricing: async ( + modelId: string, + displayName: string, + inputCost: string, + outputCost: string, + cacheReadCost: string, + cacheCreationCost: string, + ): Promise => { + return invoke("update_model_pricing", { + modelId, + displayName, + inputCost, + outputCost, + cacheReadCost, + cacheCreationCost, + }); + }, + + deleteModelPricing: async (modelId: string): Promise => { + return invoke("delete_model_pricing", { modelId }); + }, + + checkProviderLimits: async ( + providerId: string, + appType: string, + ): Promise => { + return invoke("check_provider_limits", { providerId, appType }); }, }; diff --git a/src/lib/query/usage.ts b/src/lib/query/usage.ts index dd0658ff1..fb89671a9 100644 --- a/src/lib/query/usage.ts +++ b/src/lib/query/usage.ts @@ -1,22 +1,22 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { usageApi } from '@/lib/api/usage'; -import type { LogFilters } from '@/types/usage'; +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { usageApi } from "@/lib/api/usage"; +import type { LogFilters } from "@/types/usage"; // Query keys export const usageKeys = { - all: ['usage'] as const, + all: ["usage"] as const, summary: (startDate?: number, endDate?: number) => - [...usageKeys.all, 'summary', startDate, endDate] as const, - trends: (days: number) => [...usageKeys.all, 'trends', days] as const, - providerStats: () => [...usageKeys.all, 'provider-stats'] as const, - modelStats: () => [...usageKeys.all, 'model-stats'] as const, + [...usageKeys.all, "summary", startDate, endDate] as const, + trends: (days: number) => [...usageKeys.all, "trends", days] as const, + providerStats: () => [...usageKeys.all, "provider-stats"] as const, + modelStats: () => [...usageKeys.all, "model-stats"] as const, logs: (filters: LogFilters, limit: number, offset: number) => - [...usageKeys.all, 'logs', filters, limit, offset] as const, + [...usageKeys.all, "logs", filters, limit, offset] as const, detail: (requestId: string) => - [...usageKeys.all, 'detail', requestId] as const, - pricing: () => [...usageKeys.all, 'pricing'] as const, + [...usageKeys.all, "detail", requestId] as const, + pricing: () => [...usageKeys.all, "pricing"] as const, limits: (providerId: string, appType: string) => - [...usageKeys.all, 'limits', providerId, appType] as const, + [...usageKeys.all, "limits", providerId, appType] as const, }; // Hooks @@ -51,7 +51,7 @@ export function useModelStats() { export function useRequestLogs( filters: LogFilters, limit: number = 50, - offset: number = 0 + offset: number = 0, ) { return useQuery({ queryKey: usageKeys.logs(filters, limit, offset), @@ -100,10 +100,21 @@ export function useUpdateModelPricing() { params.inputCost, params.outputCost, params.cacheReadCost, - params.cacheCreationCost + params.cacheCreationCost, ), onSuccess: () => { queryClient.invalidateQueries({ queryKey: usageKeys.pricing() }); }, }); } + +export function useDeleteModelPricing() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (modelId: string) => usageApi.deleteModelPricing(modelId), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: usageKeys.pricing() }); + }, + }); +} diff --git a/src/types/usage.ts b/src/types/usage.ts index f8b4dc779..2cc6ab44e 100644 --- a/src/types/usage.ts +++ b/src/types/usage.ts @@ -10,6 +10,7 @@ export interface TokenUsage { export interface RequestLog { requestId: string; providerId: string; + providerName?: string; appType: string; model: string; inputTokens: number; @@ -41,6 +42,8 @@ export interface UsageSummary { totalCost: string; totalInputTokens: number; totalOutputTokens: number; + totalCacheCreationTokens: number; + totalCacheReadTokens: number; successRate: number; } @@ -49,6 +52,10 @@ export interface DailyStats { requestCount: number; totalCost: string; totalTokens: number; + totalInputTokens: number; + totalOutputTokens: number; + totalCacheCreationTokens: number; + totalCacheReadTokens: number; } export interface ProviderStats { @@ -87,7 +94,7 @@ export interface ProviderLimitStatus { monthlyExceeded: boolean; } -export type TimeRange = '7d' | '30d' | '90d'; +export type TimeRange = "1d" | "7d" | "30d"; export interface StatsFilters { timeRange: TimeRange;