Initial Home Assistant commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
"""Endpoint normalization helpers for provider setup and requests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def ensure_http_url(value: str | None, *, default_scheme: str = "http") -> str:
|
||||
"""Return a stripped HTTP(S) URL, adding a scheme when one is omitted."""
|
||||
|
||||
endpoint = str(value or "").strip().rstrip("/")
|
||||
if not endpoint:
|
||||
return ""
|
||||
if re.match(r"^https?://", endpoint):
|
||||
return endpoint
|
||||
return f"{default_scheme}://{endpoint}"
|
||||
|
||||
|
||||
def openai_chat_endpoint(endpoint: str | None) -> str:
|
||||
"""Normalize an OpenAI-compatible endpoint to a chat completions URL."""
|
||||
|
||||
base = ensure_http_url(endpoint)
|
||||
if not base:
|
||||
return ""
|
||||
if base.endswith("/chat/completions"):
|
||||
return base
|
||||
if base.endswith("/api"):
|
||||
return f"{base}/chat/completions"
|
||||
if base.endswith("/v1"):
|
||||
return f"{base}/chat/completions"
|
||||
return f"{base}/v1/chat/completions"
|
||||
|
||||
|
||||
def openai_model_endpoint_candidates(endpoint: str | None) -> list[str]:
|
||||
"""Return likely model-listing endpoints for OpenAI-compatible servers."""
|
||||
|
||||
base = ensure_http_url(endpoint)
|
||||
if not base:
|
||||
return []
|
||||
if base.endswith("/chat/completions"):
|
||||
base = base[: -len("/chat/completions")]
|
||||
|
||||
candidates: list[str]
|
||||
if base.endswith("/api"):
|
||||
candidates = [f"{base}/models", f"{base}/v1/models"]
|
||||
elif base.endswith("/v1"):
|
||||
candidates = [f"{base}/models"]
|
||||
else:
|
||||
candidates = [f"{base}/v1/models", f"{base}/models", f"{base}/api/models"]
|
||||
return _dedupe(candidates)
|
||||
|
||||
|
||||
def ollama_base_url(
|
||||
*,
|
||||
base_url: str | None = None,
|
||||
ip_address: str | None = None,
|
||||
port: int | str | None = None,
|
||||
https: bool = False,
|
||||
) -> str:
|
||||
"""Build an Ollama-compatible base URL from either a full URL or host/port fields."""
|
||||
|
||||
if base_url:
|
||||
return ensure_http_url(base_url)
|
||||
if not ip_address:
|
||||
return ""
|
||||
host = str(ip_address).strip().rstrip("/")
|
||||
if re.match(r"^https?://", host):
|
||||
return host
|
||||
proto = "https" if https else "http"
|
||||
return f"{proto}://{host}:{port or 11434}"
|
||||
|
||||
|
||||
def ollama_api_candidates(base_url: str, api_path: str) -> list[str]:
|
||||
"""Return likely Ollama API paths for native Ollama and Open WebUI proxies."""
|
||||
|
||||
base = ensure_http_url(base_url)
|
||||
if not base:
|
||||
return []
|
||||
path = api_path.strip("/")
|
||||
if base.endswith(f"/{path}"):
|
||||
return [base]
|
||||
if base.endswith("/api") and path.startswith("api/"):
|
||||
return [f"{base}/{path.split('/', 1)[1]}"]
|
||||
candidates = [f"{base}/{path}"]
|
||||
if not base.endswith("/ollama"):
|
||||
candidates.append(f"{base}/ollama/{path}")
|
||||
return _dedupe(candidates)
|
||||
|
||||
|
||||
def bearer_auth_headers(api_key: str | None) -> dict[str, str] | None:
|
||||
"""Return bearer authorization headers for provider APIs that need a token."""
|
||||
|
||||
token = str(api_key or "").strip()
|
||||
if not token:
|
||||
return None
|
||||
if token.lower().startswith("bearer "):
|
||||
return {"Authorization": token}
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
||||
|
||||
def _dedupe(values: list[str]) -> list[str]:
|
||||
seen: set[str] = set()
|
||||
deduped: list[str] = []
|
||||
for value in values:
|
||||
if value not in seen:
|
||||
seen.add(value)
|
||||
deduped.append(value)
|
||||
return deduped
|
||||
Reference in New Issue
Block a user