Update 2026-05-13 16:43:53
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import os
|
||||
from typing import Optional, Dict
|
||||
|
||||
from nanobot.providers.azure_openai_provider import AzureOpenAIProvider
|
||||
from nanobot.providers.openai_codex_provider import OpenAICodexProvider
|
||||
from nanobot.providers.registry import find_by_name
|
||||
|
||||
from app.core.patched_openai_compat_provider import PatchedOpenAICompatProvider
|
||||
|
||||
|
||||
def normalize_provider_name(provider: Optional[str]) -> Optional[str]:
|
||||
if not provider:
|
||||
return None
|
||||
normalized = provider.strip().lower()
|
||||
alias_map = {
|
||||
"azure": "azure_openai",
|
||||
"local": "vllm",
|
||||
}
|
||||
return alias_map.get(normalized, normalized)
|
||||
|
||||
|
||||
def _running_in_docker() -> bool:
|
||||
# Best-effort, cross-platform detection.
|
||||
if os.environ.get("DATACLAW_RUNNING_IN_DOCKER", "").strip().lower() in ("1", "true", "yes", "y"):
|
||||
return True
|
||||
return os.path.exists("/.dockerenv")
|
||||
|
||||
|
||||
def _rewrite_localhost_api_base(api_base: Optional[str]) -> Optional[str]:
|
||||
"""
|
||||
When running inside Docker, `localhost` points to the container itself.
|
||||
For host-local LLMs (Ollama/vLLM), users often configure `http://localhost:...`,
|
||||
which breaks in containers. We rewrite it to `host.docker.internal`.
|
||||
"""
|
||||
if not api_base:
|
||||
return api_base
|
||||
base = api_base.strip()
|
||||
if base.startswith("http://localhost") or base.startswith("https://localhost"):
|
||||
return base.replace("://localhost", "://host.docker.internal", 1)
|
||||
if base.startswith("http://127.0.0.1") or base.startswith("https://127.0.0.1"):
|
||||
return base.replace("://127.0.0.1", "://host.docker.internal", 1)
|
||||
return api_base
|
||||
|
||||
|
||||
def build_llm_provider(
|
||||
*,
|
||||
model: str,
|
||||
provider: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
api_base: Optional[str] = None,
|
||||
extra_headers: Optional[Dict[str, str]] = None,
|
||||
):
|
||||
provider_name = normalize_provider_name(provider)
|
||||
spec = find_by_name(provider_name) if provider_name else None
|
||||
backend = spec.backend if spec else "openai_compat"
|
||||
if _running_in_docker():
|
||||
api_base = _rewrite_localhost_api_base(api_base)
|
||||
|
||||
if backend == "openai_codex" or model.startswith("openai-codex/"):
|
||||
return OpenAICodexProvider(default_model=model)
|
||||
|
||||
if backend == "azure_openai":
|
||||
if not api_key or not api_base:
|
||||
raise ValueError("Azure OpenAI requires api_key and api_base.")
|
||||
return AzureOpenAIProvider(
|
||||
api_key=api_key,
|
||||
api_base=api_base,
|
||||
default_model=model,
|
||||
)
|
||||
|
||||
if backend == "anthropic":
|
||||
from nanobot.providers.anthropic_provider import AnthropicProvider
|
||||
|
||||
return AnthropicProvider(
|
||||
api_key=api_key,
|
||||
api_base=api_base,
|
||||
default_model=model,
|
||||
extra_headers=extra_headers,
|
||||
)
|
||||
|
||||
return PatchedOpenAICompatProvider(
|
||||
api_key=api_key,
|
||||
api_base=api_base,
|
||||
default_model=model,
|
||||
extra_headers=extra_headers,
|
||||
spec=spec,
|
||||
)
|
||||
Reference in New Issue
Block a user