feat(webui): add hot-reload account management with OAuth support

This commit is contained in:
Wha1eChai
2026-01-08 23:49:12 +08:00
parent dc9bea1100
commit c9c5e7d486
10 changed files with 194 additions and 153 deletions

View File

@@ -423,32 +423,51 @@ app.get('/account-limits', async (req, res) => {
return res.send(lines.join('\n'));
}
// Get account metadata from AccountManager
const accountStatus = accountManager.getStatus();
const accountMetadataMap = new Map(
accountStatus.accounts.map(a => [a.email, a])
);
// Default: JSON format
res.json({
timestamp: new Date().toLocaleString(),
totalAccounts: allAccounts.length,
models: sortedModels,
modelConfig: config.modelMapping || {},
accounts: accountLimits.map(acc => ({
email: acc.email,
status: acc.status,
error: acc.error || null,
limits: Object.fromEntries(
sortedModels.map(modelId => {
const quota = acc.models?.[modelId];
if (!quota) {
return [modelId, null];
}
return [modelId, {
remaining: quota.remainingFraction !== null
? `${Math.round(quota.remainingFraction * 100)}%`
: 'N/A',
remainingFraction: quota.remainingFraction,
resetTime: quota.resetTime || null
}];
})
)
}))
accounts: accountLimits.map(acc => {
// Merge quota data with account metadata
const metadata = accountMetadataMap.get(acc.email) || {};
return {
email: acc.email,
status: acc.status,
error: acc.error || null,
// Include metadata from AccountManager (WebUI needs these)
source: metadata.source || 'unknown',
enabled: metadata.enabled !== false,
projectId: metadata.projectId || null,
isInvalid: metadata.isInvalid || false,
invalidReason: metadata.invalidReason || null,
lastUsed: metadata.lastUsed || null,
modelRateLimits: metadata.modelRateLimits || {},
// Quota limits
limits: Object.fromEntries(
sortedModels.map(modelId => {
const quota = acc.models?.[modelId];
if (!quota) {
return [modelId, null];
}
return [modelId, {
remaining: quota.remainingFraction !== null
? `${Math.round(quota.remainingFraction * 100)}%`
: 'N/A',
remainingFraction: quota.remainingFraction,
resetTime: quota.resetTime || null
}];
})
)
};
})
});
} catch (error) {
res.status(500).json({