| import os |
| import time |
| import random |
| import logging |
|
|
| logger = logging.getLogger("gemini-client") |
|
|
| |
| |
| |
|
|
| PRIMARY_MODELS = [ |
| "gemini-3.1-pro", |
| "gemini-3.1-flash", |
| ] |
|
|
| FALLBACK_MODELS = [ |
| "gemini-2.5-flash", |
| "gemini-3.1-flash-lite", |
| ] |
|
|
| |
| |
| |
| _model_fail_count = { |
| "gemini-3.1-pro": 0, |
| "gemini-3.1-flash": 0, |
| } |
|
|
|
|
| MAX_FAILS = 3 |
|
|
|
|
| |
| |
| |
|
|
| def _pick_model(): |
| """ |
| Select best available model with fallback logic. |
| """ |
| for m in PRIMARY_MODELS: |
| if _model_fail_count.get(m, 0) < MAX_FAILS: |
| return m |
|
|
| return random.choice(FALLBACK_MODELS) |
|
|
|
|
| |
| |
| |
|
|
| def get_model(): |
| """ |
| Public entrypoint used by publisher_ai. |
| Returns an initialized Gemini model. |
| """ |
| try: |
| import google.generativeai as genai |
| except ImportError as exc: |
| raise RuntimeError("google-generativeai is required for Gemini features") from exc |
|
|
| api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY") |
| if api_key: |
| genai.configure(api_key=api_key) |
|
|
| model_name = _pick_model() |
| logger.info(f"[Gemini] Selected model: {model_name}") |
| return genai.GenerativeModel(model_name) |
|
|
|
|
| def safe_generate(prompt: str, client_callable): |
| """ |
| Wrapper for Gemini calls with automatic fallback. |
| """ |
|
|
| last_error = None |
|
|
| for _ in range(3): |
| model = _pick_model() |
|
|
| try: |
| result = client_callable(model, prompt) |
| return result |
|
|
| except Exception as e: |
| last_error = e |
| _model_fail_count[model] = _model_fail_count.get(model, 0) + 1 |
| logger.warning(f"[Gemini FAIL] {model}: {str(e)}") |
| time.sleep(0.5) |
|
|
| raise RuntimeError(f"All Gemini models failed: {last_error}") |
|
|