mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-05 09:35:31 -03:00
The owner could not tell from the UI what "Buzz Price Tracking" enabled, what the "Price alert threshold" number meant, or what "Price Alerts" was alerting about. That was not a copy problem: the implementation exposed our mechanism (a page scrape) and our SQL predicates as the user's concepts. Two concrete defects came from the same root: - the alert population included versions the user already owns (neither the event generator nor the query filtered on is_in_library; in the owner's library 28 of 52 gated versions were already downloaded, so most "alerts" were about files already on disk, which cannot become cheaper *for them*); - a threshold-filtered state list lived in a notification surface, so an empty panel had three indistinguishable causes and read as a broken feature. The information model is now the version plus ownership: cost is shown only where a decision exists. Owned -> nothing. Not owned and free -> nothing. Not owned and gated -> the price when it is known, `Paid` without a number when it is not, and early access keeps its countdown because "free on <date>" decides between waiting and paying. The numeric threshold has no place in that model: every decision is categorical (wait / pay / skip), so the setting, the comparison and the whole alert-state machine are gone. - both alert-state columns are removed from the schema rather than left dead; a database created by an unreleased build has them dropped on open (native ALTER TABLE ... DROP COLUMN, guarded), which is a no-op for everyone else - gate events are emitted only for versions the user does not have, and the price-drop event goes with the threshold it belonged to - both alert endpoints, PriceAlertsHandler and the service-registry adapter field it needed are removed: events already reach the UI through the refresh response - the bell tab, panel, CSS, both entry points, the unread watermark and their locales are removed; the setting keeps only the enable flag and the refresh interval and is framed as plumbing - "Price unavailable" is replaced by `Paid`: the gate is certain from the public API, only the number is best-effort, and that is our plumbing, not the user's problem Verified against a copy of the owner's real database: 52 gated versions -> 28 owned (now silent) + 24 the feature is actually about; the drop migration ran and both removed endpoints 404.
174 lines
6.5 KiB
Python
174 lines
6.5 KiB
Python
"""Route controller for miscellaneous endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from typing import Awaitable, Callable, Mapping
|
|
|
|
from aiohttp import web
|
|
from server import PromptServer # pyright: ignore[reportMissingImports]
|
|
|
|
from ..services.metadata_service import (
|
|
get_metadata_archive_manager,
|
|
get_metadata_provider,
|
|
update_metadata_providers,
|
|
)
|
|
from ..services.settings_manager import get_settings_manager
|
|
from ..services.downloader import get_downloader
|
|
from ..utils.usage_stats import UsageStats
|
|
from .handlers.misc_handlers import (
|
|
CustomWordsHandler,
|
|
DoctorHandler,
|
|
ExampleWorkflowsHandler,
|
|
FileSystemHandler,
|
|
HealthCheckHandler,
|
|
LoraCodeHandler,
|
|
BackupHandler,
|
|
MetadataArchiveHandler,
|
|
MiscHandlerSet,
|
|
ModelExampleFilesHandler,
|
|
ModelLibraryHandler,
|
|
NodeRegistry,
|
|
NodeRegistryHandler,
|
|
SettingsHandler,
|
|
SidecarMigrationHandler,
|
|
SupportersHandler,
|
|
TrainedWordsHandler,
|
|
UsageStatsHandler,
|
|
WildcardsHandler,
|
|
build_service_registry_adapter,
|
|
)
|
|
from .handlers.base_model_handlers import BaseModelHandlerSet
|
|
from .handlers.model_source_handlers import ModelSourceHandler
|
|
from .handlers.agent_handlers import AgentHandler
|
|
from .handlers.download_routing_handlers import DownloadRoutingHandler
|
|
from .misc_route_registrar import MiscRouteRegistrar
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
standalone_mode = (
|
|
os.environ.get("LORA_MANAGER_STANDALONE", "0") == "1"
|
|
or os.environ.get("HF_HUB_DISABLE_TELEMETRY", "0") == "0"
|
|
)
|
|
|
|
|
|
class MiscRoutes:
|
|
"""Route controller that mirrors the model route architecture."""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
settings_service=None,
|
|
usage_stats_factory: Callable[[], UsageStats] = UsageStats,
|
|
prompt_server: type[PromptServer] = PromptServer,
|
|
service_registry_adapter=build_service_registry_adapter(),
|
|
metadata_provider_factory=get_metadata_provider,
|
|
metadata_archive_manager_factory=get_metadata_archive_manager,
|
|
metadata_provider_updater=update_metadata_providers,
|
|
downloader_factory=get_downloader,
|
|
registrar_factory=MiscRouteRegistrar,
|
|
handler_set_factory=MiscHandlerSet,
|
|
node_registry: NodeRegistry | None = None,
|
|
standalone_mode_flag: bool = standalone_mode,
|
|
) -> None:
|
|
self._settings = settings_service or get_settings_manager()
|
|
self._usage_stats_factory = usage_stats_factory
|
|
self._prompt_server = prompt_server
|
|
self._service_registry_adapter = service_registry_adapter
|
|
self._metadata_provider_factory = metadata_provider_factory
|
|
self._metadata_archive_manager_factory = metadata_archive_manager_factory
|
|
self._metadata_provider_updater = metadata_provider_updater
|
|
self._downloader_factory = downloader_factory
|
|
self._registrar_factory = registrar_factory
|
|
self._handler_set_factory = handler_set_factory
|
|
self._node_registry = node_registry or NodeRegistry()
|
|
self._standalone_mode = standalone_mode_flag
|
|
|
|
self._handler_mapping: (
|
|
Mapping[str, Callable[[web.Request], Awaitable[web.StreamResponse]]] | None
|
|
) = None
|
|
|
|
@staticmethod
|
|
def setup_routes(app: web.Application) -> None:
|
|
"""Entry point used by the application bootstrap."""
|
|
controller = MiscRoutes()
|
|
controller.bind(app)
|
|
|
|
def bind(self, app: web.Application) -> None:
|
|
registrar = self._registrar_factory(app)
|
|
registrar.register_routes(self._ensure_handler_mapping())
|
|
|
|
def _ensure_handler_mapping(
|
|
self,
|
|
) -> Mapping[str, Callable[[web.Request], Awaitable[web.StreamResponse]]]:
|
|
if self._handler_mapping is None:
|
|
handler_set = self._create_handler_set()
|
|
self._handler_mapping = handler_set.to_route_mapping()
|
|
return self._handler_mapping
|
|
|
|
def _create_handler_set(self) -> MiscHandlerSet:
|
|
health = HealthCheckHandler()
|
|
settings_handler = SettingsHandler(
|
|
settings_service=self._settings,
|
|
metadata_provider_updater=self._metadata_provider_updater,
|
|
downloader_factory=self._downloader_factory,
|
|
)
|
|
usage_stats = UsageStatsHandler(usage_stats_factory=self._usage_stats_factory)
|
|
lora_code = LoraCodeHandler(prompt_server=self._prompt_server)
|
|
trained_words = TrainedWordsHandler()
|
|
model_examples = ModelExampleFilesHandler()
|
|
metadata_archive = MetadataArchiveHandler(
|
|
metadata_archive_manager_factory=self._metadata_archive_manager_factory,
|
|
settings_service=self._settings,
|
|
metadata_provider_updater=self._metadata_provider_updater,
|
|
)
|
|
backup = BackupHandler()
|
|
filesystem = FileSystemHandler(settings_service=self._settings)
|
|
node_registry_handler = NodeRegistryHandler(
|
|
node_registry=self._node_registry,
|
|
prompt_server=self._prompt_server,
|
|
standalone_mode=self._standalone_mode,
|
|
)
|
|
model_library = ModelLibraryHandler(
|
|
service_registry=self._service_registry_adapter,
|
|
metadata_provider_factory=self._metadata_provider_factory,
|
|
)
|
|
custom_words = CustomWordsHandler()
|
|
wildcards = WildcardsHandler()
|
|
supporters = SupportersHandler()
|
|
doctor = DoctorHandler(settings_service=self._settings)
|
|
example_workflows = ExampleWorkflowsHandler()
|
|
base_model = BaseModelHandlerSet()
|
|
model_source_handler = ModelSourceHandler()
|
|
agent_handler = AgentHandler()
|
|
download_routing = DownloadRoutingHandler()
|
|
sidecar_migration = SidecarMigrationHandler()
|
|
|
|
return self._handler_set_factory(
|
|
health=health,
|
|
settings=settings_handler,
|
|
usage_stats=usage_stats,
|
|
lora_code=lora_code,
|
|
trained_words=trained_words,
|
|
model_examples=model_examples,
|
|
node_registry=node_registry_handler,
|
|
model_library=model_library,
|
|
metadata_archive=metadata_archive,
|
|
backup=backup,
|
|
filesystem=filesystem,
|
|
custom_words=custom_words,
|
|
wildcards=wildcards,
|
|
supporters=supporters,
|
|
doctor=doctor,
|
|
example_workflows=example_workflows,
|
|
base_model=base_model,
|
|
model_source_handler=model_source_handler,
|
|
agent_handler=agent_handler,
|
|
download_routing=download_routing,
|
|
sidecar_migration=sidecar_migration,
|
|
)
|
|
|
|
|
|
__all__ = ["MiscRoutes"]
|