import { DOMPurify } from '../lib.js'; import { isMobile } from './RossAscends-mods.js'; import { amount_gen, callPopup, eventSource, event_types, getRequestHeaders, max_context, online_status, setGenerationParamsFromPreset } from '../script.js'; import { textgenerationwebui_settings as textgen_settings, textgen_types } from './textgen-settings.js'; import { tokenizers } from './tokenizers.js'; import { renderTemplateAsync } from './templates.js'; import { POPUP_TYPE, callGenericPopup } from './popup.js'; let mancerModels = []; let togetherModels = []; let infermaticAIModels = []; let dreamGenModels = []; let vllmModels = []; let aphroditeModels = []; let featherlessModels = []; let tabbyModels = []; export let openRouterModels = []; /** * List of OpenRouter providers. * @type {string[]} */ const OPENROUTER_PROVIDERS = [ 'OpenAI', 'Anthropic', 'Google', 'Google AI Studio', 'Groq', 'SambaNova', 'Cohere', 'Mistral', 'Together', 'Together 2', 'Fireworks', 'DeepInfra', 'Lepton', 'Novita', 'Avian', 'Lambda', 'Azure', 'Modal', 'AnyScale', 'Replicate', 'Perplexity', 'Recursal', 'OctoAI', 'DeepSeek', 'Infermatic', 'AI21', 'Featherless', 'Inflection', 'xAI', '01.AI', 'HuggingFace', 'Mancer', 'Mancer 2', 'Hyperbolic', 'Hyperbolic 2', 'Lynn 2', 'Lynn', 'Reflection', ]; export async function loadOllamaModels(data) { if (!Array.isArray(data)) { console.error('Invalid Ollama models data', data); return; } if (!data.find(x => x.id === textgen_settings.ollama_model)) { textgen_settings.ollama_model = data[0]?.id || ''; } $('#ollama_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.name; option.selected = model.id === textgen_settings.ollama_model; $('#ollama_model').append(option); } } export async function loadTabbyModels(data) { if (!Array.isArray(data)) { console.error('Invalid Tabby models data', data); return; } tabbyModels = data; tabbyModels.sort((a, b) => a.id.localeCompare(b.id)); tabbyModels.unshift({ id: '' }); if (!tabbyModels.find(x => x.id === textgen_settings.tabby_model)) { textgen_settings.tabby_model = tabbyModels[0]?.id || ''; } $('#tabby_model').empty(); for (const model of tabbyModels) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.tabby_model; $('#tabby_model').append(option); } } export async function loadTogetherAIModels(data) { if (!Array.isArray(data)) { console.error('Invalid Together AI models data', data); return; } data.sort((a, b) => a.name.localeCompare(b.name)); togetherModels = data; if (!data.find(x => x.name === textgen_settings.togetherai_model)) { textgen_settings.togetherai_model = data[0]?.name || ''; } $('#model_togetherai_select').empty(); for (const model of data) { // Hey buddy, I think you've got the wrong door. if (model.display_type === 'image') { continue; } const option = document.createElement('option'); option.value = model.name; option.text = model.display_name; option.selected = model.name === textgen_settings.togetherai_model; $('#model_togetherai_select').append(option); } } export async function loadInfermaticAIModels(data) { if (!Array.isArray(data)) { console.error('Invalid Infermatic AI models data', data); return; } data.sort((a, b) => a.id.localeCompare(b.id)); infermaticAIModels = data; if (!data.find(x => x.id === textgen_settings.infermaticai_model)) { textgen_settings.infermaticai_model = data[0]?.id || ''; } $('#model_infermaticai_select').empty(); for (const model of data) { if (model.display_type === 'image') { continue; } const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.infermaticai_model; $('#model_infermaticai_select').append(option); } } export function loadGenericModels(data) { if (!Array.isArray(data)) { console.error('Invalid Generic models data', data); return; } data.sort((a, b) => a.id.localeCompare(b.id)); const dataList = $('#generic_model_fill'); dataList.empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; dataList.append(option); } } export async function loadDreamGenModels(data) { if (!Array.isArray(data)) { console.error('Invalid DreamGen models data', data); return; } dreamGenModels = data; if (!data.find(x => x.id === textgen_settings.dreamgen_model)) { textgen_settings.dreamgen_model = data[0]?.id || ''; } $('#model_dreamgen_select').empty(); for (const model of data) { if (model.display_type === 'image') { continue; } const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.dreamgen_model; $('#model_dreamgen_select').append(option); } } export async function loadMancerModels(data) { if (!Array.isArray(data)) { console.error('Invalid Mancer models data', data); return; } data.sort((a, b) => a.name.localeCompare(b.name)); mancerModels = data; if (!data.find(x => x.id === textgen_settings.mancer_model)) { textgen_settings.mancer_model = data[0]?.id || ''; } $('#mancer_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.name; option.selected = model.id === textgen_settings.mancer_model; $('#mancer_model').append(option); } } export async function loadOpenRouterModels(data) { if (!Array.isArray(data)) { console.error('Invalid OpenRouter models data', data); return; } data.sort((a, b) => a.name.localeCompare(b.name)); openRouterModels = data; if (!data.find(x => x.id === textgen_settings.openrouter_model)) { textgen_settings.openrouter_model = data[0]?.id || ''; } $('#openrouter_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.openrouter_model; $('#openrouter_model').append(option); } // Calculate the cost of the selected model + update on settings change calculateOpenRouterCost(); } export async function loadVllmModels(data) { if (!Array.isArray(data)) { console.error('Invalid vLLM models data', data); return; } vllmModels = data; if (!data.find(x => x.id === textgen_settings.vllm_model)) { textgen_settings.vllm_model = data[0]?.id || ''; } $('#vllm_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.vllm_model; $('#vllm_model').append(option); } } export async function loadAphroditeModels(data) { if (!Array.isArray(data)) { console.error('Invalid Aphrodite models data', data); return; } aphroditeModels = data; if (!data.find(x => x.id === textgen_settings.aphrodite_model)) { textgen_settings.aphrodite_model = data[0]?.id || ''; } $('#aphrodite_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.aphrodite_model; $('#aphrodite_model').append(option); } } let featherlessCurrentPage = 1; export async function loadFeatherlessModels(data) { const searchBar = document.getElementById('featherless_model_search_bar'); const modelCardBlock = document.getElementById('featherless_model_card_block'); const paginationContainer = $('#featherless_model_pagination_container'); const sortOrderSelect = document.getElementById('featherless_model_sort_order'); const classSelect = document.getElementById('featherless_class_selection'); const categoriesSelect = document.getElementById('featherless_category_selection'); const storageKey = 'FeatherlessModels_PerPage'; // Store the original models data for search and filtering let originalModels = []; if (!Array.isArray(data)) { console.error('Invalid Featherless models data', data); return; } // Sort the data by model id (default A-Z) data.sort((a, b) => a.id.localeCompare(b.id)); originalModels = data; // Store the original data for search featherlessModels = data; if (!data.find(x => x.id === textgen_settings.featherless_model)) { textgen_settings.featherless_model = data[0]?.id || ''; } // Populate class select options with unique classes populateClassSelection(data); // Retrieve the stored number of items per page or default to 10 const perPage = Number(localStorage.getItem(storageKey)) || 10; // Initialize pagination with the full set of models const currentModelIndex = data.findIndex(x => x.id === textgen_settings.featherless_model); featherlessCurrentPage = currentModelIndex >= 0 ? (currentModelIndex / perPage) + 1 : 1; setupPagination(originalModels, perPage); // Function to set up pagination (also used for filtered results) function setupPagination(models, perPage, pageNumber = featherlessCurrentPage) { paginationContainer.pagination({ dataSource: models, pageSize: perPage, pageNumber: pageNumber, sizeChangerOptions: [6, 10, 26, 50, 100, 250, 500, 1000], pageRange: 1, showPageNumbers: true, showSizeChanger: false, prevText: '<', nextText: '>', formatNavigator: function (currentPage, totalPage) { return (currentPage - 1) * perPage + 1 + ' - ' + currentPage * perPage + ' of ' + totalPage * perPage; }, showNavigator: true, callback: function (modelsOnPage, pagination) { modelCardBlock.innerHTML = ''; modelsOnPage.forEach(model => { const card = document.createElement('div'); card.classList.add('model-card'); const modelNameContainer = document.createElement('div'); modelNameContainer.classList.add('model-name-container'); const modelTitle = document.createElement('div'); modelTitle.classList.add('model-title'); modelTitle.textContent = model.id.replace(/_/g, '_\u200B'); modelNameContainer.appendChild(modelTitle); const detailsContainer = document.createElement('div'); detailsContainer.classList.add('details-container'); const modelClassDiv = document.createElement('div'); modelClassDiv.classList.add('model-class'); modelClassDiv.textContent = `Class: ${model.model_class || 'N/A'}`; const contextLengthDiv = document.createElement('div'); contextLengthDiv.classList.add('model-context-length'); contextLengthDiv.textContent = `Context Length: ${model.context_length}`; const dateAddedDiv = document.createElement('div'); dateAddedDiv.classList.add('model-date-added'); dateAddedDiv.textContent = `Added On: ${new Date(model.updated_at).toLocaleDateString()}`; detailsContainer.appendChild(modelClassDiv); detailsContainer.appendChild(contextLengthDiv); detailsContainer.appendChild(dateAddedDiv); card.appendChild(modelNameContainer); card.appendChild(detailsContainer); modelCardBlock.appendChild(card); if (model.id === textgen_settings.featherless_model) { card.classList.add('selected'); } card.addEventListener('click', function () { document.querySelectorAll('.model-card').forEach(c => c.classList.remove('selected')); card.classList.add('selected'); onFeatherlessModelSelect(model.id); }); }); // Update the current page value whenever the page changes featherlessCurrentPage = pagination.pageNumber; }, afterSizeSelectorChange: function (e) { const newPerPage = e.target.value; localStorage.setItem('Models_PerPage', newPerPage); setupPagination(models, Number(newPerPage), featherlessCurrentPage); // Use the stored current page number }, }); } // Unset previously added listeners $(searchBar).off('input'); $(sortOrderSelect).off('change'); $(classSelect).off('change'); $(categoriesSelect).off('change'); // Add event listener for input on the search bar searchBar.addEventListener('input', function () { applyFiltersAndSort(); }); // Add event listener for the sort order select sortOrderSelect.addEventListener('change', function () { applyFiltersAndSort(); }); // Add event listener for the class select classSelect.addEventListener('change', function () { applyFiltersAndSort(); }); categoriesSelect.addEventListener('change', function () { applyFiltersAndSort(); }); // Function to populate class selection dropdown function populateClassSelection(models) { const uniqueClasses = [...new Set(models.map(model => model.model_class).filter(Boolean))]; // Get unique class names uniqueClasses.sort((a, b) => a.localeCompare(b)); uniqueClasses.forEach(className => { const option = document.createElement('option'); option.value = className; option.textContent = className; classSelect.appendChild(option); }); } // Function to apply sorting and filtering based on user input async function applyFiltersAndSort() { if (!(searchBar instanceof HTMLInputElement) || !(sortOrderSelect instanceof HTMLSelectElement) || !(classSelect instanceof HTMLSelectElement) || !(categoriesSelect instanceof HTMLSelectElement)) { return; } const searchQuery = searchBar.value.toLowerCase(); const selectedSortOrder = sortOrderSelect.value; const selectedClass = classSelect.value; const selectedCategory = categoriesSelect.value; let featherlessTop = []; let featherlessNew = []; if (selectedCategory === 'Top') { featherlessTop = await fetchFeatherlessStats(); } const featherlessIds = featherlessTop.map(stat => stat.id); if (selectedCategory === 'New') { featherlessNew = await fetchFeatherlessNew(); } const featherlessNewIds = featherlessNew.map(stat => stat.id); let filteredModels = originalModels.filter(model => { const matchesSearch = model.id.toLowerCase().includes(searchQuery); const matchesClass = selectedClass ? model.model_class === selectedClass : true; const matchesTop = featherlessIds.includes(model.id); const matchesNew = featherlessNewIds.includes(model.id); if (selectedCategory === 'All') { return matchesSearch && matchesClass; } else if (selectedCategory === 'Top') { return matchesSearch && matchesClass && matchesTop; } else if (selectedCategory === 'New') { return matchesSearch && matchesClass && matchesNew; } else { return matchesSearch; } }); if (selectedSortOrder === 'asc') { filteredModels.sort((a, b) => a.id.localeCompare(b.id)); } else if (selectedSortOrder === 'desc') { filteredModels.sort((a, b) => b.id.localeCompare(a.id)); } else if (selectedSortOrder === 'date_asc') { filteredModels.sort((a, b) => a.updated_at.localeCompare(b.updated_at)); } else if (selectedSortOrder === 'date_desc') { filteredModels.sort((a, b) => b.updated_at.localeCompare(a.updated_at)); } setupPagination(filteredModels, Number(localStorage.getItem(storageKey)) || perPage, featherlessCurrentPage); } // Required to keep the /model command function $('#featherless_model').empty(); for (const model of data) { const option = document.createElement('option'); option.value = model.id; option.text = model.id; option.selected = model.id === textgen_settings.featherless_model; $('#featherless_model').append(option); } } async function fetchFeatherlessStats() { const response = await fetch('https://api.featherless.ai/feather/popular'); const data = await response.json(); return data.popular; } async function fetchFeatherlessNew() { const response = await fetch('https://api.featherless.ai/feather/models?sort=-created_at&perPage=10'); const data = await response.json(); return data.items; } function onFeatherlessModelSelect(modelId) { const model = featherlessModels.find(x => x.id === modelId); textgen_settings.featherless_model = modelId; $('#featherless_model').val(modelId); $('#api_button_textgenerationwebui').trigger('click'); setGenerationParamsFromPreset({ max_length: model.context_length }); } let featherlessIsGridView = false; // Default state set to grid view // Ensure the correct initial view is applied when the page loads document.addEventListener('DOMContentLoaded', function () { const modelCardBlock = document.getElementById('featherless_model_card_block'); modelCardBlock.classList.add('list-view'); const toggleButton = document.getElementById('featherless_model_grid_toggle'); toggleButton.addEventListener('click', function () { // Toggle between grid and list view if (featherlessIsGridView) { modelCardBlock.classList.remove('grid-view'); modelCardBlock.classList.add('list-view'); this.title = 'Toggle to grid view'; } else { modelCardBlock.classList.remove('list-view'); modelCardBlock.classList.add('grid-view'); this.title = 'Toggle to list view'; } featherlessIsGridView = !featherlessIsGridView; }); }); function onMancerModelSelect() { const modelId = String($('#mancer_model').val()); textgen_settings.mancer_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); const limits = mancerModels.find(x => x.id === modelId)?.limits; setGenerationParamsFromPreset({ max_length: limits.context }); } function onTogetherModelSelect() { const modelName = String($('#model_togetherai_select').val()); textgen_settings.togetherai_model = modelName; $('#api_button_textgenerationwebui').trigger('click'); const model = togetherModels.find(x => x.name === modelName); setGenerationParamsFromPreset({ max_length: model.context_length }); } function onInfermaticAIModelSelect() { const modelName = String($('#model_infermaticai_select').val()); textgen_settings.infermaticai_model = modelName; $('#api_button_textgenerationwebui').trigger('click'); const model = infermaticAIModels.find(x => x.id === modelName); setGenerationParamsFromPreset({ max_length: model.context_length }); } function onDreamGenModelSelect() { const modelName = String($('#model_dreamgen_select').val()); textgen_settings.dreamgen_model = modelName; $('#api_button_textgenerationwebui').trigger('click'); // TODO(DreamGen): Consider retuning max_tokens from API and setting it here. } function onOllamaModelSelect() { const modelId = String($('#ollama_model').val()); textgen_settings.ollama_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); } function onTabbyModelSelect() { const modelId = String($('#tabby_model').val()); textgen_settings.tabby_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); } function onOpenRouterModelSelect() { const modelId = String($('#openrouter_model').val()); textgen_settings.openrouter_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); const model = openRouterModels.find(x => x.id === modelId); setGenerationParamsFromPreset({ max_length: model.context_length }); } function onVllmModelSelect() { const modelId = String($('#vllm_model').val()); textgen_settings.vllm_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); } function onAphroditeModelSelect() { const modelId = String($('#aphrodite_model').val()); textgen_settings.aphrodite_model = modelId; $('#api_button_textgenerationwebui').trigger('click'); } function getMancerModelTemplate(option) { const model = mancerModels.find(x => x.id === option?.element?.value); if (!option.id || !model) { return option.text; } const creditsPerPrompt = (model.limits?.context - model.limits?.completion) * model.pricing?.prompt; const creditsPerCompletion = model.limits?.completion * model.pricing?.completion; const creditsTotal = Math.round(creditsPerPrompt + creditsPerCompletion).toFixed(0); return $((`
llama2:latest
.