Open router provider filter (#5208) * Added filter for OpenRouter models provider selection Now if a model is selected, only available providers for that model will show. Wanted to do the same for the quants, but I think the API is not returning the quants available for each model at the moment. Used existing API that for some reason was not consumed. * Added filter for OpenRouter providers Now if a model is selected, only the providers available show. Wanted to do the same with the quants but it seems the OpenRouter API is not giving the available quants list at the moment for each model. * gua * Now it also works on chat completion and only disables options * detail * Warning added * eslint * Move inline styles to CSS --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

8f5c8f0a8edce57ae3fa9458e379784b07311e06

GERNOMA <54479238+GERNOMA@users.noreply.github.com>

Signed
5 files changed, +105 -3Showing whitespace changes
public/css/toggle-dependent.css+6 -0
@@ -568,3 +568,9 @@ label[for="bind_preset_to_connection"]:has(input:checked) {
568#adaptive_p_block:has([data-tg-samplers="adaptive_target"][style*="display: none"]):has([data-tg-samplers="adaptive_decay"][style*="display: none"]) {568#adaptive_p_block:has([data-tg-samplers="adaptive_target"][style*="display: none"]):has([data-tg-samplers="adaptive_decay"][style*="display: none"]) {
569 display: none;569 display: none;
570}570}
571
572#openrouter_provider_warning_text,
573#openrouter_provider_warning_chat {
574 color: var(--warning);
575 margin-left: 5px;
576}
public/index.html+8 -2
@@ -2460,7 +2460,10 @@
2460 </select>2460 </select>
2461 </div>2461 </div>
2462 <div>2462 <div>
2463 <h4 data-i18n="Model Providers">Model Providers</h4>2463 <h4>
2464 <span data-i18n="Model Providers">Model Providers</span>
2465 <i id="openrouter_provider_warning_text" class="fa-solid fa-circle-exclamation displayNone" title="Deselect inapplicable provider(s) or select an applicable provider to avoid a 404 error."></i>
2466 </h4>
2464 <select id="openrouter_providers_text" class="openrouter_providers" multiple>2467 <select id="openrouter_providers_text" class="openrouter_providers" multiple>
2465 </select>2468 </select>
2466 <label class="checkbox_label" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">2469 <label class="checkbox_label" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
@@ -3214,7 +3217,10 @@
3214 </div>3217 </div>
3215 </div>3218 </div>
3216 <div>3219 <div>
3217 <h4 data-i18n="Model Providers">Model Providers</h4>3220 <h4>
3221 <span data-i18n="Model Providers">Model Providers</span>
3222 <i id="openrouter_provider_warning_chat" class="fa-solid fa-circle-exclamation displayNone" title="Deselect inapplicable provider(s) or select an applicable provider to avoid a 404 error."></i>
3223 </h4>
3218 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>3224 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>
3219 </select>3225 </select>
3220 <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." title="Automatically chooses an alternative provider if chosen providers can't serve your request.">3226 <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
public/scripts/openai.js+4 -0
@@ -79,6 +79,7 @@ import { t } from './i18n.js';
79import { ToolManager } from './tool-calling.js';79import { ToolManager } from './tool-calling.js';
80import { accountStorage } from './util/AccountStorage.js';80import { accountStorage } from './util/AccountStorage.js';
81import { COMETAPI_IGNORE_PATTERNS, IGNORE_SYMBOL, MEDIA_DISPLAY, MEDIA_TYPE } from './constants.js';81import { COMETAPI_IGNORE_PATTERNS, IGNORE_SYMBOL, MEDIA_DISPLAY, MEDIA_TYPE } from './constants.js';
82import { syncOpenRouterProvidersForModel, updateOpenRouterProvidersWarning } from './textgen-models.js';
8283
83export {84export {
84 openai_messages_count,85 openai_messages_count,
@@ -5135,6 +5136,7 @@ async function onModelChange() {
51355136
5136 console.log('OpenRouter model changed to', value);5137 console.log('OpenRouter model changed to', value);
5137 oai_settings.openrouter_model = value;5138 oai_settings.openrouter_model = value;
5139 syncOpenRouterProvidersForModel(value, '#openrouter_providers_chat');
5138 }5140 }
51395141
5140 if ($(this).is('#model_ai21_select')) {5142 if ($(this).is('#model_ai21_select')) {
@@ -6623,6 +6625,7 @@ export function initOpenAI() {
66236625
6624 $('#openrouter_allow_fallbacks').on('input', function () {6626 $('#openrouter_allow_fallbacks').on('input', function () {
6625 oai_settings.openrouter_allow_fallbacks = !!$(this).prop('checked');6627 oai_settings.openrouter_allow_fallbacks = !!$(this).prop('checked');
6628 updateOpenRouterProvidersWarning('#openrouter_providers_chat');
6626 saveSettingsDebounced();6629 saveSettingsDebounced();
6627 });6630 });
66286631
@@ -6882,6 +6885,7 @@ export function initOpenAI() {
68826885
6883 oai_settings.openrouter_providers = selectedProviders;6886 oai_settings.openrouter_providers = selectedProviders;
68846887
6888 updateOpenRouterProvidersWarning('#openrouter_providers_chat');
6885 saveSettingsDebounced();6889 saveSettingsDebounced();
6886 });6890 });
68876891
public/scripts/textgen-models.js+81 -0
@@ -101,6 +101,85 @@ const OPENROUTER_PROVIDERS = [
101 'Z.AI',101 'Z.AI',
102];102];
103103
104const OPENROUTER_PROVIDER_WARNING_SELECTORS = {
105 '#openrouter_providers_text': {
106 fallbackSelector: '#openrouter_allow_fallbacks_textgenerationwebui',
107 warningSelector: '#openrouter_provider_warning_text',
108 },
109 '#openrouter_providers_chat': {
110 fallbackSelector: '#openrouter_allow_fallbacks',
111 warningSelector: '#openrouter_provider_warning_chat',
112 },
113};
114
115export function updateOpenRouterProvidersWarning(providersSelector) {
116 const $providers = $(providersSelector);
117
118 const warningSelectors = OPENROUTER_PROVIDER_WARNING_SELECTORS[providersSelector];
119
120 if ($providers.length === 0 || !warningSelectors) {
121 return;
122 }
123
124 const $fallback = $(warningSelectors.fallbackSelector);
125 const $warning = $(warningSelectors.warningSelector);
126
127 const allowFallback = !!$fallback.prop('checked');
128 const selectedCount = $providers.find('option:selected').length;
129 const applicableSelectedCount = $providers.find('option:selected:not(:disabled)').length;
130 const showWarning = !allowFallback && selectedCount > 0 && applicableSelectedCount === 0;
131
132 $warning.toggleClass('displayNone', !showWarning);
133}
134
135export async function syncOpenRouterProvidersForModel(modelId, providersSelector) {
136 const $providers = $(providersSelector);
137
138 const refreshWarningState = () => {
139 updateOpenRouterProvidersWarning(providersSelector);
140 };
141
142 if (!modelId || !modelId.includes('/')) {
143 $providers.find('option').prop('disabled', false);
144 $providers.trigger('change.select2');
145 refreshWarningState();
146 return;
147 }
148
149 try {
150 const response = await fetch('/api/openrouter/models/providers', {
151 method: 'POST',
152 headers: getRequestHeaders(),
153 body: JSON.stringify({ model: modelId }),
154 });
155
156 if (!response.ok) {
157 refreshWarningState();
158 return;
159 }
160
161 const providerNames = await response.json();
162
163 if (!Array.isArray(providerNames) || providerNames.length === 0) {
164 $providers.find('option').prop('disabled', false);
165 $providers.trigger('change.select2');
166 refreshWarningState();
167 return;
168 }
169
170 $providers.find('option').each(function () {
171 const isAvailable = providerNames.includes($(this).val());
172 $(this).prop('disabled', !isAvailable);
173 });
174
175 $providers.trigger('change.select2');
176 refreshWarningState();
177 } catch (error) {
178 console.error('Failed to fetch OpenRouter providers for model', error);
179 refreshWarningState();
180 }
181}
182
104export async function loadOllamaModels(data) {183export async function loadOllamaModels(data) {
105 if (!Array.isArray(data)) {184 if (!Array.isArray(data)) {
106 console.error('Invalid Ollama models data', data);185 console.error('Invalid Ollama models data', data);
@@ -315,6 +394,7 @@ export async function loadOpenRouterModels(data) {
315394
316 // Calculate the cost of the selected model + update on settings change395 // Calculate the cost of the selected model + update on settings change
317 calculateOpenRouterCost();396 calculateOpenRouterCost();
397 syncOpenRouterProvidersForModel(textgen_settings.openrouter_model, '#openrouter_providers_text');
318}398}
319399
320export async function loadVllmModels(data) {400export async function loadVllmModels(data) {
@@ -675,6 +755,7 @@ function onOpenRouterModelSelect() {
675 textgen_settings.openrouter_model = modelId;755 textgen_settings.openrouter_model = modelId;
676 $('#api_button_textgenerationwebui').trigger('click');756 $('#api_button_textgenerationwebui').trigger('click');
677 const model = openRouterModels.find(x => x.id === modelId);757 const model = openRouterModels.find(x => x.id === modelId);
758 syncOpenRouterProvidersForModel(modelId, '#openrouter_providers_text');
678 setGenerationParamsFromPreset({ max_length: model.context_length });759 setGenerationParamsFromPreset({ max_length: model.context_length });
679}760}
680761
public/scripts/textgen-settings.js+6 -1
@@ -23,7 +23,7 @@ import { power_user, registerDebugFunction } from './power-user.js';
23import { getActiveManualApiSamplers, loadApiSelectedSamplers, isSamplerManualPriorityEnabled } from './samplerSelect.js';23import { getActiveManualApiSamplers, loadApiSelectedSamplers, isSamplerManualPriorityEnabled } from './samplerSelect.js';
24import { SECRET_KEYS, writeSecret } from './secrets.js';24import { SECRET_KEYS, writeSecret } from './secrets.js';
25import { getEventSourceStream } from './sse-stream.js';25import { getEventSourceStream } from './sse-stream.js';
26import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadLlamaCppModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels } from './textgen-models.js';26import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadLlamaCppModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels, updateOpenRouterProvidersWarning } from './textgen-models.js';
27import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, TOKENIZER_SUPPORTED_KEY, getTextTokens, getTokenizerBestMatch, tokenizers } from './tokenizers.js';27import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, TOKENIZER_SUPPORTED_KEY, getTextTokens, getTokenizerBestMatch, tokenizers } from './tokenizers.js';
28import { AbortReason } from './util/AbortReason.js';28import { AbortReason } from './util/AbortReason.js';
29import { getSortableDelay, onlyUnique, arraysEqual, isObject } from './utils.js';29import { getSortableDelay, onlyUnique, arraysEqual, isObject } from './utils.js';
@@ -1069,9 +1069,14 @@ export function initTextGenSettings() {
10691069
1070 textgenerationwebui_settings.openrouter_providers = selectedProviders;1070 textgenerationwebui_settings.openrouter_providers = selectedProviders;
10711071
1072 updateOpenRouterProvidersWarning('#openrouter_providers_text');
1072 saveSettingsDebounced();1073 saveSettingsDebounced();
1073 });1074 });
10741075
1076 $('#openrouter_allow_fallbacks_textgenerationwebui').on('input', function () {
1077 updateOpenRouterProvidersWarning('#openrouter_providers_text');
1078 });
1079
1075 $('#openrouter_quantizations_text').on('change', function () {1080 $('#openrouter_quantizations_text').on('change', function () {
1076 const selectedQuantizations = $(this).val();1081 const selectedQuantizations = $(this).val();
10771082