mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-07-06 17:31:16 -03:00
feat(ui): load provider model catalog asynchronously to avoid blocking page render
This commit is contained in:
@@ -38,7 +38,12 @@ from ...services.settings_manager import get_settings_manager
|
|||||||
from ...services.websocket_manager import ws_manager
|
from ...services.websocket_manager import ws_manager
|
||||||
from ...services.downloader import get_downloader
|
from ...services.downloader import get_downloader
|
||||||
from ...services.errors import ResourceNotFoundError
|
from ...services.errors import ResourceNotFoundError
|
||||||
from ...services.llm_service import get_provider_model_ids, fetch_ollama_models
|
from ...services.llm_service import (
|
||||||
|
PROVIDER_PRESETS,
|
||||||
|
fetch_ollama_models,
|
||||||
|
get_all_provider_models,
|
||||||
|
get_provider_model_ids,
|
||||||
|
)
|
||||||
from ...services.cache_health_monitor import CacheHealthMonitor, CacheHealthStatus
|
from ...services.cache_health_monitor import CacheHealthMonitor, CacheHealthStatus
|
||||||
from ...utils.models import BaseModelMetadata
|
from ...utils.models import BaseModelMetadata
|
||||||
from ...utils.constants import (
|
from ...utils.constants import (
|
||||||
@@ -1625,6 +1630,20 @@ class SettingsHandler:
|
|||||||
def _is_dedicated_example_images_folder(self, folder_path: str) -> bool:
|
def _is_dedicated_example_images_folder(self, folder_path: str) -> bool:
|
||||||
return is_valid_example_images_root(folder_path)
|
return is_valid_example_images_root(folder_path)
|
||||||
|
|
||||||
|
async def get_provider_models(self, request: web.Request) -> web.Response:
|
||||||
|
"""Return the model catalog for all preset providers.
|
||||||
|
|
||||||
|
This endpoint is called asynchronously by the settings UI so that
|
||||||
|
page rendering never blocks on the remote model catalog fetch.
|
||||||
|
"""
|
||||||
|
catalog_provider_ids = [p for p in PROVIDER_PRESETS if p != "custom"]
|
||||||
|
try:
|
||||||
|
provider_models = await get_all_provider_models(catalog_provider_ids)
|
||||||
|
return web.json_response({"success": True, "models": provider_models})
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning("Failed to fetch provider models: %s", exc)
|
||||||
|
return web.json_response({"success": False, "models": {}, "error": str(exc)})
|
||||||
|
|
||||||
|
|
||||||
class UsageStatsHandler:
|
class UsageStatsHandler:
|
||||||
def __init__(self, usage_stats_factory: UsageStatsFactory = UsageStats) -> None:
|
def __init__(self, usage_stats_factory: UsageStatsFactory = UsageStats) -> None:
|
||||||
@@ -3395,6 +3414,7 @@ class MiscHandlerSet:
|
|||||||
"get_settings_libraries": self.settings.get_libraries,
|
"get_settings_libraries": self.settings.get_libraries,
|
||||||
"activate_library": self.settings.activate_library,
|
"activate_library": self.settings.activate_library,
|
||||||
"get_llm_models": self.settings.get_llm_models,
|
"get_llm_models": self.settings.get_llm_models,
|
||||||
|
"get_provider_models": self.settings.get_provider_models,
|
||||||
"update_usage_stats": self.usage_stats.update_usage_stats,
|
"update_usage_stats": self.usage_stats.update_usage_stats,
|
||||||
"get_usage_stats": self.usage_stats.get_usage_stats,
|
"get_usage_stats": self.usage_stats.get_usage_stats,
|
||||||
"update_lora_code": self.lora_code.update_lora_code,
|
"update_lora_code": self.lora_code.update_lora_code,
|
||||||
|
|||||||
@@ -154,10 +154,13 @@ class ModelPageView:
|
|||||||
)
|
)
|
||||||
self._template_env._i18n_filter_added = True # type: ignore[attr-defined]
|
self._template_env._i18n_filter_added = True # type: ignore[attr-defined]
|
||||||
|
|
||||||
from ...services.llm_service import PROVIDER_PRESETS, get_all_provider_models
|
from ...services.llm_service import PROVIDER_PRESETS
|
||||||
|
|
||||||
catalog_provider_ids = [p for p in PROVIDER_PRESETS if p != "custom"]
|
# Provider presets are embedded directly (local, no await needed).
|
||||||
provider_models = await get_all_provider_models(catalog_provider_ids)
|
# Provider model catalogs are fetched asynchronously by the
|
||||||
|
# frontend via GET /api/lm/llm/provider-models so page rendering
|
||||||
|
# never blocks on the remote model catalog (which can take up to
|
||||||
|
# 30s on cold cache).
|
||||||
|
|
||||||
template_context = {
|
template_context = {
|
||||||
"is_initializing": is_initializing,
|
"is_initializing": is_initializing,
|
||||||
@@ -167,7 +170,7 @@ class ModelPageView:
|
|||||||
"t": self._server_i18n.get_translation,
|
"t": self._server_i18n.get_translation,
|
||||||
"version": self._get_app_version(),
|
"version": self._get_app_version(),
|
||||||
"provider_presets_json": json.dumps(PROVIDER_PRESETS),
|
"provider_presets_json": json.dumps(PROVIDER_PRESETS),
|
||||||
"provider_models_json": json.dumps(provider_models),
|
"provider_models_json": "{}",
|
||||||
}
|
}
|
||||||
|
|
||||||
if not is_initializing:
|
if not is_initializing:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ MISC_ROUTE_DEFINITIONS: tuple[RouteDefinition, ...] = (
|
|||||||
RouteDefinition("GET", "/api/lm/settings", "get_settings"),
|
RouteDefinition("GET", "/api/lm/settings", "get_settings"),
|
||||||
RouteDefinition("POST", "/api/lm/settings", "update_settings"),
|
RouteDefinition("POST", "/api/lm/settings", "update_settings"),
|
||||||
RouteDefinition("GET", "/api/lm/llm/models", "get_llm_models"),
|
RouteDefinition("GET", "/api/lm/llm/models", "get_llm_models"),
|
||||||
|
RouteDefinition("GET", "/api/lm/llm/provider-models", "get_provider_models"),
|
||||||
RouteDefinition("GET", "/api/lm/doctor/diagnostics", "get_doctor_diagnostics"),
|
RouteDefinition("GET", "/api/lm/doctor/diagnostics", "get_doctor_diagnostics"),
|
||||||
RouteDefinition("POST", "/api/lm/doctor/repair-cache", "repair_doctor_cache"),
|
RouteDefinition("POST", "/api/lm/doctor/repair-cache", "repair_doctor_cache"),
|
||||||
RouteDefinition("POST", "/api/lm/doctor/resolve-filename-conflicts", "resolve_doctor_filename_conflicts"),
|
RouteDefinition("POST", "/api/lm/doctor/resolve-filename-conflicts", "resolve_doctor_filename_conflicts"),
|
||||||
|
|||||||
@@ -789,6 +789,27 @@ export class SettingsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _fetchProviderModelsAsync() {
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/api/lm/llm/provider-models');
|
||||||
|
if (!resp.ok) return;
|
||||||
|
const data = await resp.json();
|
||||||
|
if (data.success && data.models) {
|
||||||
|
this._providerModels = data.models;
|
||||||
|
// Refresh model combobox if the settings modal is still open.
|
||||||
|
// Skip when provider is Ollama — it fetches its own live list
|
||||||
|
// from the local Ollama API and we must not overwrite it.
|
||||||
|
const llmProviderSelect = document.getElementById('llmProvider');
|
||||||
|
const provider = llmProviderSelect ? llmProviderSelect.value : 'openai';
|
||||||
|
if (this._llmModelCombobox && provider !== 'ollama') {
|
||||||
|
this._llmModelCombobox.updatePresets(this._providerModels[provider] || []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Silently ignore — models stay empty until next modal open
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async loadSettingsToUI() {
|
async loadSettingsToUI() {
|
||||||
// Set frontend settings from state
|
// Set frontend settings from state
|
||||||
const blurMatureContentCheckbox = document.getElementById('blurMatureContent');
|
const blurMatureContentCheckbox = document.getElementById('blurMatureContent');
|
||||||
@@ -850,6 +871,12 @@ export class SettingsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the embedded provider models is empty (server did not block on
|
||||||
|
// the remote catalog during page render), fetch asynchronously.
|
||||||
|
if (!this._providerModels || Object.keys(this._providerModels).length === 0) {
|
||||||
|
this._fetchProviderModelsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
const llmProviderSelect = document.getElementById('llmProvider');
|
const llmProviderSelect = document.getElementById('llmProvider');
|
||||||
if (llmProviderSelect) {
|
if (llmProviderSelect) {
|
||||||
llmProviderSelect.value = state.global.settings.llm_provider || 'openai';
|
llmProviderSelect.value = state.global.settings.llm_provider || 'openai';
|
||||||
|
|||||||
Reference in New Issue
Block a user