LLM - Upgrade litellm to >=1.106.2, add DeepSeek, Groq, Mistral, Together AI and xAI providers (#4597)

* Update litellm requirement from >=1.40.0 to >=1.106.2

Supersedes #4595.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* LLM - Add DeepSeek, Groq, Mistral, Together AI and xAI to the provider list

All five serve OpenAI's GET /models, so "Load available models" works for
them via model_list without importing litellm. Together's bare-list response
and its image/embedding models are handled, and Mistral's {"detail": ...}
errors are surfaced.

Also re-select Anthropic on page load for saved 'anthropic/claude-...' models,
the form the model list returns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
dgtlmoonandClaude Opus 5.5 authored and GitHub committed 2026-10-24 21:45:16 +02:00
1 parent 769f438a00
commit 480dfb8b46
24 files changed
+439 -7

No files matched your search

@@ -121,11 +121,16 @@
<select id="llm-provider" onchange="llmOnProviderChange(this.value)"{% if llm_provider_locked %} disabled{% endif %}>
<option value="">— {{ _('select a provider') }} —</option>
<option value="anthropic">Anthropic</option>
<option value="deepseek">DeepSeek</option>
<option value="gemini">Google (Gemini)</option>
<option value="groq">Groq</option>
<option value="mistral">Mistral</option>
<option value="ollama">Ollama</option>
<option value="openai">OpenAI</option>
<option value="openai_compatible">{{ _('OpenAI-compatible (vLLM, LM Studio, llama.cpp)') }}</option>
<option value="openrouter">OpenRouter (200+ models)</option>
<option value="together_ai">Together AI</option>
<option value="xai">xAI (Grok)</option>
</select>
</div>
@@ -460,7 +465,8 @@
<script>
(function () {
const LIVE_PROVIDERS = ['openai', 'anthropic', 'gemini', 'ollama', 'openai_compatible', 'openrouter'];
const LIVE_PROVIDERS = ['openai', 'anthropic', 'gemini', 'ollama', 'openai_compatible', 'openrouter',
'deepseek', 'groq', 'mistral', 'together_ai', 'xai'];
const BASE_DEFAULTS = { ollama: 'http://localhost:11434' };
const KEY_HINTS = {
openai: '{{ _("platform.openai.com → API keys") }}',
@@ -469,6 +475,11 @@
ollama: '{{ _("No API key needed for local Ollama") }}',
openai_compatible: '{{ _("Bearer token for your self-hosted server (vLLM, LM Studio, etc.)") }}',
openrouter: '{{ _("openrouter.ai → Keys") }}',
deepseek: '{{ _("platform.deepseek.com → API keys") }}',
groq: '{{ _("console.groq.com → API keys") }}',
mistral: '{{ _("console.mistral.ai → API keys") }}',
together_ai: '{{ _("api.together.ai → API keys") }}',
xai: '{{ _("console.x.ai → API keys") }}',
};
window.llmDisclaimerToggle = function (cb) {
@@ -630,12 +641,17 @@
if (m.startsWith('gemini/')) guessed = 'gemini';
else if (m.startsWith('ollama/')) guessed = 'ollama';
else if (m.startsWith('openrouter/')) guessed = 'openrouter';
else if (m.startsWith('deepseek/')) guessed = 'deepseek';
else if (m.startsWith('groq/')) guessed = 'groq';
else if (m.startsWith('mistral/')) guessed = 'mistral';
else if (m.startsWith('together_ai/')) guessed = 'together_ai';
else if (m.startsWith('xai/')) guessed = 'xai';
else if (m.startsWith('openai/')) {
// openai/<model> + custom api_base = self-hosted OpenAI-compatible (vLLM etc.)
const baseField = document.querySelector('[name="llm-api_base"]');
guessed = (baseField && baseField.value.trim()) ? 'openai_compatible' : 'openai';
}
else if (m.startsWith('claude')) guessed = 'anthropic';
else if (m.startsWith('claude') || m.startsWith('anthropic/')) guessed = 'anthropic';
else if (m.startsWith('gpt') || m.startsWith('o1') || m.startsWith('o3')) guessed = 'openai';
if (guessed) {
+26 -3
View File
@@ -24,6 +24,18 @@ _GEMINI_BASE = 'https://generativelanguage.googleapis.com'
_OLLAMA_BASE = 'http://localhost:11434'
_OPENROUTER_BASE = 'https://openrouter.ai'
# Hosted providers that serve OpenAI's GET {base}/models, all routed by litellm on their own
# prefix. ui value -> (default base including the version path, litellm model prefix)
_OPENAI_STYLE_PROVIDERS = {
'deepseek': ('https://api.deepseek.com/v1', 'deepseek/'),
'groq': ('https://api.groq.com/openai/v1', 'groq/'),
'mistral': ('https://api.mistral.ai/v1', 'mistral/'),
'together_ai': ('https://api.together.xyz/v1', 'together_ai/'),
'xai': ('https://api.x.ai/v1', 'xai/'),
}
# Together lists image/embedding/rerank models alongside chat ones and labels each with a type
_NON_CHAT_MODEL_TYPES = ('embedding', 'image', 'moderation', 'rerank', 'audio', 'transcribe', 'video')
# Endpoint suffixes people paste into the Ollama base URL, stripped back to the server root
_OLLAMA_SUFFIXES = ('/api/generate', '/api/chat', '/api/embed', '/api/embeddings', '/api/show', '/api/tags', '/api')
@@ -34,7 +46,7 @@ class ModelListError(Exception):
def _provider_error_message(response) -> str:
# Providers wrap the reason differently: OpenAI/Anthropic/Gemini use
# {"error": {"message": ...}}, Ollama and some proxies {"error": "..."} or {"message": ...}
# {"error": {"message": ...}}, Ollama and xAI {"error": "..."}, Mistral {"detail": ...}
try:
body = response.json()
except (ValueError, json.JSONDecodeError):
@@ -45,8 +57,9 @@ def _provider_error_message(response) -> str:
return str(err['message'])
if isinstance(err, str) and err:
return err
if body.get('message'):
return str(body['message'])
for key in ('message', 'detail'):
if isinstance(body.get(key), str) and body[key]:
return body[key]
text = (response.text or '').strip()
return f"HTTP {response.status_code}" + (f": {text[:300]}" if text else '')
@@ -134,6 +147,16 @@ def list_models(provider, api_key=None, api_base=None, timeout=DEFAULT_TIMEOUT):
data = _get_json(url, headers, timeout)
names = ['openrouter/' + m['id'] for m in (data.get('data') or []) if m.get('id')]
elif provider in _OPENAI_STYLE_PROVIDERS:
default_base, prefix = _OPENAI_STYLE_PROVIDERS[provider]
if not api_key:
raise ModelListError(f"An API key is required to list {provider} models.")
base = (api_base or default_base).rstrip('/')
data = _get_json(f"{base}/models", {'Authorization': f'Bearer {api_key}'}, timeout)
entries = data.get('data') if isinstance(data, dict) else data
names = [prefix + m['id'] for m in (entries or [])
if isinstance(m, dict) and m.get('id') and m.get('type') not in _NON_CHAT_MODEL_TYPES]
else:
raise ModelListError(f"Unknown provider '{provider}'")
@@ -96,9 +96,42 @@ def test_openrouter(fake_get):
assert fake_get['calls'][0]['url'] == 'https://openrouter.ai/api/v1/models'
@pytest.mark.parametrize('provider, url, prefix', [
('deepseek', 'https://api.deepseek.com/v1/models', 'deepseek/'),
('groq', 'https://api.groq.com/openai/v1/models', 'groq/'),
('mistral', 'https://api.mistral.ai/v1/models', 'mistral/'),
('together_ai', 'https://api.together.xyz/v1/models', 'together_ai/'),
('xai', 'https://api.x.ai/v1/models', 'xai/'),
])
def test_openai_style_hosted_providers(fake_get, provider, url, prefix):
fake_get['response'] = _FakeResponse(payload={'data': [{'id': 'model-a'}]})
assert list_models(provider, api_key='k') == [prefix + 'model-a']
call = fake_get['calls'][0]
assert call['url'] == url
assert call['headers']['Authorization'] == 'Bearer k'
@pytest.mark.parametrize('provider', ['deepseek', 'groq', 'mistral', 'together_ai', 'xai'])
def test_openai_style_hosted_providers_need_key(fake_get, provider):
with pytest.raises(ModelListError):
list_models(provider)
assert fake_get['calls'] == []
def test_together_bare_list_and_non_chat_filtered(fake_get):
# Together returns a bare list and mixes in image/embedding models
fake_get['response'] = _FakeResponse(payload=[
{'id': 'meta-llama/Llama-3.3-70B-Instruct-Turbo', 'type': 'chat'},
{'id': 'black-forest-labs/FLUX.1-schnell', 'type': 'image'},
{'id': 'BAAI/bge-large-en-v1.5', 'type': 'embedding'},
])
assert list_models('together_ai', api_key='k') == ['together_ai/meta-llama/Llama-3.3-70B-Instruct-Turbo']
@pytest.mark.parametrize('payload, text, expected', [
({'error': {'message': 'Incorrect API key provided'}}, '', 'Incorrect API key provided'),
({'error': 'model runner offline'}, '', 'model runner offline'),
({'detail': 'Invalid API Key'}, '', 'Invalid API Key'),
(None, 'Bad Gateway', 'HTTP 502: Bad Gateway'),
])
def test_provider_error_is_surfaced(fake_get, payload, text, expected):
@@ -1331,6 +1331,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1347,6 +1347,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1329,6 +1329,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1329,6 +1329,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1377,6 +1377,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1335,6 +1335,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1414,6 +1414,26 @@ msgstr "Bearer token untuk server self-hosted Anda (vLLM, LM Studio, dll.)"
msgid "openrouter.ai → Keys"
msgstr "openrouter.ai → Kunci"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr "Pilih penyedia terlebih dahulu."
@@ -1331,6 +1331,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1336,6 +1336,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1337,6 +1337,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr "openrouter.ai → 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr "platform.deepseek.com → API 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr "console.groq.com → API 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr "console.mistral.ai → API 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr "api.together.ai → API 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr "console.x.ai → API 키"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr "먼저 프로바이더를 선택하세요."
+21 -1
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: changedetection.io 0.60.9\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-10-23 17:16+0200\n"
"POT-Creation-Date: 2026-10-24 21:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1328,6 +1328,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1450,6 +1450,26 @@ msgstr "Token Bearer dla własnego serwera (vLLM, LM Studio itp.)"
msgid "openrouter.ai → Keys"
msgstr "openrouter.ai → Klucze"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr "Najpierw wybierz dostawcę."
@@ -1354,6 +1354,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1418,6 +1418,26 @@ msgstr "Токен носителя для вашего собственного
msgid "openrouter.ai → Keys"
msgstr "openrouter.ai → Ключи"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr "Сначала выберите провайдера."
@@ -1364,6 +1364,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1344,6 +1344,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1334,6 +1334,26 @@ msgstr ""
msgid "openrouter.ai → Keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr ""
@@ -1338,6 +1338,26 @@ msgstr "您自行架設伺服器的 Bearer 權杖(vLLM、LM Studio 等)"
msgid "openrouter.ai → Keys"
msgstr "openrouter.ai → 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "platform.deepseek.com → API keys"
msgstr "platform.deepseek.com → API 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.groq.com → API keys"
msgstr "console.groq.com → API 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.mistral.ai → API keys"
msgstr "console.mistral.ai → API 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "api.together.ai → API keys"
msgstr "api.together.ai → API 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "console.x.ai → API keys"
msgstr "console.x.ai → API 金鑰"
#: changedetectionio/blueprint/settings/templates/settings_llm_tab.html
msgid "Select a provider first."
msgstr "請先選擇供應商。"
+1 -1
View File
@@ -154,7 +154,7 @@ pluggy ~= 1.7
# Uncapped: litellm now uses jsonschema<5.0,>=4.0.0, resolving earlier openapi-spec-validator conflict.
# Note litellm >=1.83.11 does `from typing import NotRequired`, which is 3.11+ (PEP 655) - that is
# why 3.10 support was dropped rather than pinning everyone to the last 3.10-compatible release.
litellm>=1.40.0
litellm>=1.106.2
# Used today for LLMSettings (model/LLMSettings.py); transitively pulled by litellm but pinned explicitly
# so the validation/typing layer doesn't disappear if litellm drops it.
pydantic>=2.14.0,<3.0