Spaces:
Sleeping
Sleeping
File size: 5,663 Bytes
eda316b 6af95df eda316b 6af95df eda316b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | """Environment bootstrap (``.env``) and cache path helpers."""
from __future__ import annotations
import os
from pathlib import Path
from typing import Literal
_BOOTSTRAPPED = False
LLMProvider = Literal["google", "openrouter"]
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
def bootstrap_env() -> None:
"""Load ``.env`` from the process cwd (non-fatal if missing). Safe to call twice."""
global _BOOTSTRAPPED
if _BOOTSTRAPPED:
return
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
pass
_BOOTSTRAPPED = True
def default_humeo_cache_root() -> Path:
"""Default cache root: ``~/.cache/humeo`` on Unix; ``%LOCALAPPDATA%/humeo`` on Windows."""
override = (os.environ.get("HUMEO_CACHE_ROOT") or "").strip()
if override:
return Path(override)
if os.name == "nt":
base = Path(os.environ.get("LOCALAPPDATA", str(Path.home() / "AppData" / "Local")))
return base / "humeo"
return Path.home() / ".cache" / "humeo"
def resolve_gemini_api_key() -> str:
"""Return an API key for Gemini, or raise if none is configured.
Prefer ``GOOGLE_API_KEY``; fall back to ``GEMINI_API_KEY``. Values are read from
the environment after ``bootstrap_env()`` (``.env`` in cwd).
We require an explicit key so we do not fall back to Application Default
Credentials (e.g. ``gcloud auth application-default login``), which often
lack the Generative Language API scope and produce
``403 ACCESS_TOKEN_SCOPE_INSUFFICIENT``.
"""
bootstrap_env()
for env_name in ("GOOGLE_API_KEY", "GEMINI_API_KEY"):
val = (os.environ.get(env_name) or "").strip()
if val:
return val
raise ValueError(
"Set GOOGLE_API_KEY or GEMINI_API_KEY for Gemini clip selection. "
"See docs/ENVIRONMENT.md. Without an API key the client may use ADC and fail "
"with insufficient scopes (403)."
)
def resolve_openrouter_api_key() -> str:
"""Return the OpenRouter API key, or raise if missing."""
return resolve_openrouter_api_keys()[0]
def resolve_openrouter_api_keys() -> list[str]:
"""Return OpenRouter API keys in failover order, or raise if missing.
``OPENROUTER_API_KEY`` remains the primary key. Optional backups can be
supplied with ``OPENROUTER_API_KEY_BACKUP``, ``OPENROUTER_API_KEY_2``, or
a comma/newline-separated ``OPENROUTER_API_KEYS`` value.
"""
bootstrap_env()
keys: list[str] = []
for env_name in (
"OPENROUTER_API_KEY",
"OPENROUTER_API_KEY_BACKUP",
"OPENROUTER_API_KEY_2",
):
val = (os.environ.get(env_name) or "").strip()
if val:
keys.append(val)
extra = (os.environ.get("OPENROUTER_API_KEYS") or "").strip()
if extra:
for item in extra.replace("\n", ",").split(","):
val = item.strip()
if val:
keys.append(val)
deduped = list(dict.fromkeys(keys))
if deduped:
return deduped
raise ValueError(
"Set OPENROUTER_API_KEY to use OpenRouter as the backend for the Gemini stages. "
"See docs/ENVIRONMENT.md."
)
def current_llm_provider() -> LLMProvider | None:
"""Best-effort active backend detection from the environment.
``HUMEO_LLM_PROVIDER`` overrides key-based auto-detection when set.
"""
bootstrap_env()
forced = (os.environ.get("HUMEO_LLM_PROVIDER") or "auto").strip().lower()
if forced in ("google", "openrouter"):
return forced # type: ignore[return-value]
if (os.environ.get("GOOGLE_API_KEY") or "").strip():
return "google"
if (os.environ.get("GEMINI_API_KEY") or "").strip():
return "google"
if any(
(os.environ.get(name) or "").strip()
for name in (
"OPENROUTER_API_KEY",
"OPENROUTER_API_KEY_BACKUP",
"OPENROUTER_API_KEY_2",
"OPENROUTER_API_KEYS",
)
):
return "openrouter"
return None
def resolve_llm_provider() -> LLMProvider:
"""Return the active backend for Gemini-like stages, or raise if none is configured."""
provider = current_llm_provider()
if provider is not None:
if provider == "google":
resolve_gemini_api_key()
else:
resolve_openrouter_api_key()
return provider
raise ValueError(
"Set GOOGLE_API_KEY or GEMINI_API_KEY for the Google Gemini SDK, "
"or set OPENROUTER_API_KEY to route these stages through OpenRouter. "
"You can also force the backend with HUMEO_LLM_PROVIDER=google|openrouter."
)
def model_name_for_provider(model_name: str, provider: LLMProvider) -> str:
"""Normalize model identifiers between Google Gemini SDK and OpenRouter.
- Google SDK expects bare Gemini ids like ``gemini-3.1-flash-lite-preview``.
- OpenRouter expects provider-qualified ids like
``google/gemini-3.1-flash-lite-preview``.
"""
name = model_name.strip()
if provider == "openrouter":
if "/" not in name and name.startswith(("gemini-", "gemma-")):
return f"google/{name}"
return name
if provider == "google" and name.startswith("google/"):
return name.split("/", 1)[1]
return name
def openrouter_default_headers() -> dict[str, str]:
"""Headers that help identify Humeo traffic to OpenRouter."""
return {
"HTTP-Referer": "https://github.com/frenzy2004/shortform",
"X-OpenRouter-Title": "Humeo",
}
|