mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-09 09:56:37 +08:00
Merge remote-tracking branch 'origin/main' into feat/AutoRoute
This commit is contained in:
@@ -45,7 +45,7 @@ class GenerationConfig(BaseModel):
|
|||||||
|
|
||||||
class SystemInstruction(BaseModel):
|
class SystemInstruction(BaseModel):
|
||||||
role: str = "system"
|
role: str = "system"
|
||||||
parts: List[Dict[str, Any]] | Dict[str, Any]
|
parts: Union[List[Dict[str, Any]], Dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
class GeminiContent(BaseModel):
|
class GeminiContent(BaseModel):
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class ImageMetadata:
|
class ImageMetadata:
|
||||||
def __init__(self, width: int, height: int, filename: str, size: int, url: str, delete_url: str | None = None):
|
def __init__(self, width: int, height: int, filename: str, size: int, url: str, delete_url: Union[str, None] = None):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.size = size
|
self.size = size
|
||||||
self.url = url
|
self.url = url
|
||||||
self.delete_url = delete_url
|
self.delete_url = delete_url
|
||||||
|
|
||||||
|
|
||||||
class UploadResponse:
|
class UploadResponse:
|
||||||
def __init__(self, success: bool, code: str, message: str, data: ImageMetadata):
|
def __init__(self, success: bool, code: str, message: str, data: ImageMetadata):
|
||||||
self.success = success
|
self.success = success
|
||||||
self.code = code
|
self.code = code
|
||||||
self.message = message
|
self.message = message
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
|
||||||
class ImageUploader:
|
class ImageUploader:
|
||||||
def upload(self, file: bytes, filename: str) -> UploadResponse:
|
def upload(self, file: bytes, filename: str) -> UploadResponse:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
from typing import Dict
|
from typing import Dict, Union
|
||||||
|
|
||||||
from app.config.config import settings
|
from app.config.config import settings
|
||||||
from app.log.logger import get_key_manager_logger
|
from app.log.logger import get_key_manager_logger
|
||||||
@@ -178,19 +178,20 @@ class KeyManager:
|
|||||||
if self.api_keys:
|
if self.api_keys:
|
||||||
return self.api_keys[0]
|
return self.api_keys[0]
|
||||||
if not self.api_keys:
|
if not self.api_keys:
|
||||||
logger.warning("API key list is empty, cannot get first valid key.")
|
logger.warning(
|
||||||
|
"API key list is empty, cannot get first valid key.")
|
||||||
return ""
|
return ""
|
||||||
return self.api_keys[0]
|
return self.api_keys[0]
|
||||||
|
|
||||||
|
|
||||||
_singleton_instance = None
|
_singleton_instance = None
|
||||||
_singleton_lock = asyncio.Lock()
|
_singleton_lock = asyncio.Lock()
|
||||||
_preserved_failure_counts: Dict[str, int] | None = None
|
_preserved_failure_counts: Union[Dict[str, int], None] = None
|
||||||
_preserved_vertex_failure_counts: Dict[str, int] | None = None
|
_preserved_vertex_failure_counts: Union[Dict[str, int], None] = None
|
||||||
_preserved_old_api_keys_for_reset: list | None = None
|
_preserved_old_api_keys_for_reset: Union[list, None] = None
|
||||||
_preserved_vertex_old_api_keys_for_reset: list | None = None
|
_preserved_vertex_old_api_keys_for_reset: Union[list, None] = None
|
||||||
_preserved_next_key_in_cycle: str | None = None
|
_preserved_next_key_in_cycle: Union[str, None] = None
|
||||||
_preserved_vertex_next_key_in_cycle: str | None = None
|
_preserved_vertex_next_key_in_cycle: Union[str, None] = None
|
||||||
|
|
||||||
|
|
||||||
async def get_key_manager_instance(
|
async def get_key_manager_instance(
|
||||||
@@ -252,7 +253,8 @@ async def get_key_manager_instance(
|
|||||||
_singleton_instance.vertex_key_failure_counts = (
|
_singleton_instance.vertex_key_failure_counts = (
|
||||||
current_vertex_failure_counts
|
current_vertex_failure_counts
|
||||||
)
|
)
|
||||||
logger.info("Inherited failure counts for applicable Vertex keys.")
|
logger.info(
|
||||||
|
"Inherited failure counts for applicable Vertex keys.")
|
||||||
_preserved_vertex_failure_counts = None
|
_preserved_vertex_failure_counts = None
|
||||||
|
|
||||||
# 2. 调整 key_cycle 的起始点
|
# 2. 调整 key_cycle 的起始点
|
||||||
@@ -357,7 +359,7 @@ async def get_key_manager_instance(
|
|||||||
f"Error determining start key for new Vertex key cycle from preserved state: {e}. "
|
f"Error determining start key for new Vertex key cycle from preserved state: {e}. "
|
||||||
"New cycle will start from the beginning."
|
"New cycle will start from the beginning."
|
||||||
)
|
)
|
||||||
|
|
||||||
if start_key_for_new_vertex_cycle and _singleton_instance.vertex_api_keys:
|
if start_key_for_new_vertex_cycle and _singleton_instance.vertex_api_keys:
|
||||||
try:
|
try:
|
||||||
target_idx = _singleton_instance.vertex_api_keys.index(
|
target_idx = _singleton_instance.vertex_api_keys.index(
|
||||||
@@ -380,7 +382,7 @@ async def get_key_manager_instance(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"Error advancing new Vertex key cycle: {e}. Cycle will start from beginning."
|
f"Error advancing new Vertex key cycle: {e}. Cycle will start from beginning."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if _singleton_instance.vertex_api_keys:
|
if _singleton_instance.vertex_api_keys:
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -418,7 +420,7 @@ async def reset_key_manager_instance():
|
|||||||
# 3. 保存 key_cycle 的下一个 key 提示
|
# 3. 保存 key_cycle 的下一个 key 提示
|
||||||
try:
|
try:
|
||||||
if _singleton_instance.api_keys:
|
if _singleton_instance.api_keys:
|
||||||
_preserved_next_key_in_cycle = (
|
_preserved_next_key_in_cycle = (
|
||||||
await _singleton_instance.get_next_key()
|
await _singleton_instance.get_next_key()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -427,9 +429,10 @@ async def reset_key_manager_instance():
|
|||||||
logger.warning(
|
logger.warning(
|
||||||
"Could not preserve next key hint: key cycle was empty or exhausted in old instance."
|
"Could not preserve next key hint: key cycle was empty or exhausted in old instance."
|
||||||
)
|
)
|
||||||
_preserved_next_key_in_cycle = None
|
_preserved_next_key_in_cycle = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error preserving next key hint during reset: {e}")
|
logger.error(
|
||||||
|
f"Error preserving next key hint during reset: {e}")
|
||||||
_preserved_next_key_in_cycle = None
|
_preserved_next_key_in_cycle = None
|
||||||
|
|
||||||
# 4. 保存 vertex_key_cycle 的下一个 key 提示
|
# 4. 保存 vertex_key_cycle 的下一个 key 提示
|
||||||
@@ -443,12 +446,12 @@ async def reset_key_manager_instance():
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Could not preserve next key hint: Vertex key cycle was empty or exhausted in old instance."
|
"Could not preserve next key hint: Vertex key cycle was empty or exhausted in old instance."
|
||||||
)
|
)
|
||||||
_preserved_vertex_next_key_in_cycle = None
|
_preserved_vertex_next_key_in_cycle = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error preserving next key hint during reset: {e}")
|
logger.error(
|
||||||
|
f"Error preserving next key hint during reset: {e}")
|
||||||
_preserved_vertex_next_key_in_cycle = None
|
_preserved_vertex_next_key_in_cycle = None
|
||||||
|
|
||||||
|
|
||||||
_singleton_instance = None
|
_singleton_instance = None
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# app/service/stats_service.py
|
# app/service/stats_service.py
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from sqlalchemy import and_, case, func, or_, select
|
from sqlalchemy import and_, case, func, or_, select
|
||||||
|
|
||||||
@@ -195,10 +196,11 @@ class StatsService:
|
|||||||
return details
|
return details
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get API call details for period '{period}': {e}")
|
logger.error(
|
||||||
|
f"Failed to get API call details for period '{period}': {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def get_key_usage_details_last_24h(self, key: str) -> dict | None:
|
async def get_key_usage_details_last_24h(self, key: str) -> Union[dict, None]:
|
||||||
"""
|
"""
|
||||||
获取指定 API 密钥在过去 24 小时内按模型统计的调用次数。
|
获取指定 API 密钥在过去 24 小时内按模型统计的调用次数。
|
||||||
|
|
||||||
@@ -218,7 +220,8 @@ class StatsService:
|
|||||||
try:
|
try:
|
||||||
query = (
|
query = (
|
||||||
select(
|
select(
|
||||||
RequestLog.model_name, func.count(RequestLog.id).label("call_count")
|
RequestLog.model_name, func.count(
|
||||||
|
RequestLog.id).label("call_count")
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
RequestLog.api_key == key,
|
RequestLog.api_key == key,
|
||||||
@@ -237,7 +240,8 @@ class StatsService:
|
|||||||
)
|
)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
usage_details = {row["model_name"]: row["call_count"] for row in results}
|
usage_details = {row["model_name"]: row["call_count"]
|
||||||
|
for row in results}
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Successfully fetched usage details for key ending in ...{key[-4:]}: {usage_details}"
|
f"Successfully fetched usage details for key ending in ...{key[-4:]}: {usage_details}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const PROXY_REGEX =
|
|||||||
/(?:https?|socks5):\/\/(?:[^:@\/]+(?::[^@\/]+)?@)?(?:[^:\/\s]+)(?::\d+)?/g;
|
/(?:https?|socks5):\/\/(?:[^:@\/]+(?::[^@\/]+)?@)?(?:[^:\/\s]+)(?::\d+)?/g;
|
||||||
const VERTEX_API_KEY_REGEX = /AQ\.[a-zA-Z0-9_]{50}/g; // 新增 Vertex API Key 正则
|
const VERTEX_API_KEY_REGEX = /AQ\.[a-zA-Z0-9_]{50}/g; // 新增 Vertex API Key 正则
|
||||||
const MASKED_VALUE = "••••••••";
|
const MASKED_VALUE = "••••••••";
|
||||||
|
|
||||||
// DOM Elements - Global Scope for frequently accessed elements
|
// DOM Elements - Global Scope for frequently accessed elements
|
||||||
const safetySettingsContainer = document.getElementById(
|
const safetySettingsContainer = document.getElementById(
|
||||||
"SAFETY_SETTINGS_container"
|
"SAFETY_SETTINGS_container"
|
||||||
@@ -31,7 +31,7 @@ const bulkDeleteProxyModal = document.getElementById("bulkDeleteProxyModal");
|
|||||||
const bulkDeleteProxyInput = document.getElementById("bulkDeleteProxyInput");
|
const bulkDeleteProxyInput = document.getElementById("bulkDeleteProxyInput");
|
||||||
const resetConfirmModal = document.getElementById("resetConfirmModal");
|
const resetConfirmModal = document.getElementById("resetConfirmModal");
|
||||||
const configForm = document.getElementById("configForm"); // Added for frequent use
|
const configForm = document.getElementById("configForm"); // Added for frequent use
|
||||||
|
|
||||||
// Vertex API Key Modal Elements
|
// Vertex API Key Modal Elements
|
||||||
const vertexApiKeyModal = document.getElementById("vertexApiKeyModal");
|
const vertexApiKeyModal = document.getElementById("vertexApiKeyModal");
|
||||||
const vertexApiKeyBulkInput = document.getElementById("vertexApiKeyBulkInput");
|
const vertexApiKeyBulkInput = document.getElementById("vertexApiKeyBulkInput");
|
||||||
@@ -41,7 +41,7 @@ const bulkDeleteVertexApiKeyModal = document.getElementById(
|
|||||||
const bulkDeleteVertexApiKeyInput = document.getElementById(
|
const bulkDeleteVertexApiKeyInput = document.getElementById(
|
||||||
"bulkDeleteVertexApiKeyInput"
|
"bulkDeleteVertexApiKeyInput"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Model Helper Modal Elements
|
// Model Helper Modal Elements
|
||||||
const modelHelperModal = document.getElementById("modelHelperModal");
|
const modelHelperModal = document.getElementById("modelHelperModal");
|
||||||
const modelHelperTitleElement = document.getElementById("modelHelperTitle");
|
const modelHelperTitleElement = document.getElementById("modelHelperTitle");
|
||||||
@@ -384,7 +384,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initializeSensitiveFields(); // Initialize sensitive field handling
|
initializeSensitiveFields(); // Initialize sensitive field handling
|
||||||
|
|
||||||
// Vertex API Key Modal Elements and Events
|
// Vertex API Key Modal Elements and Events
|
||||||
const addVertexApiKeyBtn = document.getElementById("addVertexApiKeyBtn");
|
const addVertexApiKeyBtn = document.getElementById("addVertexApiKeyBtn");
|
||||||
const closeVertexApiKeyModalBtn = document.getElementById(
|
const closeVertexApiKeyModalBtn = document.getElementById(
|
||||||
@@ -408,7 +408,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const confirmBulkDeleteVertexApiKeyBtn = document.getElementById(
|
const confirmBulkDeleteVertexApiKeyBtn = document.getElementById(
|
||||||
"confirmBulkDeleteVertexApiKeyBtn"
|
"confirmBulkDeleteVertexApiKeyBtn"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (addVertexApiKeyBtn) {
|
if (addVertexApiKeyBtn) {
|
||||||
addVertexApiKeyBtn.addEventListener("click", () => {
|
addVertexApiKeyBtn.addEventListener("click", () => {
|
||||||
openModal(vertexApiKeyModal);
|
openModal(vertexApiKeyModal);
|
||||||
@@ -428,7 +428,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
"click",
|
"click",
|
||||||
handleBulkAddVertexApiKeys
|
handleBulkAddVertexApiKeys
|
||||||
);
|
);
|
||||||
|
|
||||||
if (bulkDeleteVertexApiKeyBtn) {
|
if (bulkDeleteVertexApiKeyBtn) {
|
||||||
bulkDeleteVertexApiKeyBtn.addEventListener("click", () => {
|
bulkDeleteVertexApiKeyBtn.addEventListener("click", () => {
|
||||||
openModal(bulkDeleteVertexApiKeyModal);
|
openModal(bulkDeleteVertexApiKeyModal);
|
||||||
@@ -448,7 +448,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
"click",
|
"click",
|
||||||
handleBulkDeleteVertexApiKeys
|
handleBulkDeleteVertexApiKeys
|
||||||
);
|
);
|
||||||
|
|
||||||
// Model Helper Modal Event Listeners
|
// Model Helper Modal Event Listeners
|
||||||
if (closeModelHelperModalBtn) {
|
if (closeModelHelperModalBtn) {
|
||||||
closeModelHelperModalBtn.addEventListener("click", () =>
|
closeModelHelperModalBtn.addEventListener("click", () =>
|
||||||
@@ -765,7 +765,7 @@ async function initConfig() {
|
|||||||
FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS: 5,
|
FAKE_STREAM_EMPTY_DATA_INTERVAL_SECONDS: 5,
|
||||||
// --- 结束:处理假流式配置的默认值 ---
|
// --- 结束:处理假流式配置的默认值 ---
|
||||||
};
|
};
|
||||||
|
|
||||||
populateForm(defaultConfig);
|
populateForm(defaultConfig);
|
||||||
if (configForm) {
|
if (configForm) {
|
||||||
// Ensure form exists
|
// Ensure form exists
|
||||||
@@ -1177,7 +1177,7 @@ function handleBulkDeleteProxies() {
|
|||||||
}
|
}
|
||||||
bulkDeleteProxyInput.value = "";
|
bulkDeleteProxyInput.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the bulk addition of Vertex API keys from the modal input.
|
* Handles the bulk addition of Vertex API keys from the modal input.
|
||||||
*/
|
*/
|
||||||
@@ -1192,10 +1192,10 @@ function handleBulkAddVertexApiKeys() {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bulkText = vertexApiKeyBulkInput.value;
|
const bulkText = vertexApiKeyBulkInput.value;
|
||||||
const extractedKeys = bulkText.match(VERTEX_API_KEY_REGEX) || [];
|
const extractedKeys = bulkText.match(VERTEX_API_KEY_REGEX) || [];
|
||||||
|
|
||||||
const currentKeyInputs = vertexApiKeyContainer.querySelectorAll(
|
const currentKeyInputs = vertexApiKeyContainer.querySelectorAll(
|
||||||
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
||||||
);
|
);
|
||||||
@@ -1206,16 +1206,16 @@ function handleBulkAddVertexApiKeys() {
|
|||||||
: input.value;
|
: input.value;
|
||||||
})
|
})
|
||||||
.filter((key) => key && key.trim() !== "" && key !== MASKED_VALUE);
|
.filter((key) => key && key.trim() !== "" && key !== MASKED_VALUE);
|
||||||
|
|
||||||
const combinedKeys = new Set([...currentKeys, ...extractedKeys]);
|
const combinedKeys = new Set([...currentKeys, ...extractedKeys]);
|
||||||
const uniqueKeys = Array.from(combinedKeys);
|
const uniqueKeys = Array.from(combinedKeys);
|
||||||
|
|
||||||
vertexApiKeyContainer.innerHTML = ""; // Clear existing items
|
vertexApiKeyContainer.innerHTML = ""; // Clear existing items
|
||||||
|
|
||||||
uniqueKeys.forEach((key) => {
|
uniqueKeys.forEach((key) => {
|
||||||
addArrayItemWithValue("VERTEX_API_KEYS", key); // VERTEX_API_KEYS are sensitive
|
addArrayItemWithValue("VERTEX_API_KEYS", key); // VERTEX_API_KEYS are sensitive
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ensure new sensitive inputs are masked
|
// Ensure new sensitive inputs are masked
|
||||||
const newKeyInputs = vertexApiKeyContainer.querySelectorAll(
|
const newKeyInputs = vertexApiKeyContainer.querySelectorAll(
|
||||||
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
||||||
@@ -1229,7 +1229,7 @@ function handleBulkAddVertexApiKeys() {
|
|||||||
input.dispatchEvent(focusoutEvent);
|
input.dispatchEvent(focusoutEvent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
closeModal(vertexApiKeyModal);
|
closeModal(vertexApiKeyModal);
|
||||||
showNotification(
|
showNotification(
|
||||||
`添加/更新了 ${uniqueKeys.length} 个唯一 Vertex 密钥`,
|
`添加/更新了 ${uniqueKeys.length} 个唯一 Vertex 密钥`,
|
||||||
@@ -1237,7 +1237,7 @@ function handleBulkAddVertexApiKeys() {
|
|||||||
);
|
);
|
||||||
vertexApiKeyBulkInput.value = "";
|
vertexApiKeyBulkInput.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the bulk deletion of Vertex API keys based on input from the modal.
|
* Handles the bulk deletion of Vertex API keys based on input from the modal.
|
||||||
*/
|
*/
|
||||||
@@ -1252,15 +1252,15 @@ function handleBulkDeleteVertexApiKeys() {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bulkText = bulkDeleteVertexApiKeyInput.value;
|
const bulkText = bulkDeleteVertexApiKeyInput.value;
|
||||||
if (!bulkText.trim()) {
|
if (!bulkText.trim()) {
|
||||||
showNotification("请粘贴需要删除的 Vertex API 密钥", "warning");
|
showNotification("请粘贴需要删除的 Vertex API 密钥", "warning");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keysToDelete = new Set(bulkText.match(VERTEX_API_KEY_REGEX) || []);
|
const keysToDelete = new Set(bulkText.match(VERTEX_API_KEY_REGEX) || []);
|
||||||
|
|
||||||
if (keysToDelete.size === 0) {
|
if (keysToDelete.size === 0) {
|
||||||
showNotification(
|
showNotification(
|
||||||
"未在输入内容中提取到有效的 Vertex API 密钥格式",
|
"未在输入内容中提取到有效的 Vertex API 密钥格式",
|
||||||
@@ -1268,10 +1268,10 @@ function handleBulkDeleteVertexApiKeys() {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyItems = vertexApiKeyContainer.querySelectorAll(`.${ARRAY_ITEM_CLASS}`);
|
const keyItems = vertexApiKeyContainer.querySelectorAll(`.${ARRAY_ITEM_CLASS}`);
|
||||||
let deleteCount = 0;
|
let deleteCount = 0;
|
||||||
|
|
||||||
keyItems.forEach((item) => {
|
keyItems.forEach((item) => {
|
||||||
const input = item.querySelector(
|
const input = item.querySelector(
|
||||||
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
`.${ARRAY_INPUT_CLASS}.${SENSITIVE_INPUT_CLASS}`
|
||||||
@@ -1286,9 +1286,9 @@ function handleBulkDeleteVertexApiKeys() {
|
|||||||
deleteCount++;
|
deleteCount++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
closeModal(bulkDeleteVertexApiKeyModal);
|
closeModal(bulkDeleteVertexApiKeyModal);
|
||||||
|
|
||||||
if (deleteCount > 0) {
|
if (deleteCount > 0) {
|
||||||
showNotification(`成功删除了 ${deleteCount} 个匹配的 Vertex 密钥`, "success");
|
showNotification(`成功删除了 ${deleteCount} 个匹配的 Vertex 密钥`, "success");
|
||||||
} else {
|
} else {
|
||||||
@@ -1296,7 +1296,7 @@ function handleBulkDeleteVertexApiKeys() {
|
|||||||
}
|
}
|
||||||
bulkDeleteVertexApiKeyInput.value = "";
|
bulkDeleteVertexApiKeyInput.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches the active configuration tab.
|
* Switches the active configuration tab.
|
||||||
* @param {string} tabId - The ID of the tab to switch to.
|
* @param {string} tabId - The ID of the tab to switch to.
|
||||||
@@ -1442,7 +1442,7 @@ function addArrayItemWithValue(key, value) {
|
|||||||
const isSensitive =
|
const isSensitive =
|
||||||
key === "API_KEYS" || isAllowedToken || isVertexApiKey; // 更新敏感判断
|
key === "API_KEYS" || isAllowedToken || isVertexApiKey; // 更新敏感判断
|
||||||
const modelId = isThinkingModel ? generateUUID() : null;
|
const modelId = isThinkingModel ? generateUUID() : null;
|
||||||
|
|
||||||
const arrayItem = document.createElement("div");
|
const arrayItem = document.createElement("div");
|
||||||
arrayItem.className = `${ARRAY_ITEM_CLASS} flex items-center mb-2 gap-2`;
|
arrayItem.className = `${ARRAY_ITEM_CLASS} flex items-center mb-2 gap-2`;
|
||||||
if (isThinkingModel) {
|
if (isThinkingModel) {
|
||||||
@@ -1535,14 +1535,14 @@ function createAndAppendBudgetMapItem(mapKey, mapValue, modelId) {
|
|||||||
valueInput.value = isNaN(intValue) ? 0 : intValue;
|
valueInput.value = isNaN(intValue) ? 0 : intValue;
|
||||||
valueInput.placeholder = "预算 (整数)";
|
valueInput.placeholder = "预算 (整数)";
|
||||||
valueInput.className = `${MAP_VALUE_INPUT_CLASS} w-24 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50`;
|
valueInput.className = `${MAP_VALUE_INPUT_CLASS} w-24 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50`;
|
||||||
valueInput.min = 0;
|
valueInput.min = -1;
|
||||||
valueInput.max = 24576;
|
valueInput.max = 32767;
|
||||||
valueInput.addEventListener("input", function () {
|
valueInput.addEventListener("input", function () {
|
||||||
let val = this.value.replace(/[^0-9]/g, "");
|
let val = this.value.replace(/[^0-9-]/g, "");
|
||||||
if (val !== "") {
|
if (val !== "") {
|
||||||
val = parseInt(val, 10);
|
val = parseInt(val, 10);
|
||||||
if (val < 0) val = 0;
|
if (val < -1) val = -1;
|
||||||
if (val > 24576) val = 24576;
|
if (val > 32767) val = 32767;
|
||||||
}
|
}
|
||||||
this.value = val; // Corrected variable name
|
this.value = val; // Corrected variable name
|
||||||
});
|
});
|
||||||
|
|||||||
+2295
-2296
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user