gmw / gemini_web2api /config.py
nanoppa's picture
Upload 20 files
f926954 verified
Raw
History Blame Contribute Delete
3.71 kB
"""Configuration management."""
import json
import os
from typing import Any, Callable
DEFAULT_CONFIG = {
"port": 7860,
"host": "0.0.0.0",
"retry_attempts": 3,
"retry_delay_sec": 2,
"request_timeout_sec": 180,
"gemini_bl": "boq_assistant-bard-web-server_20260525.09_p0",
"auth_user": None,
"xsrf_token": None,
"default_model": "gemini-3.5-flash",
"log_requests": True,
"cookie_file": None,
"proxy": None,
"api_keys": [],
}
CONFIG = dict(DEFAULT_CONFIG)
def _env_value(*names: str) -> str | None:
"""Return the first non-empty environment variable value."""
for name in names:
value = os.environ.get(name)
if value is not None and value != "":
return value
return None
def _to_bool(value: str) -> bool:
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
def _to_int(value: str) -> int:
return int(value.strip())
def _to_nullable_str(value: str) -> str | None:
value = value.strip()
if value.lower() in {"", "none", "null"}:
return None
return value
def _to_list(value: str) -> list[str]:
return [item.strip() for item in value.split(",") if item.strip()]
def load_config(path: str = None):
"""Load config from JSON file."""
if path and os.path.exists(path):
with open(path, encoding="utf-8") as f:
CONFIG.update(json.load(f))
return CONFIG
def apply_env_overrides():
"""Apply environment variables with highest priority.
Supported variables are documented in .env.example. Short names such as PORT
are accepted first, and GEMINI_WEB2API_* aliases are also supported.
"""
scalar_mappings: list[tuple[str, Callable[[str], Any], tuple[str, ...]]] = [
("port", _to_int, ("PORT", "GEMINI_WEB2API_PORT")),
("host", str, ("HOST", "GEMINI_WEB2API_HOST")),
("retry_attempts", _to_int, ("RETRY_ATTEMPTS", "GEMINI_WEB2API_RETRY_ATTEMPTS")),
("retry_delay_sec", _to_int, ("RETRY_DELAY_SEC", "GEMINI_WEB2API_RETRY_DELAY_SEC")),
("request_timeout_sec", _to_int, ("REQUEST_TIMEOUT_SEC", "GEMINI_WEB2API_REQUEST_TIMEOUT_SEC")),
("gemini_bl", str, ("GEMINI_BL", "GEMINI_WEB2API_GEMINI_BL")),
("auth_user", _to_nullable_str, ("AUTH_USER", "GEMINI_AUTH_USER", "GEMINI_WEB2API_AUTH_USER")),
("xsrf_token", _to_nullable_str, ("XSRF_TOKEN", "GEMINI_XSRF_TOKEN", "GEMINI_WEB2API_XSRF_TOKEN")),
("default_model", str, ("DEFAULT_MODEL", "GEMINI_DEFAULT_MODEL", "GEMINI_WEB2API_DEFAULT_MODEL")),
("log_requests", _to_bool, ("LOG_REQUESTS", "GEMINI_WEB2API_LOG_REQUESTS")),
("cookie_file", _to_nullable_str, ("COOKIE_FILE", "GEMINI_COOKIE_FILE", "GEMINI_WEB2API_COOKIE_FILE")),
("proxy", _to_nullable_str, ("PROXY", "HTTP_PROXY_URL", "GEMINI_WEB2API_PROXY")),
]
for key, caster, names in scalar_mappings:
value = _env_value(*names)
if value is None:
continue
CONFIG[key] = caster(value)
# API_KEY is a convenience single-key value and intentionally wins over API_KEYS.
api_key = _env_value("API_KEY", "GEMINI_API_KEY", "GEMINI_WEB2API_API_KEY")
if api_key is not None:
CONFIG["api_keys"] = [api_key.strip()] if api_key.strip() else []
return CONFIG
api_keys = _env_value("API_KEYS", "GEMINI_API_KEYS", "GEMINI_WEB2API_API_KEYS")
if api_keys is not None:
CONFIG["api_keys"] = _to_list(api_keys)
return CONFIG
def find_config():
"""Search for config file in standard locations."""
for p in ["./config.json", os.path.expanduser("~/.config/gemini-web2api/config.json")]:
if os.path.exists(p):
return p
return None