@@ -2471,14 +2484,18 @@ class CLIProxyManager {
// 获取使用统计,按 source 聚合
const stats = await this.getKeyStats();
- container.innerHTML = list.map((key, index) => {
- const masked = this.maskApiKey(key);
- const keyStats = stats[key] || stats[masked] || { success: 0, failure: 0 };
+ container.innerHTML = normalizedList.map((config, index) => {
+ const rawKey = config['api-key'] || '';
+ const masked = rawKey ? this.maskApiKey(rawKey) : '';
+ const keyStats = (rawKey && (stats[rawKey] || stats[masked])) || { success: 0, failure: 0 };
+ const configJson = JSON.stringify(config).replace(/"/g, '"');
+ const apiKeyJson = JSON.stringify(rawKey || '').replace(/"/g, '"');
return `
${i18n.t('ai_providers.gemini_item_title')} #${index + 1}
-
${this.maskApiKey(key)}
+
${this.maskApiKey(rawKey || '')}
+ ${config['base-url'] ? `
${i18n.t('common.base_url')}: ${this.escapeHtml(config['base-url'])}
` : ''}
${i18n.t('stats.success')}: ${keyStats.success}
@@ -2489,10 +2506,10 @@ class CLIProxyManager {
-
@@ -2511,6 +2528,10 @@ class CLIProxyManager {
${i18n.t('common.cancel')}
${i18n.t('common.add')}
@@ -2523,6 +2544,8 @@ class CLIProxyManager {
// 添加Gemini密钥
async addGeminiKey() {
const newKey = document.getElementById('new-gemini-key').value.trim();
+ const baseUrlInput = document.getElementById('new-gemini-url');
+ const baseUrl = baseUrlInput ? baseUrlInput.value.trim() : '';
if (!newKey) {
this.showNotification(i18n.t('notification.please_enter') + ' ' + i18n.t('notification.gemini_api_key'), 'error');
@@ -2530,11 +2553,15 @@ class CLIProxyManager {
}
try {
- const data = await this.makeRequest('/generative-language-api-key');
- const currentKeys = data['generative-language-api-key'] || [];
- currentKeys.push(newKey);
+ const data = await this.makeRequest('/gemini-api-key');
+ const currentKeys = data['gemini-api-key'] || [];
+ const newConfig = { 'api-key': newKey };
+ if (baseUrl) {
+ newConfig['base-url'] = baseUrl;
+ }
+ currentKeys.push(newConfig);
- await this.makeRequest('/generative-language-api-key', {
+ await this.makeRequest('/gemini-api-key', {
method: 'PUT',
body: JSON.stringify(currentKeys)
});
@@ -2549,19 +2576,24 @@ class CLIProxyManager {
}
// 编辑Gemini密钥
- editGeminiKey(index, currentKey) {
+ editGeminiKey(index, config) {
const modal = document.getElementById('modal');
const modalBody = document.getElementById('modal-body');
+ this.currentGeminiEditConfig = config || {};
modalBody.innerHTML = `
${i18n.t('ai_providers.gemini_edit_modal_title')}
-
+
+
+
+
+
${i18n.t('common.cancel')}
- ${i18n.t('common.update')}
+ ${i18n.t('common.update')}
`;
@@ -2569,8 +2601,10 @@ class CLIProxyManager {
}
// 更新Gemini密钥
- async updateGeminiKey(oldKey) {
+ async updateGeminiKey(index) {
const newKey = document.getElementById('edit-gemini-key').value.trim();
+ const baseUrlInput = document.getElementById('edit-gemini-url');
+ const baseUrl = baseUrlInput ? baseUrlInput.value.trim() : '';
if (!newKey) {
this.showNotification(i18n.t('notification.please_enter') + ' ' + i18n.t('notification.gemini_api_key'), 'error');
@@ -2578,14 +2612,23 @@ class CLIProxyManager {
}
try {
- await this.makeRequest('/generative-language-api-key', {
+ const existingConfig = (this.cachedGeminiKeys && this.cachedGeminiKeys[index]) || this.currentGeminiEditConfig || {};
+ const newConfig = { ...existingConfig, 'api-key': newKey };
+ if (baseUrl) {
+ newConfig['base-url'] = baseUrl;
+ } else {
+ delete newConfig['base-url'];
+ }
+
+ await this.makeRequest('/gemini-api-key', {
method: 'PATCH',
- body: JSON.stringify({ old: oldKey, new: newKey })
+ body: JSON.stringify({ index, value: newConfig })
});
this.clearCache(); // 清除缓存
this.closeModal();
this.loadGeminiKeys();
+ this.currentGeminiEditConfig = null;
this.showNotification(i18n.t('notification.gemini_key_updated'), 'success');
} catch (error) {
this.showNotification(`${i18n.t('notification.update_failed')}: ${error.message}`, 'error');
@@ -2593,11 +2636,11 @@ class CLIProxyManager {
}
// 删除Gemini密钥
- async deleteGeminiKey(key) {
+ async deleteGeminiKey(apiKey) {
if (!confirm(i18n.t('ai_providers.gemini_delete_confirm'))) return;
try {
- await this.makeRequest(`/generative-language-api-key?value=${encodeURIComponent(key)}`, { method: 'DELETE' });
+ await this.makeRequest(`/gemini-api-key?api-key=${encodeURIComponent(apiKey)}`, { method: 'DELETE' });
this.clearCache(); // 清除缓存
this.loadGeminiKeys();
this.showNotification(i18n.t('notification.gemini_key_deleted'), 'success');
diff --git a/i18n.js b/i18n.js
index 99f9b78..5716a32 100644
--- a/i18n.js
+++ b/i18n.js
@@ -133,8 +133,11 @@ const i18n = {
'ai_providers.gemini_add_modal_title': '添加Gemini API密钥',
'ai_providers.gemini_add_modal_key_label': 'API密钥:',
'ai_providers.gemini_add_modal_key_placeholder': '请输入Gemini API密钥',
+ 'ai_providers.gemini_add_modal_url_label': 'Base URL (可选):',
+ 'ai_providers.gemini_add_modal_url_placeholder': '例如: https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥',
'ai_providers.gemini_edit_modal_key_label': 'API密钥:',
+ 'ai_providers.gemini_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗?',
'ai_providers.codex_title': 'Codex API 配置',
@@ -579,8 +582,11 @@ const i18n = {
'ai_providers.gemini_add_modal_title': 'Add Gemini API Key',
'ai_providers.gemini_add_modal_key_label': 'API Key:',
'ai_providers.gemini_add_modal_key_placeholder': 'Please enter Gemini API key',
+ 'ai_providers.gemini_add_modal_url_label': 'Base URL (optional):',
+ 'ai_providers.gemini_add_modal_url_placeholder': 'e.g. https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key',
'ai_providers.gemini_edit_modal_key_label': 'API Key:',
+ 'ai_providers.gemini_edit_modal_url_label': 'Base URL (optional):',
'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?',
'ai_providers.codex_title': 'Codex API Configuration',