Download apps/enterprise_data/services/clients/api_key_pool.py from jun2024/fc: direct link, hf CLI and curl.
- Browser
- Download file 3.41 kB
-
https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/enterprise_data/services/clients/api_key_pool.py
- Command line
-
hf download hf://spaces/jun2024/fc/apps/enterprise_data/services/clients/api_key_pool.py
-
curl -L -o api_key_pool.py https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/enterprise_data/services/clients/api_key_pool.py
3.41 kB
| """API Key 池管理。""" | |
| from __future__ import annotations | |
| import hashlib | |
| from collections.abc import Iterable | |
| from django.core.cache import cache | |
| _PREFERRED_KEY_CACHE_TTL_SECONDS = 30 * 24 * 60 * 60 | |
| _AUTH_BLOCK_TTL_SECONDS = 60 * 60 | |
| _RATE_LIMIT_BLOCK_TTL_SECONDS = 2 * 60 | |
| class McpApiKeyPool: | |
| """为同一 provider 管理多个 API Key 的优先级与短期熔断。""" | |
| def __init__(self, *, provider_name: str, api_keys: Iterable[str]) -> None: | |
| self._provider_name = str(provider_name or "").strip().lower() | |
| self._api_keys = self._normalize_api_keys(api_keys) | |
| def size(self) -> int: | |
| return len(self._api_keys) | |
| def ordered_keys(self) -> list[str]: | |
| if len(self._api_keys) <= 1: | |
| return list(self._api_keys) | |
| preferred = str(cache.get(self._preferred_cache_key()) or "").strip() | |
| available = [key for key in self._api_keys if not self._is_blocked(key)] | |
| blocked = [key for key in self._api_keys if self._is_blocked(key)] | |
| ordered_available = self._order_with_preferred(available, preferred) | |
| ordered_blocked = self._order_with_preferred(blocked, preferred) | |
| return ordered_available + ordered_blocked | |
| def mark_success(self, api_key: str) -> None: | |
| fingerprint = self.fingerprint(api_key) | |
| if not fingerprint: | |
| return | |
| cache.set(self._preferred_cache_key(), fingerprint, timeout=_PREFERRED_KEY_CACHE_TTL_SECONDS) | |
| cache.delete(self._block_cache_key(api_key)) | |
| def mark_auth_failed(self, api_key: str) -> None: | |
| self._block(api_key, ttl_seconds=_AUTH_BLOCK_TTL_SECONDS) | |
| def mark_rate_limited(self, api_key: str) -> None: | |
| self._block(api_key, ttl_seconds=_RATE_LIMIT_BLOCK_TTL_SECONDS) | |
| def fingerprint(self, api_key: str) -> str: | |
| normalized = str(api_key or "").strip() | |
| if not normalized: | |
| return "" | |
| digest = hashlib.sha256(normalized.encode("utf-8")).hexdigest() | |
| return digest[:16] | |
| def _normalize_api_keys(api_keys: Iterable[str]) -> tuple[str, ...]: | |
| normalized: list[str] = [] | |
| seen: set[str] = set() | |
| for item in api_keys: | |
| value = str(item or "").strip() | |
| if not value or value in seen: | |
| continue | |
| normalized.append(value) | |
| seen.add(value) | |
| return tuple(normalized) | |
| def _block(self, api_key: str, *, ttl_seconds: int) -> None: | |
| if ttl_seconds <= 0: | |
| return | |
| cache.set(self._block_cache_key(api_key), True, timeout=ttl_seconds) | |
| def _is_blocked(self, api_key: str) -> bool: | |
| return bool(cache.get(self._block_cache_key(api_key))) | |
| def _preferred_cache_key(self) -> str: | |
| return f"enterprise_data:api_key_pool:{self._provider_name}:preferred" | |
| def _block_cache_key(self, api_key: str) -> str: | |
| return f"enterprise_data:api_key_pool:{self._provider_name}:blocked:{self.fingerprint(api_key)}" | |
| def _order_with_preferred(self, keys: list[str], preferred_fingerprint: str) -> list[str]: | |
| if len(keys) <= 1 or not preferred_fingerprint: | |
| return list(keys) | |
| for index, key in enumerate(keys): | |
| if self.fingerprint(key) != preferred_fingerprint: | |
| continue | |
| return [keys[index], *keys[:index], *keys[index + 1 :]] | |
| return list(keys) | |