mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-11 11:49:50 +08:00
Unify quota snapshots and oauth refresh handling
This commit is contained in:
@@ -112,12 +112,14 @@ import {
|
||||
} from '@/components/ui'
|
||||
import Button from '@/components/ui/button.vue'
|
||||
import { testModel } from '@/api/endpoints/providers'
|
||||
import type { UpstreamMetadata, QuotaStatusSnapshot, QuotaWindowSnapshot } from '@/api/endpoints/types'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { parseApiError } from '@/utils/errorParser'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
metadata: Record<string, unknown> | null
|
||||
metadata: UpstreamMetadata | null
|
||||
quotaSnapshot?: QuotaStatusSnapshot | null
|
||||
keyName: string
|
||||
providerId?: string
|
||||
keyId?: string
|
||||
@@ -138,14 +140,85 @@ interface QuotaItem {
|
||||
const { error: showError, success: showSuccess } = useToast()
|
||||
const testingModel = ref<string | null>(null)
|
||||
|
||||
function getQuotaSnapshotUpdatedAt(quota: QuotaStatusSnapshot | null | undefined): number | undefined {
|
||||
const updatedAt = quota?.updated_at ?? quota?.observed_at
|
||||
return typeof updatedAt === 'number' ? updatedAt : undefined
|
||||
}
|
||||
|
||||
function getQuotaWindowLiveResetSeconds(
|
||||
quota: QuotaStatusSnapshot | null | undefined,
|
||||
window: QuotaWindowSnapshot | null | undefined,
|
||||
): number | null {
|
||||
if (!window) return null
|
||||
|
||||
const now = Math.floor(Date.now() / 1000)
|
||||
if (typeof window.reset_at === 'number') {
|
||||
return Math.max(window.reset_at - now, 0)
|
||||
}
|
||||
|
||||
if (typeof window.reset_seconds === 'number') {
|
||||
const updatedAt = getQuotaSnapshotUpdatedAt(quota)
|
||||
const elapsed = typeof updatedAt === 'number' ? Math.max(now - updatedAt, 0) : 0
|
||||
return Math.max(window.reset_seconds - elapsed, 0)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function buildItemsFromQuotaSnapshot(quota: QuotaStatusSnapshot | null | undefined): QuotaItem[] {
|
||||
if (!quota) return []
|
||||
|
||||
const providerType = String(quota.provider_type || '').trim().toLowerCase()
|
||||
if (providerType && providerType !== 'antigravity') return []
|
||||
|
||||
const windows = Array.isArray(quota.windows)
|
||||
? quota.windows.filter(window => String(window?.scope || '').trim().toLowerCase() === 'model')
|
||||
: []
|
||||
if (windows.length === 0) return []
|
||||
|
||||
const items = windows
|
||||
.map((window) => {
|
||||
const model = String(window.model || window.label || window.code || '').trim()
|
||||
if (!model) return null
|
||||
|
||||
const usedPercent =
|
||||
typeof window.used_ratio === 'number'
|
||||
? Math.max(Math.min(window.used_ratio * 100, 100), 0)
|
||||
: typeof window.remaining_ratio === 'number'
|
||||
? Math.max(Math.min((1 - window.remaining_ratio) * 100, 100), 0)
|
||||
: null
|
||||
if (usedPercent == null) return null
|
||||
|
||||
const remainingPercent =
|
||||
typeof window.remaining_ratio === 'number'
|
||||
? Math.max(Math.min(window.remaining_ratio * 100, 100), 0)
|
||||
: Math.max(100 - usedPercent, 0)
|
||||
|
||||
return {
|
||||
model,
|
||||
label: String(window.label || window.model || model),
|
||||
usedPercent,
|
||||
remainingPercent,
|
||||
resetSeconds: getQuotaWindowLiveResetSeconds(quota, window),
|
||||
} satisfies QuotaItem
|
||||
})
|
||||
.filter((item): item is QuotaItem => item !== null)
|
||||
|
||||
items.sort((a, b) => (b.usedPercent - a.usedPercent) || a.model.localeCompare(b.model))
|
||||
return items
|
||||
}
|
||||
|
||||
const items = computed<QuotaItem[]>(() => {
|
||||
const snapshotItems = buildItemsFromQuotaSnapshot(props.quotaSnapshot)
|
||||
if (snapshotItems.length > 0) return snapshotItems
|
||||
|
||||
const antigravity = props.metadata?.antigravity
|
||||
if (!antigravity || typeof antigravity !== 'object') return []
|
||||
const quotaByModel = (antigravity as Record<string, unknown>).quota_by_model
|
||||
const quotaByModel = antigravity.quota_by_model
|
||||
if (!quotaByModel || typeof quotaByModel !== 'object') return []
|
||||
|
||||
const result: QuotaItem[] = []
|
||||
for (const [model, rawInfo] of Object.entries(quotaByModel as Record<string, unknown>)) {
|
||||
for (const [model, rawInfo] of Object.entries(quotaByModel)) {
|
||||
if (!model) continue
|
||||
const info = (rawInfo || {}) as Record<string, unknown>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user