mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-19 03:00:49 +08:00
fix(quota): unify Gemini CLI quota groups (Flash/Pro series)
This commit is contained in:
@@ -22,11 +22,7 @@ type Layer = {
|
|||||||
|
|
||||||
type TransitionDirection = 'forward' | 'backward';
|
type TransitionDirection = 'forward' | 'backward';
|
||||||
|
|
||||||
export function PageTransition({
|
export function PageTransition({ render, getRouteOrder, scrollContainerRef }: PageTransitionProps) {
|
||||||
render,
|
|
||||||
getRouteOrder,
|
|
||||||
scrollContainerRef,
|
|
||||||
}: PageTransitionProps) {
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const currentLayerRef = useRef<HTMLDivElement>(null);
|
const currentLayerRef = useRef<HTMLDivElement>(null);
|
||||||
const exitingLayerRef = useRef<HTMLDivElement>(null);
|
const exitingLayerRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -71,16 +67,25 @@ export function PageTransition({
|
|||||||
: 'backward';
|
: 'backward';
|
||||||
|
|
||||||
transitionDirectionRef.current = nextDirection;
|
transitionDirectionRef.current = nextDirection;
|
||||||
setLayers((prev) => {
|
|
||||||
const prevCurrent = prev[prev.length - 1];
|
let cancelled = false;
|
||||||
return [
|
queueMicrotask(() => {
|
||||||
prevCurrent
|
if (cancelled) return;
|
||||||
? { ...prevCurrent, status: 'exiting' }
|
setLayers((prev) => {
|
||||||
: { key: location.key, location, status: 'exiting' },
|
const prevCurrent = prev[prev.length - 1];
|
||||||
{ key: location.key, location, status: 'current' },
|
return [
|
||||||
];
|
prevCurrent
|
||||||
|
? { ...prevCurrent, status: 'exiting' }
|
||||||
|
: { key: location.key, location, status: 'exiting' },
|
||||||
|
{ key: location.key, location, status: 'current' },
|
||||||
|
];
|
||||||
|
});
|
||||||
|
setIsAnimating(true);
|
||||||
});
|
});
|
||||||
setIsAnimating(true);
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
}, [
|
}, [
|
||||||
isAnimating,
|
isAnimating,
|
||||||
location,
|
location,
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export interface AntigravityQuotaGroupDefinition {
|
|||||||
export interface GeminiCliQuotaGroupDefinition {
|
export interface GeminiCliQuotaGroupDefinition {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
preferredModelId?: string;
|
||||||
modelIds: string[];
|
modelIds: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
AntigravityQuotaInfo,
|
AntigravityQuotaInfo,
|
||||||
AntigravityModelsPayload,
|
AntigravityModelsPayload,
|
||||||
GeminiCliParsedBucket,
|
GeminiCliParsedBucket,
|
||||||
GeminiCliQuotaBucketState
|
GeminiCliQuotaBucketState,
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
import { ANTIGRAVITY_QUOTA_GROUPS, GEMINI_CLI_GROUP_LOOKUP } from './constants';
|
import { ANTIGRAVITY_QUOTA_GROUPS, GEMINI_CLI_GROUP_LOOKUP } from './constants';
|
||||||
import { normalizeQuotaFraction } from './parsers';
|
import { normalizeQuotaFraction } from './parsers';
|
||||||
@@ -35,7 +35,19 @@ export function buildGeminiCliQuotaBuckets(
|
|||||||
): GeminiCliQuotaBucketState[] {
|
): GeminiCliQuotaBucketState[] {
|
||||||
if (buckets.length === 0) return [];
|
if (buckets.length === 0) return [];
|
||||||
|
|
||||||
const grouped = new Map<string, GeminiCliQuotaBucketState & { modelIds: string[] }>();
|
type GeminiCliQuotaBucketGroup = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
tokenType: string | null;
|
||||||
|
modelIds: string[];
|
||||||
|
preferredModelId?: string;
|
||||||
|
preferredBucket?: GeminiCliParsedBucket;
|
||||||
|
fallbackRemainingFraction: number | null;
|
||||||
|
fallbackRemainingAmount: number | null;
|
||||||
|
fallbackResetTime: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const grouped = new Map<string, GeminiCliQuotaBucketGroup>();
|
||||||
|
|
||||||
buckets.forEach((bucket) => {
|
buckets.forEach((bucket) => {
|
||||||
if (isIgnoredGeminiCliModel(bucket.modelId)) return;
|
if (isIgnoredGeminiCliModel(bucket.modelId)) return;
|
||||||
@@ -47,37 +59,55 @@ export function buildGeminiCliQuotaBuckets(
|
|||||||
const existing = grouped.get(mapKey);
|
const existing = grouped.get(mapKey);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
|
const preferredModelId = group?.preferredModelId;
|
||||||
|
const preferredBucket =
|
||||||
|
preferredModelId && bucket.modelId === preferredModelId ? bucket : undefined;
|
||||||
grouped.set(mapKey, {
|
grouped.set(mapKey, {
|
||||||
id: `${groupId}${tokenKey ? `-${tokenKey}` : ''}`,
|
id: `${groupId}${tokenKey ? `-${tokenKey}` : ''}`,
|
||||||
label,
|
label,
|
||||||
remainingFraction: bucket.remainingFraction,
|
|
||||||
remainingAmount: bucket.remainingAmount,
|
|
||||||
resetTime: bucket.resetTime,
|
|
||||||
tokenType: bucket.tokenType,
|
tokenType: bucket.tokenType,
|
||||||
modelIds: [bucket.modelId]
|
modelIds: [bucket.modelId],
|
||||||
|
preferredModelId,
|
||||||
|
preferredBucket,
|
||||||
|
fallbackRemainingFraction: bucket.remainingFraction,
|
||||||
|
fallbackRemainingAmount: bucket.remainingAmount,
|
||||||
|
fallbackResetTime: bucket.resetTime,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
existing.remainingFraction = minNullableNumber(
|
existing.fallbackRemainingFraction = minNullableNumber(
|
||||||
existing.remainingFraction,
|
existing.fallbackRemainingFraction,
|
||||||
bucket.remainingFraction
|
bucket.remainingFraction
|
||||||
);
|
);
|
||||||
existing.remainingAmount = minNullableNumber(existing.remainingAmount, bucket.remainingAmount);
|
existing.fallbackRemainingAmount = minNullableNumber(
|
||||||
existing.resetTime = pickEarlierResetTime(existing.resetTime, bucket.resetTime);
|
existing.fallbackRemainingAmount,
|
||||||
|
bucket.remainingAmount
|
||||||
|
);
|
||||||
|
existing.fallbackResetTime = pickEarlierResetTime(existing.fallbackResetTime, bucket.resetTime);
|
||||||
existing.modelIds.push(bucket.modelId);
|
existing.modelIds.push(bucket.modelId);
|
||||||
|
|
||||||
|
if (existing.preferredModelId && bucket.modelId === existing.preferredModelId) {
|
||||||
|
existing.preferredBucket = bucket;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Array.from(grouped.values()).map((bucket) => {
|
return Array.from(grouped.values()).map((bucket) => {
|
||||||
const uniqueModelIds = Array.from(new Set(bucket.modelIds));
|
const uniqueModelIds = Array.from(new Set(bucket.modelIds));
|
||||||
|
const preferred = bucket.preferredBucket;
|
||||||
|
const remainingFraction = preferred
|
||||||
|
? preferred.remainingFraction
|
||||||
|
: bucket.fallbackRemainingFraction;
|
||||||
|
const remainingAmount = preferred ? preferred.remainingAmount : bucket.fallbackRemainingAmount;
|
||||||
|
const resetTime = preferred ? preferred.resetTime : bucket.fallbackResetTime;
|
||||||
return {
|
return {
|
||||||
id: bucket.id,
|
id: bucket.id,
|
||||||
label: bucket.label,
|
label: bucket.label,
|
||||||
remainingFraction: bucket.remainingFraction,
|
remainingFraction,
|
||||||
remainingAmount: bucket.remainingAmount,
|
remainingAmount,
|
||||||
resetTime: bucket.resetTime,
|
resetTime,
|
||||||
tokenType: bucket.tokenType,
|
tokenType: bucket.tokenType,
|
||||||
modelIds: uniqueModelIds
|
modelIds: uniqueModelIds,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -101,7 +131,7 @@ export function getAntigravityQuotaInfo(entry?: AntigravityQuotaInfo): {
|
|||||||
return {
|
return {
|
||||||
remainingFraction,
|
remainingFraction,
|
||||||
resetTime,
|
resetTime,
|
||||||
displayName
|
displayName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +180,7 @@ export function buildAntigravityQuotaGroups(
|
|||||||
id,
|
id,
|
||||||
remainingFraction,
|
remainingFraction,
|
||||||
resetTime: info.resetTime,
|
resetTime: info.resetTime,
|
||||||
displayName: info.displayName
|
displayName: info.displayName,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((entry): entry is NonNullable<typeof entry> => entry !== null);
|
.filter((entry): entry is NonNullable<typeof entry> => entry !== null);
|
||||||
@@ -168,7 +198,7 @@ export function buildAntigravityQuotaGroups(
|
|||||||
label,
|
label,
|
||||||
models: quotaEntries.map((entry) => entry.id),
|
models: quotaEntries.map((entry) => entry.id),
|
||||||
remainingFraction,
|
remainingFraction,
|
||||||
resetTime
|
resetTime,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,64 +5,64 @@
|
|||||||
import type {
|
import type {
|
||||||
AntigravityQuotaGroupDefinition,
|
AntigravityQuotaGroupDefinition,
|
||||||
GeminiCliQuotaGroupDefinition,
|
GeminiCliQuotaGroupDefinition,
|
||||||
TypeColorSet
|
TypeColorSet,
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
|
|
||||||
// Theme colors for type badges
|
// Theme colors for type badges
|
||||||
export const TYPE_COLORS: Record<string, TypeColorSet> = {
|
export const TYPE_COLORS: Record<string, TypeColorSet> = {
|
||||||
qwen: {
|
qwen: {
|
||||||
light: { bg: '#e8f5e9', text: '#2e7d32' },
|
light: { bg: '#e8f5e9', text: '#2e7d32' },
|
||||||
dark: { bg: '#1b5e20', text: '#81c784' }
|
dark: { bg: '#1b5e20', text: '#81c784' },
|
||||||
},
|
},
|
||||||
gemini: {
|
gemini: {
|
||||||
light: { bg: '#e3f2fd', text: '#1565c0' },
|
light: { bg: '#e3f2fd', text: '#1565c0' },
|
||||||
dark: { bg: '#0d47a1', text: '#64b5f6' }
|
dark: { bg: '#0d47a1', text: '#64b5f6' },
|
||||||
},
|
},
|
||||||
'gemini-cli': {
|
'gemini-cli': {
|
||||||
light: { bg: '#e7efff', text: '#1e4fa3' },
|
light: { bg: '#e7efff', text: '#1e4fa3' },
|
||||||
dark: { bg: '#1c3f73', text: '#a8c7ff' }
|
dark: { bg: '#1c3f73', text: '#a8c7ff' },
|
||||||
},
|
},
|
||||||
aistudio: {
|
aistudio: {
|
||||||
light: { bg: '#f0f2f5', text: '#2f343c' },
|
light: { bg: '#f0f2f5', text: '#2f343c' },
|
||||||
dark: { bg: '#373c42', text: '#cfd3db' }
|
dark: { bg: '#373c42', text: '#cfd3db' },
|
||||||
},
|
},
|
||||||
claude: {
|
claude: {
|
||||||
light: { bg: '#fce4ec', text: '#c2185b' },
|
light: { bg: '#fce4ec', text: '#c2185b' },
|
||||||
dark: { bg: '#880e4f', text: '#f48fb1' }
|
dark: { bg: '#880e4f', text: '#f48fb1' },
|
||||||
},
|
},
|
||||||
codex: {
|
codex: {
|
||||||
light: { bg: '#fff3e0', text: '#ef6c00' },
|
light: { bg: '#fff3e0', text: '#ef6c00' },
|
||||||
dark: { bg: '#e65100', text: '#ffb74d' }
|
dark: { bg: '#e65100', text: '#ffb74d' },
|
||||||
},
|
},
|
||||||
antigravity: {
|
antigravity: {
|
||||||
light: { bg: '#e0f7fa', text: '#006064' },
|
light: { bg: '#e0f7fa', text: '#006064' },
|
||||||
dark: { bg: '#004d40', text: '#80deea' }
|
dark: { bg: '#004d40', text: '#80deea' },
|
||||||
},
|
},
|
||||||
iflow: {
|
iflow: {
|
||||||
light: { bg: '#f3e5f5', text: '#7b1fa2' },
|
light: { bg: '#f3e5f5', text: '#7b1fa2' },
|
||||||
dark: { bg: '#4a148c', text: '#ce93d8' }
|
dark: { bg: '#4a148c', text: '#ce93d8' },
|
||||||
},
|
},
|
||||||
empty: {
|
empty: {
|
||||||
light: { bg: '#f5f5f5', text: '#616161' },
|
light: { bg: '#f5f5f5', text: '#616161' },
|
||||||
dark: { bg: '#424242', text: '#bdbdbd' }
|
dark: { bg: '#424242', text: '#bdbdbd' },
|
||||||
},
|
},
|
||||||
unknown: {
|
unknown: {
|
||||||
light: { bg: '#f0f0f0', text: '#666666', border: '1px dashed #999999' },
|
light: { bg: '#f0f0f0', text: '#666666', border: '1px dashed #999999' },
|
||||||
dark: { bg: '#3a3a3a', text: '#aaaaaa', border: '1px dashed #666666' }
|
dark: { bg: '#3a3a3a', text: '#aaaaaa', border: '1px dashed #666666' },
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Antigravity API configuration
|
// Antigravity API configuration
|
||||||
export const ANTIGRAVITY_QUOTA_URLS = [
|
export const ANTIGRAVITY_QUOTA_URLS = [
|
||||||
'https://daily-cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',
|
'https://daily-cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',
|
||||||
'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels',
|
'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels',
|
||||||
'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels'
|
'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ANTIGRAVITY_REQUEST_HEADERS = {
|
export const ANTIGRAVITY_REQUEST_HEADERS = {
|
||||||
Authorization: 'Bearer $TOKEN$',
|
Authorization: 'Bearer $TOKEN$',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'User-Agent': 'antigravity/1.11.5 windows/amd64'
|
'User-Agent': 'antigravity/1.11.5 windows/amd64',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ANTIGRAVITY_QUOTA_GROUPS: AntigravityQuotaGroupDefinition[] = [
|
export const ANTIGRAVITY_QUOTA_GROUPS: AntigravityQuotaGroupDefinition[] = [
|
||||||
@@ -73,40 +73,40 @@ export const ANTIGRAVITY_QUOTA_GROUPS: AntigravityQuotaGroupDefinition[] = [
|
|||||||
'claude-sonnet-4-5-thinking',
|
'claude-sonnet-4-5-thinking',
|
||||||
'claude-opus-4-5-thinking',
|
'claude-opus-4-5-thinking',
|
||||||
'claude-sonnet-4-5',
|
'claude-sonnet-4-5',
|
||||||
'gpt-oss-120b-medium'
|
'gpt-oss-120b-medium',
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro',
|
id: 'gemini-3-pro',
|
||||||
label: 'Gemini 3 Pro',
|
label: 'Gemini 3 Pro',
|
||||||
identifiers: ['gemini-3-pro-high', 'gemini-3-pro-low']
|
identifiers: ['gemini-3-pro-high', 'gemini-3-pro-low'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-2-5-flash',
|
id: 'gemini-2-5-flash',
|
||||||
label: 'Gemini 2.5 Flash',
|
label: 'Gemini 2.5 Flash',
|
||||||
identifiers: ['gemini-2.5-flash', 'gemini-2.5-flash-thinking']
|
identifiers: ['gemini-2.5-flash', 'gemini-2.5-flash-thinking'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-2-5-flash-lite',
|
id: 'gemini-2-5-flash-lite',
|
||||||
label: 'Gemini 2.5 Flash Lite',
|
label: 'Gemini 2.5 Flash Lite',
|
||||||
identifiers: ['gemini-2.5-flash-lite']
|
identifiers: ['gemini-2.5-flash-lite'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-2-5-cu',
|
id: 'gemini-2-5-cu',
|
||||||
label: 'Gemini 2.5 CU',
|
label: 'Gemini 2.5 CU',
|
||||||
identifiers: ['rev19-uic3-1p']
|
identifiers: ['rev19-uic3-1p'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-flash',
|
id: 'gemini-3-flash',
|
||||||
label: 'Gemini 3 Flash',
|
label: 'Gemini 3 Flash',
|
||||||
identifiers: ['gemini-3-flash']
|
identifiers: ['gemini-3-flash'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-image',
|
id: 'gemini-image',
|
||||||
label: 'gemini-3-pro-image',
|
label: 'gemini-3-pro-image',
|
||||||
identifiers: ['gemini-3-pro-image'],
|
identifiers: ['gemini-3-pro-image'],
|
||||||
labelFromModel: true
|
labelFromModel: true,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Gemini CLI API configuration
|
// Gemini CLI API configuration
|
||||||
@@ -115,30 +115,22 @@ export const GEMINI_CLI_QUOTA_URL =
|
|||||||
|
|
||||||
export const GEMINI_CLI_REQUEST_HEADERS = {
|
export const GEMINI_CLI_REQUEST_HEADERS = {
|
||||||
Authorization: 'Bearer $TOKEN$',
|
Authorization: 'Bearer $TOKEN$',
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GEMINI_CLI_QUOTA_GROUPS: GeminiCliQuotaGroupDefinition[] = [
|
export const GEMINI_CLI_QUOTA_GROUPS: GeminiCliQuotaGroupDefinition[] = [
|
||||||
{
|
{
|
||||||
id: 'gemini-2-5-flash-series',
|
id: 'gemini-flash-series',
|
||||||
label: 'Gemini 2.5 Flash Series',
|
label: 'Gemini Flash Series',
|
||||||
modelIds: ['gemini-2.5-flash', 'gemini-2.5-flash-lite']
|
preferredModelId: 'gemini-3-flash-preview',
|
||||||
|
modelIds: ['gemini-3-flash-preview', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-2-5-pro',
|
id: 'gemini-pro-series',
|
||||||
label: 'Gemini 2.5 Pro',
|
label: 'Gemini Pro Series',
|
||||||
modelIds: ['gemini-2.5-pro']
|
preferredModelId: 'gemini-3-pro-preview',
|
||||||
|
modelIds: ['gemini-3-pro-preview', 'gemini-2.5-pro'],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'gemini-3-pro-preview',
|
|
||||||
label: 'Gemini 3 Pro Preview',
|
|
||||||
modelIds: ['gemini-3-pro-preview']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'gemini-3-flash-preview',
|
|
||||||
label: 'Gemini 3 Flash Preview',
|
|
||||||
modelIds: ['gemini-3-flash-preview']
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const GEMINI_CLI_GROUP_LOOKUP = new Map(
|
export const GEMINI_CLI_GROUP_LOOKUP = new Map(
|
||||||
@@ -155,5 +147,5 @@ export const CODEX_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage';
|
|||||||
export const CODEX_REQUEST_HEADERS = {
|
export const CODEX_REQUEST_HEADERS = {
|
||||||
Authorization: 'Bearer $TOKEN$',
|
Authorization: 'Bearer $TOKEN$',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'User-Agent': 'codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal'
|
'User-Agent': 'codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal',
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user