Files
Aether/frontend/src/api/me.ts
fawney19 a2f33a6c35 perf: 拆分热力图为独立接口并添加 Redis 缓存
- 新增独立热力图 API 端点 (/api/admin/usage/heatmap, /api/users/me/usage/heatmap)
- 添加 Redis 缓存层 (5分钟 TTL),减少数据库查询
- 用户角色变更时清除热力图缓存
- 前端并行加载统计数据和热力图,添加加载/错误状态显示
- 修复 cache_decorator 缺少 JSON 解析错误处理的问题
- 更新 docker-compose 启动命令提示
2026-01-04 22:42:58 +08:00

300 lines
8.3 KiB
TypeScript

import apiClient from './client'
import type { ActivityHeatmap } from '@/types/activity'
export interface Profile {
id: string // UUID
email: string
username: string
role: string
is_active: boolean
quota_usd: number | null
used_usd: number
total_usd?: number // 累积消费总额
created_at: string
updated_at: string
last_login_at?: string
preferences?: UserPreferences
}
export interface UserPreferences {
avatar_url?: string
bio?: string
default_provider_id?: string // UUID
default_provider?: any
theme: string
language: string
timezone?: string
notifications?: {
email?: boolean
usage_alerts?: boolean
announcements?: boolean
}
}
// 提供商配置接口
export interface ProviderConfig {
provider_id: string
priority: number // 优先级(越高越优先)
weight: number // 负载均衡权重
enabled: boolean // 是否启用
}
// 使用记录接口
export interface UsageRecordDetail {
id: string
provider: string
model: string
input_tokens: number
output_tokens: number
total_tokens: number
cost: number // 官方费率
actual_cost?: number // 倍率消耗(仅管理员可见)
rate_multiplier?: number // 成本倍率(仅管理员可见)
response_time_ms?: number
is_stream: boolean
created_at: string
cache_creation_input_tokens?: number
cache_read_input_tokens?: number
status_code: number
error_message?: string
input_price_per_1m: number
output_price_per_1m: number
cache_creation_price_per_1m?: number
cache_read_price_per_1m?: number
price_per_request?: number // 按次计费价格
}
// 模型统计接口
export interface ModelSummary {
model: string
requests: number
input_tokens: number
output_tokens: number
total_tokens: number
total_cost_usd: number
actual_total_cost_usd?: number // 倍率消耗(仅管理员可见)
}
// 提供商统计接口
export interface ProviderSummary {
provider: string
requests: number
total_tokens: number
total_cost_usd: number
success_rate: number | null
avg_response_time_ms: number | null
}
// 使用统计响应接口
export interface UsageResponse {
total_requests: number
total_input_tokens: number
total_output_tokens: number
total_tokens: number
total_cost: number // 官方费率
total_actual_cost?: number // 倍率消耗(仅管理员可见)
avg_response_time: number
quota_usd: number | null
used_usd: number
summary_by_model: ModelSummary[]
summary_by_provider?: ProviderSummary[]
pagination?: {
total: number
limit: number
offset: number
has_more: boolean
}
records: UsageRecordDetail[]
activity_heatmap?: ActivityHeatmap | null
}
export interface ApiKey {
id: string // UUID
name: string
key?: string
key_display: string
is_active: boolean
last_used_at?: string
created_at: string
total_requests?: number
total_cost_usd?: number
allowed_providers?: ProviderConfig[]
force_capabilities?: Record<string, boolean> | null // 强制能力配置
}
// 不再需要 ProviderBinding 接口
export interface ChangePasswordRequest {
old_password: string
new_password: string
}
export const meApi = {
// 获取个人信息
async getProfile(): Promise<Profile> {
const response = await apiClient.get<Profile>('/api/users/me')
return response.data
},
// 更新个人信息
async updateProfile(data: {
email?: string
username?: string
}): Promise<{ message: string }> {
const response = await apiClient.put('/api/users/me', data)
return response.data
},
// 修改密码
async changePassword(data: ChangePasswordRequest): Promise<{ message: string }> {
const response = await apiClient.patch('/api/users/me/password', data)
return response.data
},
// API密钥管理
async getApiKeys(): Promise<ApiKey[]> {
const response = await apiClient.get<ApiKey[]>('/api/users/me/api-keys')
return response.data
},
async createApiKey(name: string): Promise<ApiKey> {
const response = await apiClient.post<ApiKey>('/api/users/me/api-keys', { name })
return response.data
},
async getApiKeyDetail(keyId: string, includeKey: boolean = false): Promise<ApiKey & { key?: string }> {
const response = await apiClient.get<ApiKey & { key?: string }>(
`/api/users/me/api-keys/${keyId}`,
{ params: { include_key: includeKey } }
)
return response.data
},
async getFullApiKey(keyId: string): Promise<{ key: string }> {
const response = await apiClient.get<{ key: string }>(
`/api/users/me/api-keys/${keyId}`,
{ params: { include_key: true } }
)
return response.data
},
async deleteApiKey(keyId: string): Promise<{ message: string }> {
const response = await apiClient.delete(`/api/users/me/api-keys/${keyId}`)
return response.data
},
async toggleApiKey(keyId: string): Promise<ApiKey> {
const response = await apiClient.patch<ApiKey>(`/api/users/me/api-keys/${keyId}`)
return response.data
},
// 使用统计
async getUsage(params?: {
start_date?: string
end_date?: string
limit?: number
offset?: number
}): Promise<UsageResponse> {
const response = await apiClient.get<UsageResponse>('/api/users/me/usage', { params })
return response.data
},
// 获取活跃请求状态(用于轮询更新)
async getActiveRequests(ids?: string): Promise<{
requests: Array<{
id: string
status: string
input_tokens: number
output_tokens: number
cost: number
response_time_ms: number | null
}>
}> {
const params = ids ? { ids } : {}
const response = await apiClient.get('/api/users/me/usage/active', { params })
return response.data
},
// 获取可用的提供商
async getAvailableProviders(): Promise<any[]> {
const response = await apiClient.get('/api/users/me/providers')
return response.data
},
// 获取端点状态(不包含敏感信息)
async getEndpointStatus(): Promise<any[]> {
const response = await apiClient.get('/api/users/me/endpoint-status')
return response.data
},
// 偏好设置
async getPreferences(): Promise<UserPreferences> {
const response = await apiClient.get('/api/users/me/preferences')
return response.data
},
async updatePreferences(data: Partial<UserPreferences>): Promise<{ message: string }> {
const response = await apiClient.put('/api/users/me/preferences', data)
return response.data
},
// 提供商绑定管理相关方法已移除,改为直接从可用提供商中选择
// API密钥提供商关联
async updateApiKeyProviders(keyId: string, data: {
allowed_providers?: ProviderConfig[]
}): Promise<{ message: string }> {
const response = await apiClient.put(`/api/users/me/api-keys/${keyId}/providers`, data)
return response.data
},
// API密钥能力配置
async updateApiKeyCapabilities(keyId: string, data: {
force_capabilities?: Record<string, boolean> | null
}): Promise<{ message: string; force_capabilities?: Record<string, boolean> | null }> {
const response = await apiClient.put(`/api/users/me/api-keys/${keyId}/capabilities`, data)
return response.data
},
// 模型能力配置
async getModelCapabilitySettings(): Promise<{
model_capability_settings: Record<string, Record<string, boolean>>
}> {
const response = await apiClient.get('/api/users/me/model-capabilities')
return response.data
},
async updateModelCapabilitySettings(data: {
model_capability_settings: Record<string, Record<string, boolean>> | null
}): Promise<{
message: string
model_capability_settings: Record<string, Record<string, boolean>> | null
}> {
const response = await apiClient.put('/api/users/me/model-capabilities', data)
return response.data
},
// 获取请求间隔时间线(用于散点图)
async getIntervalTimeline(params?: {
hours?: number
limit?: number
}): Promise<{
analysis_period_hours: number
total_points: number
points: Array<{ x: string; y: number; model?: string }>
models?: string[]
}> {
const response = await apiClient.get('/api/users/me/usage/interval-timeline', { params })
return response.data
},
/**
* 获取活跃度热力图数据(用户)
* 后端已缓存5分钟
*/
async getActivityHeatmap(): Promise<ActivityHeatmap> {
const response = await apiClient.get<ActivityHeatmap>('/api/users/me/usage/heatmap')
return response.data
}
}