mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-20 06:23:46 +00:00
Merge pull request #12984 from darashenka/main
honor OLLAMA_API_KEY for ollama_chat
This commit is contained in:
@@ -232,6 +232,8 @@ class OllamaChatConfig(BaseConfig):
|
||||
api_key: Optional[str] = None,
|
||||
api_base: Optional[str] = None,
|
||||
) -> dict:
|
||||
if api_key is not None and "Authorization" not in headers:
|
||||
headers["Authorization"] = f"Bearer {api_key}"
|
||||
return headers
|
||||
|
||||
def get_complete_url(
|
||||
|
||||
@@ -57,8 +57,20 @@ class OllamaModelInfo(BaseLLMModelInfo):
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_api_key(api_key=None) -> None:
|
||||
return None # Ollama does not use an API key by default
|
||||
def get_api_key(api_key=None) -> Optional[str]:
|
||||
"""Get API key from environment variables or litellm configuration"""
|
||||
import os
|
||||
|
||||
import litellm
|
||||
from litellm.secret_managers.main import get_secret_str
|
||||
|
||||
return (
|
||||
os.environ.get("OLLAMA_API_KEY")
|
||||
or litellm.api_key
|
||||
or litellm.openai_key
|
||||
or get_secret_str("OLLAMA_API_KEY")
|
||||
)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_api_base(api_base: Optional[str] = None) -> str:
|
||||
@@ -73,9 +85,12 @@ class OllamaModelInfo(BaseLLMModelInfo):
|
||||
"""
|
||||
|
||||
base = self.get_api_base(api_base)
|
||||
api_key = self.get_api_key()
|
||||
headers = { "Authorization": f"Bearer {api_key}" } if api_key else {}
|
||||
|
||||
names: set[str] = set()
|
||||
try:
|
||||
resp = httpx.get(f"{base}/api/tags")
|
||||
resp = httpx.get(f"{base}/api/tags", headers=headers)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
# Expecting a dict with a 'models' list
|
||||
|
||||
@@ -204,6 +204,21 @@ class OllamaConfig(BaseConfig):
|
||||
return v
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_api_key() -> Optional[str]:
|
||||
"""Get API key from environment variables or litellm configuration"""
|
||||
import os
|
||||
|
||||
import litellm
|
||||
from litellm.secret_managers.main import get_secret_str
|
||||
|
||||
return (
|
||||
os.environ.get("OLLAMA_API_KEY")
|
||||
or litellm.api_key
|
||||
or litellm.openai_key
|
||||
or get_secret_str("OLLAMA_API_KEY")
|
||||
)
|
||||
|
||||
def get_model_info(self, model: str) -> ModelInfoBase:
|
||||
"""
|
||||
curl http://localhost:11434/api/show -d '{
|
||||
@@ -213,11 +228,14 @@ class OllamaConfig(BaseConfig):
|
||||
if model.startswith("ollama/") or model.startswith("ollama_chat/"):
|
||||
model = model.split("/", 1)[1]
|
||||
api_base = get_secret_str("OLLAMA_API_BASE") or "http://localhost:11434"
|
||||
api_key = self.get_api_key()
|
||||
headers = { "Authorization": f"Bearer {api_key}" } if api_key else {}
|
||||
|
||||
try:
|
||||
response = litellm.module_level_client.post(
|
||||
url=f"{api_base}/api/show",
|
||||
json={"name": model},
|
||||
headers=headers,
|
||||
)
|
||||
except Exception as e:
|
||||
raise Exception(
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -56,6 +54,7 @@ class TestOllamaModelInfo:
|
||||
get_models should extract and return sorted unique model names.
|
||||
"""
|
||||
calls = []
|
||||
call_headers = []
|
||||
sample = {
|
||||
"models": [
|
||||
{"name": "zeta"},
|
||||
@@ -65,8 +64,9 @@ class TestOllamaModelInfo:
|
||||
]
|
||||
}
|
||||
|
||||
def mock_get(url):
|
||||
def mock_get(url, headers):
|
||||
calls.append(url)
|
||||
call_headers.append(headers)
|
||||
return DummyResponse(sample, status_code=200)
|
||||
|
||||
monkeypatch.setattr(httpx, "get", mock_get)
|
||||
@@ -76,6 +76,32 @@ class TestOllamaModelInfo:
|
||||
assert models == ["alpha", "zeta"]
|
||||
# Ensure correct endpoint was called
|
||||
assert calls and calls[0].endswith("/api/tags")
|
||||
assert call_headers and call_headers[0] == {}
|
||||
|
||||
def test_get_models_from_dict_response_api_key(self, monkeypatch):
|
||||
"""
|
||||
When the /api/tags endpoint returns a dict with a 'models' list,
|
||||
get_models should extract and return sorted unique model names.
|
||||
"""
|
||||
calls = []
|
||||
call_headers = []
|
||||
|
||||
def mock_get(url, headers):
|
||||
calls.append(url)
|
||||
call_headers.append(headers)
|
||||
return DummyResponse({}, status_code=200)
|
||||
|
||||
old_environ = dict(os.environ)
|
||||
os.environ.update({"OLLAMA_API_KEY": "test_api_key"})
|
||||
monkeypatch.setattr(httpx, "get", mock_get)
|
||||
info = OllamaModelInfo()
|
||||
models = info.get_models()
|
||||
os.environ.clear()
|
||||
os.environ.update(old_environ)
|
||||
assert models == []
|
||||
# Ensure correct endpoint was called
|
||||
assert calls and calls[0].endswith("/api/tags")
|
||||
assert call_headers and call_headers[0] == {'Authorization': 'Bearer test_api_key'}
|
||||
|
||||
def test_get_models_from_list_response(self, monkeypatch):
|
||||
"""
|
||||
@@ -88,7 +114,7 @@ class TestOllamaModelInfo:
|
||||
{}, # no name/model key should be ignored
|
||||
]
|
||||
|
||||
def mock_get(url):
|
||||
def mock_get(url, headers):
|
||||
return DummyResponse(sample, status_code=200)
|
||||
|
||||
monkeypatch.setattr(httpx, "get", mock_get)
|
||||
@@ -102,7 +128,7 @@ class TestOllamaModelInfo:
|
||||
fall back to the static models_by_provider list prefixed by 'ollama/'.
|
||||
"""
|
||||
|
||||
def mock_get(url):
|
||||
def mock_get(url, headers):
|
||||
raise Exception("connection failure")
|
||||
|
||||
monkeypatch.setattr(httpx, "get", mock_get)
|
||||
|
||||
Reference in New Issue
Block a user