From 462bce002e2141b342260969588e69f55f8bb46a Mon Sep 17 00:00:00 2001 From: dragonfsky Date: Fri, 22 Aug 2025 18:01:00 +0800 Subject: [PATCH 1/4] feat: add custom Gemini endpoint support - Add GEMINI_BASE_URL configuration option in .env.example - Implement custom endpoint support in GeminiModelProvider using HttpOptions - Update registry to pass base_url parameter to Gemini provider - Maintain backward compatibility - uses default Google endpoint when not configured --- .env.example | 1 + providers/gemini.py | 14 ++++++++++++-- providers/registry.py | 12 ++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 58d0037..6cc09cb 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,7 @@ # Option 1: Use native APIs (recommended for direct access) # Get your Gemini API key from: https://makersuite.google.com/app/apikey GEMINI_API_KEY=your_gemini_api_key_here +# GEMINI_BASE_URL= # Optional: Custom Gemini endpoint (defaults to Google's API) # Get your OpenAI API key from: https://platform.openai.com/api-keys OPENAI_API_KEY=your_openai_api_key_here diff --git a/providers/gemini.py b/providers/gemini.py index aa009b3..39d2ca2 100644 --- a/providers/gemini.py +++ b/providers/gemini.py @@ -117,16 +117,26 @@ class GeminiModelProvider(ModelProvider): } def __init__(self, api_key: str, **kwargs): - """Initialize Gemini provider with API key.""" + """Initialize Gemini provider with API key and optional base URL.""" super().__init__(api_key, **kwargs) self._client = None self._token_counters = {} # Cache for token counting + self._base_url = kwargs.get('base_url', None) # Optional custom endpoint @property def client(self): """Lazy initialization of Gemini client.""" if self._client is None: - self._client = genai.Client(api_key=self.api_key) + # Check if custom base URL is provided + if self._base_url: + # Use HttpOptions to set custom endpoint + from google.genai.types import HttpOptions + http_options = HttpOptions(baseUrl=self._base_url) + logger.debug(f"Initializing Gemini client with custom endpoint: {self._base_url}") + self._client = genai.Client(api_key=self.api_key, http_options=http_options) + else: + # Use default Google endpoint + self._client = genai.Client(api_key=self.api_key) return self._client def get_capabilities(self, model_name: str) -> ModelCapabilities: diff --git a/providers/registry.py b/providers/registry.py index 1bb232d..b4d4cb1 100644 --- a/providers/registry.py +++ b/providers/registry.py @@ -93,6 +93,18 @@ class ModelProviderRegistry: api_key = api_key or "" # Initialize custom provider with both API key and base URL provider = provider_class(api_key=api_key, base_url=custom_url) + elif provider_type == ProviderType.GOOGLE: + # For Gemini, check if custom base URL is configured + if not api_key: + return None + gemini_base_url = os.getenv("GEMINI_BASE_URL") + if gemini_base_url: + # Initialize with custom endpoint + provider = provider_class(api_key=api_key, base_url=gemini_base_url) + logging.info(f"Initialized Gemini provider with custom endpoint: {gemini_base_url}") + else: + # Use default Google endpoint + provider = provider_class(api_key=api_key) else: if not api_key: return None From 956e8a6927837f5c7f031a0db1dd0b0b5483c626 Mon Sep 17 00:00:00 2001 From: dragonfsky Date: Fri, 22 Aug 2025 18:34:39 +0800 Subject: [PATCH 2/4] fix: use types.HttpOptions from module imports instead of local import Addresses linting issue raised by CI checks --- providers/gemini.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/providers/gemini.py b/providers/gemini.py index 39d2ca2..2386c5a 100644 --- a/providers/gemini.py +++ b/providers/gemini.py @@ -130,8 +130,7 @@ class GeminiModelProvider(ModelProvider): # Check if custom base URL is provided if self._base_url: # Use HttpOptions to set custom endpoint - from google.genai.types import HttpOptions - http_options = HttpOptions(baseUrl=self._base_url) + http_options = types.HttpOptions(baseUrl=self._base_url) logger.debug(f"Initializing Gemini client with custom endpoint: {self._base_url}") self._client = genai.Client(api_key=self.api_key, http_options=http_options) else: From 023940be3e38a7eedbc8bf8404a4a5afc50f8398 Mon Sep 17 00:00:00 2001 From: dragonfsky Date: Fri, 22 Aug 2025 18:37:11 +0800 Subject: [PATCH 3/4] refactor: simplify Gemini provider initialization using kwargs dict As suggested by code review, this reduces code duplication and improves maintainability --- providers/registry.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/providers/registry.py b/providers/registry.py index b4d4cb1..7a1b94e 100644 --- a/providers/registry.py +++ b/providers/registry.py @@ -98,13 +98,11 @@ class ModelProviderRegistry: if not api_key: return None gemini_base_url = os.getenv("GEMINI_BASE_URL") + provider_kwargs = {"api_key": api_key} if gemini_base_url: - # Initialize with custom endpoint - provider = provider_class(api_key=api_key, base_url=gemini_base_url) + provider_kwargs["base_url"] = gemini_base_url logging.info(f"Initialized Gemini provider with custom endpoint: {gemini_base_url}") - else: - # Use default Google endpoint - provider = provider_class(api_key=api_key) + provider = provider_class(**provider_kwargs) else: if not api_key: return None From 33ea896c511764904bf2b6b22df823928f88a148 Mon Sep 17 00:00:00 2001 From: dragonfsky Date: Fri, 22 Aug 2025 18:40:25 +0800 Subject: [PATCH 4/4] style: apply Black formatting to use double quotes Fix Black linting error in CI checks --- providers/gemini.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/gemini.py b/providers/gemini.py index 2386c5a..b656ca1 100644 --- a/providers/gemini.py +++ b/providers/gemini.py @@ -121,7 +121,7 @@ class GeminiModelProvider(ModelProvider): super().__init__(api_key, **kwargs) self._client = None self._token_counters = {} # Cache for token counting - self._base_url = kwargs.get('base_url', None) # Optional custom endpoint + self._base_url = kwargs.get("base_url", None) # Optional custom endpoint @property def client(self):