-
-
Notifications
You must be signed in to change notification settings - Fork 330
fix total quota #1126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix total quota #1126
Changes from all commits
10c8c70
78d3bb4
ff7d5b6
024fcce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -327,6 +327,7 @@ export async function getProviders(): Promise<ProviderDisplay[]> { | |
| limitWeeklyUsd: provider.limitWeeklyUsd, | ||
| limitMonthlyUsd: provider.limitMonthlyUsd, | ||
| limitTotalUsd: provider.limitTotalUsd, | ||
| totalCostResetAt: provider.totalCostResetAt, | ||
| limitConcurrentSessions: provider.limitConcurrentSessions, | ||
| maxRetryAttempts: provider.maxRetryAttempts, | ||
| circuitBreakerFailureThreshold: provider.circuitBreakerFailureThreshold, | ||
|
|
@@ -1259,6 +1260,8 @@ export async function resetProviderTotalUsage(providerId: number): Promise<Actio | |
| return { ok: false, error: "供应商不存在" }; | ||
| } | ||
|
|
||
| await publishProviderCacheInvalidation(); | ||
|
|
||
| return { ok: true }; | ||
| } catch (error) { | ||
| logger.error("重置供应商总用量失败:", error); | ||
|
|
@@ -2690,6 +2693,7 @@ export async function getProviderLimitUsage(providerId: number): Promise< | |
| costDaily: { current: number; limit: number | null; resetAt?: Date }; | ||
| costWeekly: { current: number; limit: number | null; resetAt: Date }; | ||
| costMonthly: { current: number; limit: number | null; resetAt: Date }; | ||
| limitTotalUsd: { current: number; limit: number | null; resetAt?: Date }; | ||
| concurrentSessions: { current: number; limit: number }; | ||
| }> | ||
| > { | ||
|
|
@@ -2713,7 +2717,9 @@ export async function getProviderLimitUsage(providerId: number): Promise< | |
| getTimeRangeForPeriodWithMode, | ||
| } = await import("@/lib/rate-limit/time-utils"); | ||
| const { RateLimitService } = await import("@/lib/rate-limit"); | ||
| const { sumProviderCostInTimeRange } = await import("@/repository/statistics"); | ||
| const { sumProviderCostInTimeRange, sumProviderTotalCost } = await import( | ||
| "@/repository/statistics" | ||
| ); | ||
| const limit5hResetMode = provider.limit5hResetMode ?? "rolling"; | ||
|
|
||
| // 计算各周期的时间范围 | ||
|
|
@@ -2732,15 +2738,23 @@ export async function getProviderLimitUsage(providerId: number): Promise< | |
| ]); | ||
|
|
||
| // 获取金额消费(直接查询数据库,确保配额显示与 DB 一致) | ||
| const [cost5h, costDaily, costWeekly, costMonthly, concurrentSessions] = await Promise.all([ | ||
| limit5hResetMode === "fixed" | ||
| ? RateLimitService.getCurrentCost(providerId, "provider", "5h", undefined, limit5hResetMode) | ||
| : sumProviderCostInTimeRange(providerId, range5h.startTime, range5h.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeDaily.startTime, rangeDaily.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeWeekly.startTime, rangeWeekly.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeMonthly.startTime, rangeMonthly.endTime), | ||
| SessionTracker.getProviderSessionCount(providerId), | ||
| ]); | ||
| const [cost5h, costDaily, costWeekly, costMonthly, totalCost, concurrentSessions] = | ||
| await Promise.all([ | ||
| limit5hResetMode === "fixed" | ||
| ? RateLimitService.getCurrentCost( | ||
| providerId, | ||
| "provider", | ||
| "5h", | ||
| undefined, | ||
| limit5hResetMode | ||
| ) | ||
| : sumProviderCostInTimeRange(providerId, range5h.startTime, range5h.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeDaily.startTime, rangeDaily.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeWeekly.startTime, rangeWeekly.endTime), | ||
| sumProviderCostInTimeRange(providerId, rangeMonthly.startTime, rangeMonthly.endTime), | ||
| sumProviderTotalCost(providerId, provider.totalCostResetAt), | ||
| SessionTracker.getProviderSessionCount(providerId), | ||
| ]); | ||
|
|
||
| // 获取重置时间信息 | ||
| const resetDaily = await getResetInfoWithMode( | ||
|
|
@@ -2779,6 +2793,11 @@ export async function getProviderLimitUsage(providerId: number): Promise< | |
| limit: provider.limitMonthlyUsd, | ||
| resetAt: resetMonthly.resetAt!, | ||
| }, | ||
| limitTotalUsd: { | ||
| current: totalCost, | ||
| limit: provider.limitTotalUsd ?? null, | ||
| resetAt: provider.totalCostResetAt ?? undefined, | ||
| }, | ||
| concurrentSessions: { | ||
| current: concurrentSessions, | ||
| limit: provider.limitConcurrentSessions || 0, | ||
|
|
@@ -2800,6 +2819,7 @@ export type ProviderLimitUsageData = { | |
| costDaily: { current: number; limit: number | null; resetAt?: Date }; | ||
| costWeekly: { current: number; limit: number | null; resetAt: Date }; | ||
| costMonthly: { current: number; limit: number | null; resetAt: Date }; | ||
| limitTotalUsd: { current: number; limit: number | null; resetAt?: Date }; | ||
| concurrentSessions: { current: number; limit: number }; | ||
| }; | ||
|
|
||
|
|
@@ -2820,6 +2840,8 @@ export async function getProviderLimitUsageBatch( | |
| limitDailyUsd?: number | null; | ||
| limitWeeklyUsd?: number | null; | ||
| limitMonthlyUsd?: number | null; | ||
| limitTotalUsd?: number | null; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| totalCostResetAt?: Date | null; | ||
| limitConcurrentSessions?: number | null; | ||
| }> | ||
| ): Promise<Map<number, ProviderLimitUsageData>> { | ||
|
|
@@ -2845,7 +2867,9 @@ export async function getProviderLimitUsageBatch( | |
| getTimeRangeForPeriodWithMode, | ||
| } = await import("@/lib/rate-limit/time-utils"); | ||
| const { RateLimitService } = await import("@/lib/rate-limit"); | ||
| const { sumProviderCostInTimeRange } = await import("@/repository/statistics"); | ||
| const { sumProviderCostInTimeRange, sumProviderTotalCost } = await import( | ||
| "@/repository/statistics" | ||
| ); | ||
|
|
||
| const providerIds = providers.map((p) => p.id); | ||
|
|
||
|
|
@@ -2871,7 +2895,7 @@ export async function getProviderLimitUsageBatch( | |
| ); | ||
|
|
||
| // 并行查询该供应商的各周期消费(直接查询数据库) | ||
| const [cost5h, resetAt5h, costDaily, costWeekly, costMonthly] = await Promise.all([ | ||
| const [cost5h, resetAt5h, costDaily, costWeekly, costMonthly, totalCost] = await Promise.all([ | ||
| limit5hResetMode === "fixed" | ||
| ? RateLimitService.getCurrentCost( | ||
| provider.id, | ||
|
|
@@ -2887,6 +2911,7 @@ export async function getProviderLimitUsageBatch( | |
| sumProviderCostInTimeRange(provider.id, rangeDaily.startTime, rangeDaily.endTime), | ||
| sumProviderCostInTimeRange(provider.id, rangeWeekly.startTime, rangeWeekly.endTime), | ||
| sumProviderCostInTimeRange(provider.id, rangeMonthly.startTime, rangeMonthly.endTime), | ||
| sumProviderTotalCost(provider.id, provider.totalCostResetAt ?? null), | ||
| ]); | ||
|
Comment on lines
2911
to
2915
|
||
|
|
||
| const sessionCount = sessionCountMap.get(provider.id) || 0; | ||
|
|
@@ -2926,6 +2951,11 @@ export async function getProviderLimitUsageBatch( | |
| limit: provider.limitMonthlyUsd ?? null, | ||
| resetAt: resetMonthly.resetAt!, | ||
| }, | ||
| limitTotalUsd: { | ||
| current: totalCost, | ||
| limit: provider.limitTotalUsd ?? null, | ||
| resetAt: provider.totalCostResetAt ?? undefined, | ||
| }, | ||
| concurrentSessions: { | ||
| current: sessionCount, | ||
| limit: provider.limitConcurrentSessions || 0, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -32,6 +32,7 @@ interface KeyQuota { | |||||||||||||||||||||||||
| costDaily: { current: number; limit: number | null; resetAt?: Date }; | ||||||||||||||||||||||||||
| costWeekly: { current: number; limit: number | null }; | ||||||||||||||||||||||||||
| costMonthly: { current: number; limit: number | null }; | ||||||||||||||||||||||||||
| costTotal: { current: number; limit: number | null; resetAt?: Date }; | ||||||||||||||||||||||||||
| concurrentSessions: { current: number; limit: number }; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -79,6 +80,9 @@ export function EditKeyQuotaDialog({ | |||||||||||||||||||||||||
| const [limitMonthly, setLimitMonthly] = useState<string>( | ||||||||||||||||||||||||||
| currentQuota?.costMonthly.limit?.toString() ?? "" | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| const [limitTotal, setLimitTotal] = useState<string>( | ||||||||||||||||||||||||||
| currentQuota?.costTotal.limit?.toString() ?? "" | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
Comment on lines
+83
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 对 本文件 Line 35 把 Also applies to: 359-367 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| const [limitConcurrent, setLimitConcurrent] = useState<string>( | ||||||||||||||||||||||||||
| currentQuota?.concurrentSessions.limit?.toString() ?? "0" | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
@@ -98,6 +102,7 @@ export function EditKeyQuotaDialog({ | |||||||||||||||||||||||||
| dailyResetTime: resetTime, | ||||||||||||||||||||||||||
| limitWeeklyUsd: limitWeekly ? parseFloat(limitWeekly) : null, | ||||||||||||||||||||||||||
| limitMonthlyUsd: limitMonthly ? parseFloat(limitMonthly) : null, | ||||||||||||||||||||||||||
| limitTotalUsd: limitTotal ? parseFloat(limitTotal) : null, | ||||||||||||||||||||||||||
| limitConcurrentSessions: limitConcurrent ? parseInt(limitConcurrent, 10) : 0, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -127,6 +132,7 @@ export function EditKeyQuotaDialog({ | |||||||||||||||||||||||||
| dailyResetTime: resetTime, | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Medium] [LOGIC-BUG] "Clear All" button visibility condition missing Why this is a problem: This new line clears Suggested fix - Update the button visibility condition in {(currentQuota?.cost5h.limit ||
currentQuota?.costDaily.limit ||
currentQuota?.costWeekly.limit ||
currentQuota?.costMonthly.limit ||
currentQuota?.costTotal?.limit ||
(currentQuota?.concurrentSessions.limit ?? 0) > 0) && ( |
||||||||||||||||||||||||||
| limitWeeklyUsd: null, | ||||||||||||||||||||||||||
| limitMonthlyUsd: null, | ||||||||||||||||||||||||||
| limitTotalUsd: null, | ||||||||||||||||||||||||||
| limitConcurrentSessions: 0, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -335,6 +341,32 @@ export function EditKeyQuotaDialog({ | |||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| {/* 总限额 */} | ||||||||||||||||||||||||||
| <div className="grid gap-1.5"> | ||||||||||||||||||||||||||
| <Label htmlFor="limitTotal" className="text-xs"> | ||||||||||||||||||||||||||
| {t("limitTotalUsd.label")} | ||||||||||||||||||||||||||
| </Label> | ||||||||||||||||||||||||||
| <Input | ||||||||||||||||||||||||||
| id="limitTotal" | ||||||||||||||||||||||||||
| type="number" | ||||||||||||||||||||||||||
| step="0.01" | ||||||||||||||||||||||||||
| min="0" | ||||||||||||||||||||||||||
| placeholder={t("limitTotalUsd.placeholder")} | ||||||||||||||||||||||||||
| value={limitTotal} | ||||||||||||||||||||||||||
| onChange={(e) => setLimitTotal(e.target.value)} | ||||||||||||||||||||||||||
| className="h-9" | ||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
| {currentQuota?.costTotal.limit && ( | ||||||||||||||||||||||||||
| <p className="text-xs text-muted-foreground"> | ||||||||||||||||||||||||||
| {t("limitTotalUsd.current", { | ||||||||||||||||||||||||||
| currency: currencySymbol, | ||||||||||||||||||||||||||
| current: Number(currentQuota.costTotal.current).toFixed(4), | ||||||||||||||||||||||||||
| limit: Number(currentQuota.costTotal.limit).toFixed(2), | ||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||
|
Comment on lines
+355
to
+365
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/app/[locale]/dashboard/quotas/keys/_components/edit-key-quota-dialog.tsx
Line: 355-365
Comment:
**Current-usage hint hidden when limit is 0**
`currentQuota?.costTotal.limit && (...)` is falsy when `limit === 0`, so the usage hint is silently suppressed for a zero limit. Other quota fields use `limit !== null` as the guard, which is safer.
```suggestion
{currentQuota?.costTotal.limit !== null && (
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||
|
Comment on lines
+359
to
+367
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
L359 建议修改- {currentQuota?.costTotal.limit && (
+ {currentQuota?.costTotal?.limit != null && (🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| {/* 并发限额 */} | ||||||||||||||||||||||||||
| <div className="grid gap-1.5"> | ||||||||||||||||||||||||||
| <Label htmlFor="limitConcurrent" className="text-xs"> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.