${modelName}
@@ -1905,14 +1643,15 @@ async function toggleAntigravityQuotaDetails(pathId) {
contentDiv.innerHTML = quotaHTML;
}
- showStatus('✅ 成功加载额度信息', 'success');
+ contentDiv.setAttribute('data-loaded', 'true');
+ showStatus('✅ Quota information loaded successfully', 'success');
} else {
- // 失败时显示错误
- const errorMsg = data.error || '获取额度信息失败';
+ // Show error on failure
+ const errorMsg = data.error || 'Failed to get quota information';
contentDiv.innerHTML = `
❌
-
获取额度信息失败
+
Failed to get quota information
${errorMsg}
`;
@@ -1922,207 +1661,31 @@ async function toggleAntigravityQuotaDetails(pathId) {
contentDiv.innerHTML = `
❌
-
网络错误
+
Network Error
${error.message}
`;
- showStatus(`❌ 获取额度信息失败: ${error.message}`, 'error');
+ showStatus(`❌ Failed to get quota information: ${error.message}`, 'error');
}
}
}
}
-// =====================================================================
-// 查看报错详情
-// =====================================================================
-async function toggleErrorDetails(pathId) {
- await toggleErrorDetailsCommon(pathId, AppState.creds);
-}
-
-async function toggleAntigravityErrorDetails(pathId) {
- await toggleErrorDetailsCommon(pathId, AppState.antigravityCreds);
-}
-
-async function toggleErrorDetailsCommon(pathId, manager) {
- const errorDetails = document.getElementById('errors-' + pathId);
- if (!errorDetails) return;
-
- // 切换显示状态
- const isShowing = errorDetails.classList.toggle('show');
-
- if (isShowing) {
- const contentDiv = errorDetails.querySelector('.cred-content');
- const filename = contentDiv.getAttribute('data-filename');
-
- // 每次展开都重新加载数据
- if (filename) {
- contentDiv.innerHTML = '
⏳ 正在加载报错信息...
';
-
- try {
- const modeParam = manager.type === 'antigravity' ? 'mode=antigravity' : 'mode=geminicli';
- const response = await fetch(`./creds/errors/${encodeURIComponent(filename)}?${modeParam}`, {
- method: 'GET',
- headers: getAuthHeaders()
- });
- const data = await response.json();
-
- if (response.ok) {
- const errorCodes = data.error_codes || [];
- const errorMessages = data.error_messages || {};
-
- if (errorCodes.length === 0) {
- contentDiv.innerHTML = `
-
- `;
- } else {
- let errorHTML = '';
-
- // 遍历所有错误码,从 errorMessages 对象中获取对应消息
- errorCodes.forEach((errorCode) => {
- const messageStr = errorMessages[errorCode] || '无详细信息';
-
- // 提取核心错误消息和详细信息
- let displayMsg = messageStr;
- let detailsHtml = '';
-
- try {
- // 尝试解析 JSON 格式的 message
- const parsedMsg = JSON.parse(messageStr);
- if (parsedMsg.error) {
- // 显示核心错误信息
- if (parsedMsg.error.message) {
- displayMsg = parsedMsg.error.message;
- }
-
- // 如果有 details 字段,也显示出来
- if (parsedMsg.error.details && Array.isArray(parsedMsg.error.details)) {
- detailsHtml = '
';
- detailsHtml += '
详细信息:
';
-
- parsedMsg.error.details.forEach((detail, idx) => {
- detailsHtml += '
';
-
- // 显示 @type
- if (detail['@type']) {
- const highlightedType = highlightHttpLinks(escapeHtml(detail['@type']));
- detailsHtml += `
类型: ${highlightedType}
`;
- }
-
- // 显示 reason
- if (detail.reason) {
- detailsHtml += `
原因: ${escapeHtml(detail.reason)}
`;
- }
-
- // 显示 metadata(如 quotaResetTimeStamp)
- if (detail.metadata) {
- detailsHtml += '
';
- for (const [key, value] of Object.entries(detail.metadata)) {
- const highlightedValue = highlightHttpLinks(escapeHtml(String(value)));
- detailsHtml += `
${escapeHtml(key)}: ${highlightedValue}
`;
- }
- detailsHtml += '
';
- }
-
- detailsHtml += '
';
- });
-
- detailsHtml += '
';
- }
-
- // 如果有 status 字段,也显示
- if (parsedMsg.error.status) {
- if (!detailsHtml) {
- detailsHtml = '
';
- }
- detailsHtml += `
状态: ${escapeHtml(parsedMsg.error.status)}
`;
- if (!parsedMsg.error.details) {
- detailsHtml += '
';
- }
- }
- }
- } catch (e) {
- // 如果不是 JSON 格式,直接使用原始消息
- }
-
- // 对消息中的HTTP链接进行高亮处理
- const highlightedMsg = highlightHttpLinks(escapeHtml(displayMsg));
-
- errorHTML += `
-
-
错误码: ${errorCode}
-
- ${highlightedMsg}
-
- ${detailsHtml}
-
- `;
- });
-
- contentDiv.innerHTML = errorHTML;
- }
-
- showStatus('✅ 成功加载报错信息', 'success');
- } else {
- // 失败时显示错误
- const errorMsg = data.detail || data.error || '获取报错信息失败';
- contentDiv.innerHTML = `
-
-
❌
-
加载失败
-
${errorMsg}
-
- `;
- showStatus(`❌ 获取报错信息失败: ${errorMsg}`, 'error');
- }
- } catch (error) {
- contentDiv.innerHTML = `
-
-
❌
-
网络错误
-
${error.message}
-
- `;
- showStatus(`❌ 获取报错信息失败: ${error.message}`, 'error');
- }
- }
- }
-}
-
-// HTML转义函数
-function escapeHtml(text) {
- const div = document.createElement('div');
- div.textContent = text;
- return div.innerHTML;
-}
-
-// 高亮HTTP链接函数
-function highlightHttpLinks(text) {
- // 匹配 http:// 或 https:// 开头的URL
- const urlRegex = /(https?:\/\/[^\s<>"]+)/gi;
- return text.replace(urlRegex, function(url) {
- return `
${url}`;
- });
-}
-
async function batchVerifyProjectIds() {
const selectedFiles = Array.from(AppState.creds.selectedFiles);
if (selectedFiles.length === 0) {
- showStatus('❌ 请先选择要检验的凭证', 'error');
- showMessageModal('提示', '请先选择要检验的凭证', 'error');
+ showStatus('❌ Please select credentials to verify first', 'error');
+ alert('Please select credentials to verify first');
return;
}
- if (!confirm(`确定要批量检验 ${selectedFiles.length} 个凭证的Project ID吗?\n\n将并行检验以加快速度。`)) {
+ if (!confirm(`Are you sure you want to batch verify ${selectedFiles.length} credentials'Project ID?\n\nParallel verification will be used to speed up.`)) {
return;
}
- showStatus(`🔍 正在并行检验 ${selectedFiles.length} 个凭证,请稍候...`, 'info');
+ showStatus(`🔍 Parallel verification in progress ${selectedFiles.length} credentials...`, 'info');
- // 并行执行所有检验请求
+ // Execute all verification requests in parallel
const promises = selectedFiles.map(async (filename) => {
try {
const response = await fetch(`./creds/verify-project/${encodeURIComponent(filename)}`, {
@@ -2132,25 +1695,19 @@ async function batchVerifyProjectIds() {
const data = await response.json();
if (response.ok && data.success) {
- return {
- success: true,
- filename,
- projectId: data.project_id,
- creditAmount: data.credit_amount,
- message: data.message
- };
+ return { success: true, filename, projectId: data.project_id, message: data.message };
} else {
- return { success: false, filename, error: data.message || '失败' };
+ return { success: false, filename, error: data.message || 'Failed' };
}
} catch (error) {
return { success: false, filename, error: error.message };
}
});
- // 等待所有请求完成
+ // Wait for all requests to complete
const results = await Promise.all(promises);
- // 统计结果
+ // Statistics results
let successCount = 0;
let failCount = 0;
const resultMessages = [];
@@ -2158,10 +1715,7 @@ async function batchVerifyProjectIds() {
results.forEach(result => {
if (result.success) {
successCount++;
- const creditSuffix = result.creditAmount !== undefined && result.creditAmount !== null
- ? ` (积分: ${result.creditAmount})`
- : '';
- resultMessages.push(`✅ ${result.filename}: ${result.projectId}${creditSuffix}`);
+ resultMessages.push(`✅ ${result.filename}: ${result.projectId}`);
} else {
failCount++;
resultMessages.push(`❌ ${result.filename}: ${result.error}`);
@@ -2170,37 +1724,35 @@ async function batchVerifyProjectIds() {
await AppState.creds.refresh();
- const summary = `批量检验完成!\n\n成功: ${successCount} 个\n失败: ${failCount} 个\n总计: ${selectedFiles.length} 个\n\n详细结果:\n${resultMessages.join('\n')}`;
+ const summary = `Batch verification complete!\n\nSuccess: ${successCount} units\nFailed: ${failCount} units\nTotal: ${selectedFiles.length} units\n\nDetailed results:\n${resultMessages.join('\n')}`;
if (failCount === 0) {
- showStatus(`✅ 全部检验成功!成功检验 ${successCount}/${selectedFiles.length} 个凭证`, 'success');
- showMessageModal('批量检验完成', summary, 'success');
+ showStatus(`✅ All verifications successful! Successfully verified ${successCount}/${selectedFiles.length} credentials`, 'success');
} else if (successCount === 0) {
- showStatus(`❌ 全部检验失败!失败 ${failCount}/${selectedFiles.length} 个凭证`, 'error');
- showMessageModal('批量检验完成', summary, 'error');
+ showStatus(`❌ All verifications failed! Failed ${failCount}/${selectedFiles.length} credentials`, 'error');
} else {
- showStatus(`⚠️ 批量检验完成:成功 ${successCount}/${selectedFiles.length} 个,失败 ${failCount} 个`, 'info');
- showMessageModal('批量检验完成', summary, 'info');
+ showStatus(`⚠️ Batch verification complete: Success ${successCount}/${selectedFiles.length} files, failed ${failCount} units`, 'info');
}
console.log(summary);
+ alert(summary);
}
async function batchVerifyAntigravityProjectIds() {
const selectedFiles = Array.from(AppState.antigravityCreds.selectedFiles);
if (selectedFiles.length === 0) {
- showStatus('❌ 请先选择要检验的Antigravity凭证', 'error');
- showMessageModal('提示', '请先选择要检验的Antigravity凭证', 'error');
+ showStatus('❌ Please select theAntigravityCredentials', 'error');
+ alert('Please select theAntigravityCredentials');
return;
}
- if (!confirm(`确定要批量检验 ${selectedFiles.length} 个Antigravity凭证的Project ID吗?\n\n将并行检验以加快速度。`)) {
+ if (!confirm(`Are you sure you want to batch verify ${selectedFiles.length} unitsAntigravitycredentials'Project ID?\n\nParallel verification will be used to speed up.`)) {
return;
}
- showStatus(`🔍 正在并行检验 ${selectedFiles.length} 个Antigravity凭证,请稍候...`, 'info');
+ showStatus(`🔍 Parallel verification in progress ${selectedFiles.length} unitsAntigravitycredentials...`, 'info');
- // 并行执行所有检验请求
+ // Execute all verification requests in parallel
const promises = selectedFiles.map(async (filename) => {
try {
const response = await fetch(`./creds/verify-project/${encodeURIComponent(filename)}?mode=antigravity`, {
@@ -2210,25 +1762,19 @@ async function batchVerifyAntigravityProjectIds() {
const data = await response.json();
if (response.ok && data.success) {
- return {
- success: true,
- filename,
- projectId: data.project_id,
- creditAmount: data.credit_amount,
- message: data.message
- };
+ return { success: true, filename, projectId: data.project_id, message: data.message };
} else {
- return { success: false, filename, error: data.message || '失败' };
+ return { success: false, filename, error: data.message || 'Failed' };
}
} catch (error) {
return { success: false, filename, error: error.message };
}
});
- // 等待所有请求完成
+ // Wait for all requests to complete
const results = await Promise.all(promises);
- // 统计结果
+ // Statistics results
let successCount = 0;
let failCount = 0;
const resultMessages = [];
@@ -2236,10 +1782,7 @@ async function batchVerifyAntigravityProjectIds() {
results.forEach(result => {
if (result.success) {
successCount++;
- const creditSuffix = result.creditAmount !== undefined && result.creditAmount !== null
- ? ` (积分: ${result.creditAmount})`
- : '';
- resultMessages.push(`✅ ${result.filename}: ${result.projectId}${creditSuffix}`);
+ resultMessages.push(`✅ ${result.filename}: ${result.projectId}`);
} else {
failCount++;
resultMessages.push(`❌ ${result.filename}: ${result.error}`);
@@ -2248,215 +1791,131 @@ async function batchVerifyAntigravityProjectIds() {
await AppState.antigravityCreds.refresh();
- const summary = `Antigravity批量检验完成!\n\n成功: ${successCount} 个\n失败: ${failCount} 个\n总计: ${selectedFiles.length} 个\n\n详细结果:\n${resultMessages.join('\n')}`;
+ const summary = `AntigravityBatch verification complete!\n\nSuccess: ${successCount} units\nFailed: ${failCount} units\nTotal: ${selectedFiles.length} units\n\nDetailed results:\n${resultMessages.join('\n')}`;
if (failCount === 0) {
- showStatus(`✅ 全部检验成功!成功检验 ${successCount}/${selectedFiles.length} 个Antigravity凭证`, 'success');
- showMessageModal('Antigravity批量检验完成', summary, 'success');
+ showStatus(`✅ All verifications successful! Successfully verified ${successCount}/${selectedFiles.length} unitsAntigravityCredentials`, 'success');
} else if (successCount === 0) {
- showStatus(`❌ 全部检验失败!失败 ${failCount}/${selectedFiles.length} 个Antigravity凭证`, 'error');
- showMessageModal('Antigravity批量检验完成', summary, 'error');
+ showStatus(`❌ All verifications failed! Failed ${failCount}/${selectedFiles.length} unitsAntigravityCredentials`, 'error');
} else {
- showStatus(`⚠️ 批量检验完成:成功 ${successCount}/${selectedFiles.length} 个,失败 ${failCount} 个`, 'info');
- showMessageModal('Antigravity批量检验完成', summary, 'info');
- }
-
- console.log(summary);
-}
-
-async function batchConfigurePreview() {
- const selectedFiles = Array.from(AppState.creds.selectedFiles);
- if (selectedFiles.length === 0) {
- showStatus('❌ 请先选择要配置Preview的凭证', 'error');
- showMessageModal('提示', '请先选择要配置Preview的凭证', 'error');
- return;
- }
-
- if (!confirm(`确定要为 ${selectedFiles.length} 个凭证批量设置Preview通道吗?\n\n将并行配置以加快速度。`)) {
- return;
- }
-
- showStatus(`🔧 正在为 ${selectedFiles.length} 个凭证配置Preview通道,请稍候...`, 'info');
-
- // 并行执行所有配置请求
- const promises = selectedFiles.map(async (filename) => {
- try {
- const response = await fetch(`./creds/configure-preview/${encodeURIComponent(filename)}`, {
- method: 'POST',
- headers: getAuthHeaders()
- });
- const data = await response.json();
-
- if (response.ok && data.success) {
- return {
- success: true,
- filename,
- message: data.message,
- setting_id: data.setting_id,
- binding_id: data.binding_id
- };
- } else {
- return {
- success: false,
- filename,
- error: data.message || '配置失败',
- step: data.step,
- errorDetail: data.error
- };
- }
- } catch (error) {
- return { success: false, filename, error: error.message };
- }
- });
-
- // 等待所有请求完成
- const results = await Promise.all(promises);
-
- // 统计结果
- let successCount = 0;
- let failCount = 0;
- const resultMessages = [];
-
- results.forEach(result => {
- if (result.success) {
- successCount++;
- resultMessages.push(`✅ ${result.filename}: ${result.message || '配置成功'}`);
- } else {
- failCount++;
- const errorMsg = result.step ? `${result.error} (步骤: ${result.step})` : result.error;
- resultMessages.push(`❌ ${result.filename}: ${errorMsg}`);
- }
- });
-
- await AppState.creds.refresh();
-
- const summary = `批量配置Preview通道完成!\n\n成功: ${successCount} 个\n失败: ${failCount} 个\n总计: ${selectedFiles.length} 个\n\n详细结果:\n${resultMessages.join('\n')}`;
-
- if (failCount === 0) {
- showStatus(`✅ 全部配置成功!成功配置 ${successCount}/${selectedFiles.length} 个凭证的Preview通道`, 'success');
- showMessageModal('批量配置Preview通道完成', summary, 'success');
- } else if (successCount === 0) {
- showStatus(`❌ 全部配置失败!失败 ${failCount}/${selectedFiles.length} 个凭证`, 'error');
- showMessageModal('批量配置Preview通道完成', summary, 'error');
- } else {
- showStatus(`⚠️ 批量配置完成:成功 ${successCount}/${selectedFiles.length} 个,失败 ${failCount} 个`, 'info');
- showMessageModal('批量配置Preview通道完成', summary, 'info');
+ showStatus(`⚠️ Batch verification complete: Success ${successCount}/${selectedFiles.length} files, failed ${failCount} units`, 'info');
}
console.log(summary);
+ alert(summary);
}
async function refreshAllEmails() {
- if (!confirm('确定要刷新所有凭证的用户邮箱吗?这可能需要一些时间。')) return;
+ if (!confirm('Are you sure you want to refresh all user emails? This may take some time.')) return;
try {
- showStatus('正在刷新所有用户邮箱...', 'info');
+ showStatus('Refreshing all user emails...', 'info');
const response = await fetch('./creds/refresh-all-emails', {
method: 'POST',
headers: getAuthHeaders()
});
const data = await response.json();
if (response.ok) {
- showStatus(`邮箱刷新完成:成功获取 ${data.success_count}/${data.total_count} 个邮箱地址`, 'success');
+ showStatus(`Email refresh complete: Successfully fetched ${data.success_count}/${data.total_count} email addresses`, 'success');
await AppState.creds.refresh();
} else {
- showStatus(data.message || '邮箱刷新失败', 'error');
+ showStatus(data.message || 'Email refresh failed', 'error');
}
} catch (error) {
- showStatus(`邮箱刷新网络错误: ${error.message}`, 'error');
+ showStatus(`Email refresh network error: ${error.message}`, 'error');
}
}
async function refreshAllAntigravityEmails() {
- if (!confirm('确定要刷新所有Antigravity凭证的用户邮箱吗?这可能需要一些时间。')) return;
+ if (!confirm('Are you sure you want to refresh allAntigravitycredentials' user email? This may take some time.')) return;
try {
- showStatus('正在刷新所有用户邮箱...', 'info');
+ showStatus('Refreshing all user emails...', 'info');
const response = await fetch('./creds/refresh-all-emails?mode=antigravity', {
method: 'POST',
headers: getAuthHeaders()
});
const data = await response.json();
if (response.ok) {
- showStatus(`邮箱刷新完成:成功获取 ${data.success_count}/${data.total_count} 个邮箱地址`, 'success');
+ showStatus(`Email refresh complete: Successfully fetched ${data.success_count}/${data.total_count} email addresses`, 'success');
await AppState.antigravityCreds.refresh();
} else {
- showStatus(data.message || '邮箱刷新失败', 'error');
+ showStatus(data.message || 'Email refresh failed', 'error');
}
} catch (error) {
- showStatus(`邮箱刷新网络错误: ${error.message}`, 'error');
+ showStatus(`Email refresh network error: ${error.message}`, 'error');
}
}
async function deduplicateByEmail() {
- if (!confirm('确定要对凭证进行凭证一键去重吗?\n\n相同邮箱的凭证只保留一个,其他将被删除。\n此操作不可撤销!')) return;
+ if (!confirm('Are you sure you want to perform one-click credential deduplication?\n\nOnly one credential per email will be kept\nThis action cannot be undone!')) return;
try {
- showStatus('正在进行凭证一键去重...', 'info');
+ showStatus('One-click credential deduplication in progress...', 'info');
const response = await fetch('./creds/deduplicate-by-email', {
method: 'POST',
headers: getAuthHeaders()
});
const data = await response.json();
if (response.ok) {
- const msg = `去重完成:删除 ${data.deleted_count} 个重复凭证,保留 ${data.kept_count} 个凭证(${data.unique_emails_count} 个唯一邮箱)`;
+ const msg = `Deduplication complete: Deleted ${data.deleted_count} duplicate credentials ${data.kept_count} credentials (${data.unique_emails_count} unique emails)`;
showStatus(msg, 'success');
await AppState.creds.refresh();
- // 显示详细信息
+ // Show detailed information
if (data.duplicate_groups && data.duplicate_groups.length > 0) {
- let details = '去重详情:\n\n';
+ let details = 'Deduplication details:\n\n';
data.duplicate_groups.forEach(group => {
- details += `邮箱: ${group.email}\n保留: ${group.kept_file}\n删除: ${group.deleted_files.join(', ')}\n\n`;
+ details += `Email: ${group.email}\nKeep: ${group.kept_file}\nDelete: ${group.deleted_files.join(', ')}\n\n`;
});
console.log(details);
}
} else {
- showStatus(data.message || '去重失败', 'error');
+ showStatus(data.message || 'Deduplication failed', 'error');
}
} catch (error) {
- showStatus(`去重网络错误: ${error.message}`, 'error');
+ showStatus(`Deduplication network error: ${error.message}`, 'error');
}
}
async function deduplicateAntigravityByEmail() {
- if (!confirm('确定要对Antigravity凭证进行凭证一键去重吗?\n\n相同邮箱的凭证只保留一个,其他将被删除。\n此操作不可撤销!')) return;
+ if (!confirm('Are you sure you want to performAntigravitycredentials for one-click deduplication?\n\nOnly one credential per email will be kept\nThis action cannot be undone!')) return;
try {
- showStatus('正在进行凭证一键去重...', 'info');
+ showStatus('One-click credential deduplication in progress...', 'info');
const response = await fetch('./creds/deduplicate-by-email?mode=antigravity', {
method: 'POST',
headers: getAuthHeaders()
});
const data = await response.json();
if (response.ok) {
- const msg = `去重完成:删除 ${data.deleted_count} 个重复凭证,保留 ${data.kept_count} 个凭证(${data.unique_emails_count} 个唯一邮箱)`;
+ const msg = `Deduplication complete: Deleted ${data.deleted_count} duplicate credentials ${data.kept_count} credentials (${data.unique_emails_count} unique emails)`;
showStatus(msg, 'success');
await AppState.antigravityCreds.refresh();
- // 显示详细信息
+ // Show detailed information
if (data.duplicate_groups && data.duplicate_groups.length > 0) {
- let details = '去重详情:\n\n';
+ let details = 'Deduplication details:\n\n';
data.duplicate_groups.forEach(group => {
- details += `邮箱: ${group.email}\n保留: ${group.kept_file}\n删除: ${group.deleted_files.join(', ')}\n\n`;
+ details += `Email: ${group.email}\nKeep: ${group.kept_file}\nDelete: ${group.deleted_files.join(', ')}\n\n`;
});
console.log(details);
}
} else {
- showStatus(data.message || '去重失败', 'error');
+ showStatus(data.message || 'Deduplication failed', 'error');
}
} catch (error) {
- showStatus(`去重网络错误: ${error.message}`, 'error');
+ showStatus(`Deduplication network error: ${error.message}`, 'error');
}
}
// =====================================================================
-// WebSocket日志相关
+// WebSocketLog related
// =====================================================================
function connectWebSocket() {
if (AppState.logWebSocket && AppState.logWebSocket.readyState === WebSocket.OPEN) {
- showStatus('WebSocket已经连接', 'info');
+ showStatus('WebSocketConnected', 'info');
return;
}
@@ -2464,18 +1923,18 @@ function connectWebSocket() {
const wsPath = new URL('./logs/stream', window.location.href).href;
const wsUrl = wsPath.replace(/^http/, 'ws');
- // 添加 token 认证参数
+ // Add token Authentication parameters
const wsUrlWithAuth = `${wsUrl}?token=${encodeURIComponent(AppState.authToken)}`;
- document.getElementById('connectionStatusText').textContent = '连接中...';
+ document.getElementById('connectionStatusText').textContent = 'Connecting...';
document.getElementById('logConnectionStatus').className = 'status info';
AppState.logWebSocket = new WebSocket(wsUrlWithAuth);
AppState.logWebSocket.onopen = () => {
- document.getElementById('connectionStatusText').textContent = '已连接';
+ document.getElementById('connectionStatusText').textContent = 'Connected';
document.getElementById('logConnectionStatus').className = 'status success';
- showStatus('日志流连接成功', 'success');
+ showStatus('Log stream connected successfully', 'success');
clearLogsDisplay();
};
@@ -2495,19 +1954,19 @@ function connectWebSocket() {
};
AppState.logWebSocket.onclose = () => {
- document.getElementById('connectionStatusText').textContent = '连接断开';
+ document.getElementById('connectionStatusText').textContent = 'Connection disconnected';
document.getElementById('logConnectionStatus').className = 'status error';
- showStatus('日志流连接断开', 'info');
+ showStatus('Log stream connection disconnected', 'info');
};
AppState.logWebSocket.onerror = (error) => {
- document.getElementById('connectionStatusText').textContent = '连接错误';
+ document.getElementById('connectionStatusText').textContent = 'Connection error';
document.getElementById('logConnectionStatus').className = 'status error';
- showStatus('日志流连接错误: ' + error, 'error');
+ showStatus('Log stream connection error: ' + error, 'error');
};
} catch (error) {
- showStatus('创建WebSocket连接失败: ' + error.message, 'error');
- document.getElementById('connectionStatusText').textContent = '连接失败';
+ showStatus('CreateWebSocketConnection failed: ' + error.message, 'error');
+ document.getElementById('connectionStatusText').textContent = 'Connection failed';
document.getElementById('logConnectionStatus').className = 'status error';
}
}
@@ -2516,16 +1975,16 @@ function disconnectWebSocket() {
if (AppState.logWebSocket) {
AppState.logWebSocket.close();
AppState.logWebSocket = null;
- document.getElementById('connectionStatusText').textContent = '未连接';
+ document.getElementById('connectionStatusText').textContent = 'Not connected';
document.getElementById('logConnectionStatus').className = 'status info';
- showStatus('日志流连接已断开', 'info');
+ showStatus('Log stream connection has been disconnected', 'info');
}
}
function clearLogsDisplay() {
AppState.allLogs = [];
AppState.filteredLogs = [];
- document.getElementById('logContent').textContent = '日志已清空,等待新日志...';
+ document.getElementById('logContent').textContent = 'Logs cleared...';
}
async function downloadLogs() {
@@ -2548,13 +2007,13 @@ async function downloadLogs() {
a.click();
window.URL.revokeObjectURL(url);
- showStatus(`日志文件下载成功: ${filename}`, 'success');
+ showStatus(`Log file downloaded successfully: ${filename}`, 'success');
} else {
const data = await response.json();
- showStatus(`下载日志失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Failed to download logs: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`下载日志时网络错误: ${error.message}`, 'error');
+ showStatus(`Network error while downloading logs: ${error.message}`, 'error');
}
}
@@ -2571,11 +2030,11 @@ async function clearLogs() {
clearLogsDisplay();
showStatus(data.message, 'success');
} else {
- showStatus(`清空日志失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Failed to clear logs: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
clearLogsDisplay();
- showStatus(`清空日志时网络错误: ${error.message}`, 'error');
+ showStatus(`Network error while clearing logs: ${error.message}`, 'error');
}
}
@@ -2596,14 +2055,14 @@ function displayLogs() {
const logContent = document.getElementById('logContent');
if (AppState.filteredLogs.length === 0) {
logContent.textContent = AppState.currentLogFilter === 'all' ?
- '暂无日志...' : `暂无${AppState.currentLogFilter}级别的日志...`;
+ 'No logs available...' : `None${AppState.currentLogFilter}level logs...`;
} else {
logContent.textContent = AppState.filteredLogs.join('\n');
}
}
// =====================================================================
-// 环境变量凭证管理
+// Environment variable credential management
// =====================================================================
async function checkEnvCredsStatus() {
const loading = document.getElementById('envStatusLoading');
@@ -2620,26 +2079,26 @@ async function checkEnvCredsStatus() {
const envVarsList = document.getElementById('envVarsList');
envVarsList.textContent = Object.keys(data.available_env_vars).length > 0
? Object.keys(data.available_env_vars).join(', ')
- : '未找到GCLI_CREDS_*环境变量';
+ : 'Not foundGCLI_CREDS_*Environment Variables';
const autoLoadStatus = document.getElementById('autoLoadStatus');
- autoLoadStatus.textContent = data.auto_load_enabled ? '✅ 已启用' : '❌ 未启用';
+ autoLoadStatus.textContent = data.auto_load_enabled ? '✅ Enabled' : '❌ Not enabled';
autoLoadStatus.style.color = data.auto_load_enabled ? '#28a745' : '#dc3545';
- document.getElementById('envFilesCount').textContent = `${data.existing_env_files_count} 个文件`;
+ document.getElementById('envFilesCount').textContent = `${data.existing_env_files_count} files`;
const envFilesList = document.getElementById('envFilesList');
envFilesList.textContent = data.existing_env_files.length > 0
? data.existing_env_files.join(', ')
- : '无';
+ : 'None';
content.classList.remove('hidden');
- showStatus('环境变量状态检查完成', 'success');
+ showStatus('Environment variable status check complete', 'success');
} else {
- showStatus(`获取环境变量状态失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Failed to get environment variable status: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
} finally {
loading.style.display = 'none';
}
@@ -2647,7 +2106,7 @@ async function checkEnvCredsStatus() {
async function loadEnvCredentials() {
try {
- showStatus('正在从环境变量导入凭证...', 'info');
+ showStatus('Importing credentials from environment variables...', 'info');
const response = await fetch('./auth/load-env-creds', {
method: 'POST',
@@ -2658,26 +2117,26 @@ async function loadEnvCredentials() {
if (response.ok) {
if (data.loaded_count > 0) {
- showStatus(`✅ 成功导入 ${data.loaded_count}/${data.total_count} 个凭证文件`, 'success');
+ showStatus(`✅ Successfully imported ${data.loaded_count}/${data.total_count} credential files`, 'success');
setTimeout(() => checkEnvCredsStatus(), 1000);
} else {
showStatus(`⚠️ ${data.message}`, 'info');
}
} else {
- showStatus(`导入失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Import failed: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
}
}
async function clearEnvCredentials() {
- if (!confirm('确定要清除所有从环境变量导入的凭证文件吗?\n这将删除所有文件名以 "env-" 开头的认证文件。')) {
+ if (!confirm('Are you sure you want to clear all credential files imported from environment variables?\nThis will delete all authentication files starting with "env-" prefix.')) {
return;
}
try {
- showStatus('正在清除环境变量凭证文件...', 'info');
+ showStatus('Clearing environment variable credential files...', 'info');
const response = await fetch('./auth/env-creds', {
method: 'DELETE',
@@ -2687,18 +2146,18 @@ async function clearEnvCredentials() {
const data = await response.json();
if (response.ok) {
- showStatus(`✅ 成功删除 ${data.deleted_count} 个环境变量凭证文件`, 'success');
+ showStatus(`✅ Successfully deleted ${data.deleted_count} environment variable credential files`, 'success');
setTimeout(() => checkEnvCredsStatus(), 1000);
} else {
- showStatus(`清除失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Clear failed: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
}
}
// =====================================================================
-// 配置管理
+// Configuration Management
// =====================================================================
async function loadConfig() {
const loading = document.getElementById('configLoading');
@@ -2717,12 +2176,12 @@ async function loadConfig() {
populateConfigForm();
form.classList.remove('hidden');
- showStatus('配置加载成功', 'success');
+ showStatus('Configuration loaded successfully', 'success');
} else {
- showStatus(`加载配置失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Failed to load configuration: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
} finally {
loading.style.display = 'none';
}
@@ -2756,12 +2215,8 @@ function populateConfigForm() {
document.getElementById('compatibilityModeEnabled').checked = Boolean(c.compatibility_mode_enabled);
document.getElementById('returnThoughtsToFrontend').checked = Boolean(c.return_thoughts_to_frontend !== false);
document.getElementById('antigravityStream2nostream').checked = Boolean(c.antigravity_stream2nostream !== false);
- document.getElementById('antigravitySwitchCredentialEnabled').checked = Boolean(c.antigravity_switch_credential_enabled);
setConfigField('antiTruncationMaxAttempts', c.anti_truncation_max_attempts || 3);
-
- setConfigField('keepaliveUrl', c.keepalive_url || '');
- setConfigField('keepaliveInterval', c.keepalive_interval || 60);
}
function setConfigField(fieldId, value) {
@@ -2810,10 +2265,7 @@ async function saveConfig() {
compatibility_mode_enabled: getChecked('compatibilityModeEnabled'),
return_thoughts_to_frontend: getChecked('returnThoughtsToFrontend'),
antigravity_stream2nostream: getChecked('antigravityStream2nostream'),
- antigravity_switch_credential_enabled: getChecked('antigravitySwitchCredentialEnabled'),
- anti_truncation_max_attempts: getInt('antiTruncationMaxAttempts', 3),
- keepalive_url: getValue('keepaliveUrl'),
- keepalive_interval: getInt('keepaliveInterval', 60)
+ anti_truncation_max_attempts: getInt('antiTruncationMaxAttempts', 3)
};
const response = await fetch('./config/save', {
@@ -2825,14 +2277,14 @@ async function saveConfig() {
const data = await response.json();
if (response.ok) {
- let message = '配置保存成功';
+ let message = 'Configuration saved successfully';
if (data.hot_updated && data.hot_updated.length > 0) {
- message += `,以下配置已立即生效: ${data.hot_updated.join(', ')}`;
+ message += `: ${data.hot_updated.join(', ')}`;
}
if (data.restart_required && data.restart_required.length > 0) {
- message += `\n⚠️ 重启提醒: ${data.restart_notice}`;
+ message += `\n⚠️ Restart reminder: ${data.restart_notice}`;
showStatus(message, 'info');
} else {
showStatus(message, 'success');
@@ -2840,14 +2292,14 @@ async function saveConfig() {
setTimeout(() => loadConfig(), 1000);
} else {
- showStatus(`保存配置失败: ${data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Failed to save configuration: ${data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
}
}
-// 镜像网址配置
+// Mirror URL configuration
const mirrorUrls = {
codeAssistEndpoint: 'https://gcli-api.sukaka.top/cloudcode-pa',
oauthProxyUrl: 'https://gcli-api.sukaka.top/oauth2',
@@ -2863,31 +2315,31 @@ const officialUrls = {
googleapisProxyUrl: 'https://www.googleapis.com',
resourceManagerApiUrl: 'https://cloudresourcemanager.googleapis.com',
serviceUsageApiUrl: 'https://serviceusage.googleapis.com',
- antigravityApiUrl: 'https://daily-cloudcode-pa.googleapis.com'
+ antigravityApiUrl: 'https://daily-cloudcode-pa.sandbox.googleapis.com'
};
function useMirrorUrls() {
- if (confirm('确定要将所有端点配置为镜像网址吗?')) {
+ if (confirm('Are you sure you want to configure all endpoints as mirror URLs?')) {
for (const [fieldId, url] of Object.entries(mirrorUrls)) {
const field = document.getElementById(fieldId);
if (field && !field.disabled) field.value = url;
}
- showStatus('✅ 已切换到镜像网址配置,记得点击"保存配置"按钮保存设置', 'success');
+ showStatus('✅ Switched to mirror URL configuration"Save configuration"button to save settings', 'success');
}
}
function restoreOfficialUrls() {
- if (confirm('确定要将所有端点配置为官方地址吗?')) {
+ if (confirm('Are you sure you want to configure all endpoints as official addresses?')) {
for (const [fieldId, url] of Object.entries(officialUrls)) {
const field = document.getElementById(fieldId);
if (field && !field.disabled) field.value = url;
}
- showStatus('✅ 已切换到官方端点配置,记得点击"保存配置"按钮保存设置', 'success');
+ showStatus('✅ Switched to official endpoint configuration"Save configuration"button to save settings', 'success');
}
}
// =====================================================================
-// 使用统计
+// Usage Statistics
// =====================================================================
async function refreshUsageStats() {
const loading = document.getElementById('usageLoading');
@@ -2903,7 +2355,7 @@ async function refreshUsageStats() {
]);
if (statsResponse.status === 401 || aggregatedResponse.status === 401) {
- showStatus('认证失败,请重新登录', 'error');
+ showStatus('Authentication failed', 'error');
setTimeout(() => location.reload(), 1500);
return;
}
@@ -2921,13 +2373,13 @@ async function refreshUsageStats() {
renderUsageList();
- showStatus(`已加载 ${aggData.total_files || Object.keys(AppState.usageStatsData).length} 个文件的使用统计`, 'success');
+ showStatus(`Loaded ${aggData.total_files || Object.keys(AppState.usageStatsData).length} usage statistics for files`, 'success');
} else {
- const errorMsg = statsData.detail || aggregatedData.detail || '加载使用统计失败';
- showStatus(`错误: ${errorMsg}`, 'error');
+ const errorMsg = statsData.detail || aggregatedData.detail || 'Failed to load usage statistics';
+ showStatus(`Error: ${errorMsg}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
} finally {
loading.style.display = 'none';
}
@@ -2938,7 +2390,7 @@ function renderUsageList() {
list.innerHTML = '';
if (Object.keys(AppState.usageStatsData).length === 0) {
- list.innerHTML = '
暂无使用统计数据
';
+ list.innerHTML = '
No usage statistics data available
';
return;
}
@@ -2954,12 +2406,12 @@ function renderUsageList() {
`;
@@ -2968,7 +2420,7 @@ function renderUsageList() {
}
async function resetSingleUsageStats(filename) {
- if (!confirm(`确定要重置 ${filename} 的使用统计吗?`)) return;
+ if (!confirm(`Are you sure you want to reset ${filename} usage statistics?`)) return;
try {
const response = await fetch('./usage/reset', {
@@ -2983,15 +2435,15 @@ async function resetSingleUsageStats(filename) {
showStatus(data.message, 'success');
await refreshUsageStats();
} else {
- showStatus(`重置失败: ${data.message || data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Reset failed: ${data.message || data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
}
}
async function resetAllUsageStats() {
- if (!confirm('确定要重置所有文件的使用统计吗?此操作不可恢复!')) return;
+ if (!confirm('Are you sure you want to reset usage statistics for all files? This action cannot be undone!')) return;
try {
const response = await fetch('./usage/reset', {
@@ -3006,15 +2458,15 @@ async function resetAllUsageStats() {
showStatus(data.message, 'success');
await refreshUsageStats();
} else {
- showStatus(`重置失败: ${data.message || data.detail || data.error || '未知错误'}`, 'error');
+ showStatus(`Reset failed: ${data.message || data.detail || data.error || 'Unknown Error'}`, 'error');
}
} catch (error) {
- showStatus(`网络错误: ${error.message}`, 'error');
+ showStatus(`Network Error: ${error.message}`, 'error');
}
}
// =====================================================================
-// 冷却倒计时自动更新
+// Cooldown countdown auto-update
// =====================================================================
function startCooldownTimer() {
if (AppState.cooldownTimerInterval) {
@@ -3036,7 +2488,7 @@ function stopCooldownTimer() {
function updateCooldownDisplays() {
let needsRefresh = false;
- // 检查模型级冷却是否过期
+ // Check if model-level cooldown has expired
for (const credInfo of Object.values(AppState.creds.data)) {
if (credInfo.model_cooldowns && Object.keys(credInfo.model_cooldowns).length > 0) {
const currentTime = Date.now() / 1000;
@@ -3054,7 +2506,7 @@ function updateCooldownDisplays() {
return;
}
- // 更新模型级冷却的显示
+ // Update model-level cooldown display
document.querySelectorAll('.cooldown-badge').forEach(badge => {
const card = badge.closest('.cred-card');
const filenameEl = card?.querySelector('.cred-filename');
@@ -3065,7 +2517,7 @@ function updateCooldownDisplays() {
if (credInfo && credInfo.model_cooldowns) {
const currentTime = Date.now() / 1000;
- const titleMatch = badge.getAttribute('title')?.match(/模型: (.+)/);
+ const titleMatch = badge.getAttribute('title')?.match(/Model: (.+)/);
if (titleMatch) {
const model = titleMatch[1];
const cooldownUntil = credInfo.model_cooldowns[model];
@@ -3075,7 +2527,7 @@ function updateCooldownDisplays() {
const shortModel = model.replace('gemini-', '').replace('-exp', '')
.replace('2.0-', '2-').replace('1.5-', '1.5-');
const timeDisplay = formatCooldownTime(remaining).replace(/s$/, '').replace(/ /g, '');
- badge.innerHTML = `⏰ ${shortModel}: ${timeDisplay}`;
+ badge.innerHTML = `🔧 ${shortModel}: ${timeDisplay}`;
}
}
}
@@ -3084,10 +2536,10 @@ function updateCooldownDisplays() {
}
// =====================================================================
-// 版本信息管理
+// Version information management
// =====================================================================
-// 获取并显示版本信息(不检查更新)
+// Get and display version info (without checking for updates)
async function fetchAndDisplayVersion() {
try {
const response = await fetch('./version/info');
@@ -3096,24 +2548,24 @@ async function fetchAndDisplayVersion() {
const versionText = document.getElementById('versionText');
if (data.success) {
- // 只显示版本号
+ // Show version number only
versionText.textContent = `v${data.version}`;
- versionText.title = `完整版本: ${data.full_hash}\n提交信息: ${data.message}\n提交时间: ${data.date}`;
+ versionText.title = `Full version: ${data.full_hash}\nCommit message: ${data.message}\nCommit time: ${data.date}`;
versionText.style.cursor = 'help';
} else {
- versionText.textContent = '未知版本';
- versionText.title = data.error || '无法获取版本信息';
+ versionText.textContent = 'Unknown version';
+ versionText.title = data.error || 'Unable to get version information';
}
} catch (error) {
- console.error('获取版本信息失败:', error);
+ console.error('Failed to get version information:', error);
const versionText = document.getElementById('versionText');
if (versionText) {
- versionText.textContent = '版本信息获取失败';
+ versionText.textContent = 'Version information retrieval failed';
}
}
}
-// 检查更新
+// Check for updates
async function checkForUpdates() {
const checkBtn = document.getElementById('checkUpdateBtn');
if (!checkBtn) return;
@@ -3121,70 +2573,70 @@ async function checkForUpdates() {
const originalText = checkBtn.textContent;
try {
- // 显示检查中状态
- checkBtn.textContent = '检查中...';
+ // Show checking status
+ checkBtn.textContent = 'Checking...';
checkBtn.disabled = true;
- // 调用API检查更新
+ // CallAPICheck for updates
const response = await fetch('./version/info?check_update=true');
const data = await response.json();
if (data.success) {
if (data.check_update === false) {
- // 检查更新失败
- showStatus(`检查更新失败: ${data.update_error || '未知错误'}`, 'error');
+ // Failed to check for updates
+ showStatus(`Failed to check for updates: ${data.update_error || 'Unknown Error'}`, 'error');
} else if (data.has_update === true) {
- // 有更新
- const updateMsg = `发现新版本!\n当前: v${data.version}\n最新: v${data.latest_version}\n\n更新内容: ${data.latest_message || '无'}`;
+ // Update available
+ const updateMsg = `New version found!\nCurrent: v${data.version}\nLatest: v${data.latest_version}\n\nUpdate content: ${data.latest_message || 'None'}`;
showStatus(updateMsg.replace(/\n/g, ' '), 'warning');
- // 更新按钮样式
+ // Update button style
checkBtn.style.backgroundColor = '#ffc107';
- checkBtn.textContent = '有新版本';
+ checkBtn.textContent = 'New version available';
setTimeout(() => {
checkBtn.style.backgroundColor = '#17a2b8';
checkBtn.textContent = originalText;
}, 5000);
} else if (data.has_update === false) {
- // 已是最新
- showStatus('已是最新版本!', 'success');
+ // Already latest
+ showStatus('Already the latest version!', 'success');
checkBtn.style.backgroundColor = '#28a745';
- checkBtn.textContent = '已是最新';
+ checkBtn.textContent = 'Already latest';
setTimeout(() => {
checkBtn.style.backgroundColor = '#17a2b8';
checkBtn.textContent = originalText;
}, 3000);
} else {
- // 无法确定
- showStatus('无法确定是否有更新', 'info');
+ // Unable to determine
+ showStatus('Unable to determine if there is an update', 'info');
}
} else {
- showStatus(`检查更新失败: ${data.error}`, 'error');
+ showStatus(`Failed to check for updates: ${data.error}`, 'error');
}
} catch (error) {
- console.error('检查更新失败:', error);
- showStatus(`检查更新失败: ${error.message}`, 'error');
+ console.error('Failed to check for updates:', error);
+ showStatus(`Failed to check for updates: ${error.message}`, 'error');
} finally {
checkBtn.disabled = false;
- if (checkBtn.textContent === '检查中...') {
+ if (checkBtn.textContent === 'Checking...') {
checkBtn.textContent = originalText;
}
}
}
// =====================================================================
-// 页面初始化
+// Page initialization
// =====================================================================
window.onload = async function () {
const autoLoginSuccess = await autoLogin();
if (!autoLoginSuccess) {
- showStatus('请输入密码登录', 'info');
+ showStatus('Please enter password to log in', 'info');
} else {
- // 登录成功后获取版本信息
+ // Get version info after successful login
await fetchAndDisplayVersion();
}
@@ -3196,7 +2648,7 @@ window.onload = async function () {
}
};
-// 拖拽功能 - 初始化
+// Drag and drop functionality - Initialization
document.addEventListener('DOMContentLoaded', function () {
const uploadArea = document.getElementById('uploadArea');
@@ -3218,8 +2670,3 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
});
-
-function autoSetKeepaliveUrl() {
- const url = `${window.location.protocol}//${window.location.host}`;
- document.getElementById('keepaliveUrl').value = url;
-}
diff --git a/front/control_panel.html b/front/control_panel.html
index 237826a24..e88a1e242 100644
--- a/front/control_panel.html
+++ b/front/control_panel.html
@@ -4,7 +4,7 @@