| 266 | } | 266 | } |
| 267 | | 267 | |
| 268 | export async function loadFeatherlessModels(data) { | 268 | export async function loadFeatherlessModels(data) { |
| | 269 | const searchBar = document.getElementById('model_search_bar'); |
| | 270 | const modelCardBlock = document.getElementById('model_card_block'); |
| | 271 | const paginationContainer = $('#model_pagination_container'); |
| | 272 | const sortOrderSelect = document.getElementById('model_sort_order'); |
| | 273 | const classSelect = document.getElementById('class_selection'); |
| | 274 | const storageKey = 'Models_PerPage'; |
| | 275 | |
| | 276 | // Store the original models data for search and filtering |
| | 277 | let originalModels = []; |
| | 278 | |
| 269 | if (!Array.isArray(data)) { | 279 | if (!Array.isArray(data)) { |
| 270 | console.error('Invalid Featherless models data', data); | 280 | console.error('Invalid Featherless models data', data); |
| 271 | return; | 281 | return; |
| 272 | } | 282 | } |
| 273 | | 283 | |
| | 284 | // Sort the data by model id (default A-Z) |
| 274 | data.sort((a, b) => a.id.localeCompare(b.id)); | 285 | data.sort((a, b) => a.id.localeCompare(b.id)); |
| 275 | featherlessModels = data; | 286 | originalModels = data; // Store the original data for search |
| 276 | | 287 | |
| 277 | if (!data.find(x => x.id === textgen_settings.featherless_model)) { | 288 | // Populate class select options with unique classes |
| 278 | textgen_settings.featherless_model = data[0]?.id || ''; | 289 | populateClassSelection(data); |
| | 290 | |
| | 291 | // Retrieve the stored number of items per page or default to 5 |
| | 292 | const perPage = Number(localStorage.getItem(storageKey)) || 5; |
| | 293 | |
| | 294 | // Initialize pagination with the full set of models |
| | 295 | setupPagination(originalModels, perPage); |
| | 296 | |
| | 297 | // Function to set up pagination (also used for filtered results) |
| | 298 | function setupPagination(models, perPage) { |
| | 299 | paginationContainer.pagination({ |
| | 300 | dataSource: models, |
| | 301 | pageSize: perPage, |
| | 302 | sizeChangerOptions: [5, 10, 25, 50, 100, 250, 500, 1000], |
| | 303 | pageRange: 1, |
| | 304 | pageNumber: 1, |
| | 305 | showPageNumbers: true, |
| | 306 | showSizeChanger: true, |
| | 307 | prevText: '<', |
| | 308 | nextText: '>', |
| | 309 | formatNavigator: function (currentPage, totalPage) { |
| | 310 | return 'Page ' + currentPage + ' of ' + totalPage; |
| | 311 | }, |
| | 312 | showNavigator: true, |
| | 313 | callback: function (modelsOnPage) { |
| | 314 | // Clear the model card block before adding new cards |
| | 315 | modelCardBlock.innerHTML = ''; |
| | 316 | |
| | 317 | // Loop through the models for the current page and create cards |
| | 318 | modelsOnPage.forEach(model => { |
| | 319 | const card = document.createElement('div'); |
| | 320 | card.classList.add('model-card'); |
| | 321 | |
| | 322 | const modelNameContainer = document.createElement('div'); |
| | 323 | modelNameContainer.classList.add('model-name-container'); |
| | 324 | |
| | 325 | const modelTitle = document.createElement('div'); |
| | 326 | modelTitle.classList.add('model-title'); |
| | 327 | modelTitle.textContent = model.id; |
| | 328 | modelNameContainer.appendChild(modelTitle); |
| | 329 | |
| | 330 | const detailsContainer = document.createElement('div'); |
| | 331 | detailsContainer.classList.add('details-container'); |
| | 332 | |
| | 333 | const modelClassDiv = document.createElement('div'); |
| | 334 | modelClassDiv.classList.add('model-class'); |
| | 335 | modelClassDiv.textContent = `Class: ${model.model_class || 'N/A'}`; |
| | 336 | |
| | 337 | const contextLengthDiv = document.createElement('div'); |
| | 338 | contextLengthDiv.classList.add('model-context-length'); |
| | 339 | contextLengthDiv.textContent = `Context Length: ${model.context_length}`; |
| | 340 | |
| | 341 | detailsContainer.appendChild(modelClassDiv); |
| | 342 | detailsContainer.appendChild(contextLengthDiv); |
| | 343 | |
| | 344 | card.appendChild(modelNameContainer); |
| | 345 | card.appendChild(detailsContainer); |
| | 346 | |
| | 347 | // Append the card to the container |
| | 348 | modelCardBlock.appendChild(card); |
| | 349 | |
| | 350 | // Check if this card is the currently selected model |
| | 351 | if (model.id === selectedModelId) { |
| | 352 | card.classList.add('selected'); // Keep the selected class if it's the same model |
| | 353 | } |
| | 354 | |
| | 355 | // Add click event listener to the card |
| | 356 | card.addEventListener('click', function() { |
| | 357 | // Remove the selected class from all other cards |
| | 358 | document.querySelectorAll('.model-card').forEach(c => c.classList.remove('selected')); |
| | 359 | |
| | 360 | // Add the selected class to the clicked card |
| | 361 | card.classList.add('selected'); |
| | 362 | |
| | 363 | // Call the onFeatherlessModelSelect function with the selected model ID |
| | 364 | onFeatherlessModelSelect(model.id); |
| | 365 | }); |
| | 366 | }); |
| | 367 | }, |
| | 368 | afterSizeSelectorChange: function (e) { |
| | 369 | const newPerPage = e.target.value; |
| | 370 | localStorage.setItem('Models_PerPage', newPerPage); // Save the new value in localStorage |
| | 371 | setupPagination(models, Number(newPerPage)); // Reinitialize pagination with the new per page value |
| | 372 | }, |
| | 373 | }); |
| 279 | } | 374 | } |
| 280 | | 375 | |
| 281 | $('#featherless_model').empty(); | 376 | // Add event listener for input on the search bar |
| 282 | for (const model of data) { | 377 | searchBar.addEventListener('input', function() { |
| | 378 | applyFiltersAndSort(); |
| | 379 | }); |
| | 380 | |
| | 381 | // Add event listener for the sort order select |
| | 382 | sortOrderSelect.addEventListener('change', function() { |
| | 383 | applyFiltersAndSort(); |
| | 384 | }); |
| | 385 | |
| | 386 | // Add event listener for the class select |
| | 387 | classSelect.addEventListener('change', function() { |
| | 388 | applyFiltersAndSort(); |
| | 389 | }); |
| | 390 | |
| | 391 | // Function to populate class selection dropdown |
| | 392 | function populateClassSelection(models) { |
| | 393 | const uniqueClasses = [...new Set(models.map(model => model.model_class).filter(Boolean))]; // Get unique class names |
| | 394 | uniqueClasses.forEach(className => { |
| 283 | const option = document.createElement('option'); | 395 | const option = document.createElement('option'); |
| 284 | option.value = model.id; | 396 | option.value = className; |
| 285 | option.text = model.id; | 397 | option.textContent = className; |
| 286 | option.selected = model.id === textgen_settings.featherless_model; | 398 | classSelect.appendChild(option); |
| 287 | $('#featherless_model').append(option); | 399 | }); |
| 288 | } | 400 | } |
| | 401 | |
| | 402 | // Function to apply sorting and filtering based on user input |
| | 403 | function applyFiltersAndSort() { |
| | 404 | const searchQuery = searchBar.value.toLowerCase(); |
| | 405 | const selectedSortOrder = sortOrderSelect.value; |
| | 406 | const selectedClass = classSelect.value; |
| | 407 | |
| | 408 | // Filter the models based on the search query and selected class |
| | 409 | let filteredModels = originalModels.filter(model => { |
| | 410 | const matchesSearch = model.id.toLowerCase().includes(searchQuery); |
| | 411 | const matchesClass = selectedClass ? model.model_class === selectedClass : true; |
| | 412 | return matchesSearch && matchesClass; |
| | 413 | }); |
| | 414 | |
| | 415 | // Sort the filtered models based on selected sort order (A-Z or Z-A) |
| | 416 | if (selectedSortOrder === 'asc') { |
| | 417 | filteredModels.sort((a, b) => a.id.localeCompare(b.id)); |
| | 418 | } else if (selectedSortOrder === 'desc') { |
| | 419 | filteredModels.sort((a, b) => b.id.localeCompare(a.id)); |
| 289 | } | 420 | } |
| 290 | | 421 | |
| 291 | function onFeatherlessModelSelect() { | 422 | // Reinitialize pagination with the filtered and sorted models |
| 292 | const modelId = String($('#featherless_model').val()); | 423 | setupPagination(filteredModels, Number(localStorage.getItem(storageKey)) || perPage); |
| | 424 | } |
| | 425 | } |
| | 426 | |
| | 427 | let selectedModelId = null; |
| | 428 | function onFeatherlessModelSelect(modelId) { |
| | 429 | // Find the selected model and set the settings |
| | 430 | const model = featherlessModels.find(x => x.id === modelId); |
| 293 | textgen_settings.featherless_model = modelId; | 431 | textgen_settings.featherless_model = modelId; |
| 294 | $('#api_button_textgenerationwebui').trigger('click'); | 432 | $('#api_button_textgenerationwebui').trigger('click'); |
| 295 | const model = featherlessModels.find(x => x.id === modelId); | | |
| 296 | setGenerationParamsFromPreset({ max_length: model.context_length }); | 433 | setGenerationParamsFromPreset({ max_length: model.context_length }); |
| | 434 | selectedModelId = modelId; // Store the selected model ID |
| 297 | } | 435 | } |
| 298 | | | |
| 299 | | | |
| 300 | function onMancerModelSelect() { | 436 | function onMancerModelSelect() { |
| 301 | const modelId = String($('#mancer_model').val()); | 437 | const modelId = String($('#mancer_model').val()); |
| 302 | textgen_settings.mancer_model = modelId; | 438 | textgen_settings.mancer_model = modelId; |