From 35ceab0dae7ac95d112ebf5716078e3d434b387f Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Sun, 9 Nov 2025 17:51:38 +0800 Subject: [PATCH] feat(app.js, i18n): enhance Gemini API key management with base URL support - Updated the CLIProxyManager to handle both API keys and optional base URLs for Gemini. - Added new input fields in the modal for base URL entry during key addition and editing. - Updated internationalization strings to include labels and placeholders for the base URL in both English and Chinese. - Improved key normalization and rendering logic to accommodate the new structure. --- app.js | 85 +++++++++++++++++++++++++++++++++++++++++++-------------- i18n.js | 6 ++++ 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/app.js b/app.js index 10bcb78..4026252 100644 --- a/app.js +++ b/app.js @@ -2442,7 +2442,11 @@ class CLIProxyManager { async loadGeminiKeys() { try { const config = await this.getConfig(); - const keys = Array.isArray(config['generative-language-api-key']) ? config['generative-language-api-key'] : []; + let keys = Array.isArray(config['gemini-api-key']) ? config['gemini-api-key'] : []; + if (keys.length === 0) { + const legacyKeys = Array.isArray(config['generative-language-api-key']) ? config['generative-language-api-key'] : []; + keys = legacyKeys.map(key => ({ 'api-key': key })); + } await this.renderGeminiKeys(keys); } catch (error) { console.error('加载Gemini密钥失败:', error); @@ -2455,9 +2459,18 @@ class CLIProxyManager { if (!container) { return; } - const list = Array.isArray(keys) ? keys : []; + const normalizedList = (Array.isArray(keys) ? keys : []).map(item => { + if (item && typeof item === 'object') { + return { ...item }; + } + if (typeof item === 'string') { + return { 'api-key': item }; + } + return null; + }).filter(config => config && config['api-key']); + this.cachedGeminiKeys = normalizedList; - if (list.length === 0) { + if (normalizedList.length === 0) { container.innerHTML = `
@@ -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 {
+
+ + +