File size: 2,367 Bytes
5f24abe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
export type LiteUsageBreakdownSource = {
  model: string
  name: string
  cost: number
  quotaCost: number
  multiplier?: number
  estimated: boolean
}

export type LiteUsageBreakdownItem = {
  model: string
  name: string
  cost?: number
  multiplier?: number
  quotaCost: number
  contributionPercent: number
  estimated: boolean
}

export function buildLiteUsageBreakdown(input: { usage: number; limit: number; sources: LiteUsageBreakdownSource[] }) {
  // Legacy usage can resolve to the same rate as a separately grouped recorded multiplier.
  const groups = new Map<string, LiteUsageBreakdownSource>()
  input.sources.forEach((item) => {
    const key = JSON.stringify([item.model, item.multiplier])
    const row = groups.get(key)
    if (!row) {
      groups.set(key, { ...item })
      return
    }
    row.cost += item.cost
    row.quotaCost += item.quotaCost
    row.estimated ||= item.estimated
  })
  const rows: LiteUsageBreakdownItem[] = Array.from(groups.values())
    .filter((item) => item.cost !== 0 || item.quotaCost !== 0)
    .sort((a, b) => b.quotaCost - a.quotaCost)
    .map((item) => ({
      ...item,
      contributionPercent: 0,
    }))

  const usagePercent = getUsagePercent(input.usage, input.limit)
  const target = Math.max(0, Math.round(usagePercent * 10))
  const totalQuota = rows.reduce((total, item) => total + Math.max(0, item.quotaCost), 0)
  const units = rows.map((item) => {
    const exact = totalQuota === 0 ? 0 : (Math.max(0, item.quotaCost) / totalQuota) * target
    const value = Math.floor(exact)
    return { item, exact, value }
  })
  const remaining = target - units.reduce((total, item) => total + item.value, 0)
  const ranked = units.toSorted((a, b) => b.exact - b.value - (a.exact - a.value))
  Array.from({ length: ranked.length === 0 ? 0 : remaining }).forEach((_, index) => {
    ranked[index % ranked.length].value += 1
  })
  units.forEach((unit) => (unit.item.contributionPercent = unit.value / 10))

  return {
    usage: input.usage,
    limit: input.limit,
    usagePercent,
    rows,
  }
}

export function getModelQuotaLimit(limit: number, multiplier?: number) {
  if (multiplier === undefined || multiplier <= 0) return
  return limit / multiplier
}

export function getUsagePercent(amount: number, limit: number) {
  if (limit === 0) return 0
  return Math.round((amount / limit) * 1000) / 10
}