A node's "Mark this state" keeps the serialized canvas as a mark in a bar under it. A mark's number goes back to that state, each has its runs, and seeds are Random or Locked (one per round, shared by the marks; a fixed seed alone would come from ComfyUI's cache). Run checks every mark with validate_prompt first, then compiles detached copies with their seeds written, so the canvas and its seeds stay as they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
156 lines
10 KiB
Python
156 lines
10 KiB
Python
from . import (
|
|
activity_log, audio_catalog, folder_types, gallery_routes, materials, media_routes, model_catalog,
|
|
model_folder, model_media, model_metadata, model_resolution, model_type_listing, kept_images, quick_index, node_material, recipe_packages, recipes, scan_choice, scan_report, scan_summary,
|
|
local_guard, lora_info, mcp_server, model_download, model_import, model_placement, translation_routes, version_manager, tts_version, backup,
|
|
network_check, model_heads, model_usage, usage_ledger, sidecar_layout, ai_tasks_routes, snapshot_routes,
|
|
)
|
|
from .scanner import *
|
|
from .config import *
|
|
from .notebooks import *
|
|
from .parameters import *
|
|
|
|
import os
|
|
|
|
from aiohttp import web
|
|
|
|
# ComfyUI serves the web folder under the plugin folder's own name, whatever it is called.
|
|
EXTENSION_STATIC_PREFIX = f'/extensions/{os.path.basename(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))}/'
|
|
|
|
|
|
@web.middleware
|
|
async def no_cache_extension_middleware(request, handler):
|
|
"""Make browsers revalidate this plugin's JS/CSS so a normal refresh picks up updates.
|
|
|
|
`no-cache` still allows 304 responses via ETag/Last-Modified. This replaces
|
|
per-import `?v=` query strings, which load a second module instance whenever
|
|
two files import the same module with different URLs.
|
|
"""
|
|
response = await handler(request)
|
|
if request.path.startswith(EXTENSION_STATIC_PREFIX):
|
|
response.headers['Cache-Control'] = 'no-cache'
|
|
return response
|
|
|
|
def setup_routes(app):
|
|
model_heads.keep_on_disk()
|
|
if hasattr(app, 'middlewares') and no_cache_extension_middleware not in app.middlewares:
|
|
app.middlewares.append(no_cache_extension_middleware)
|
|
# Other devices on the network may look; only this computer may change things (local_guard.py).
|
|
if hasattr(app, 'middlewares') and local_guard.local_only_middleware not in app.middlewares:
|
|
app.middlewares.append(local_guard.local_only_middleware)
|
|
app.router.add_get('/anomalous/access', local_guard.api_access)
|
|
app.router.add_post('/anomalous/snapshot_check', snapshot_routes.api_snapshot_check)
|
|
try:
|
|
folder_types.upgrade_folder_defaults()
|
|
except Exception as error:
|
|
print(f"[Anomalous Browser] Could not update the shown model folders: {error}")
|
|
app.router.add_get('/anomalous/folders', model_catalog.api_get_folders)
|
|
app.router.add_get('/anomalous/all_folder_types', folder_types.api_get_all_folder_types)
|
|
app.router.add_get('/anomalous/models', model_catalog.api_get_models)
|
|
app.router.add_get('/anomalous/type_models', model_type_listing.api_get_type_models)
|
|
app.router.add_get('/anomalous/all_scan_models', model_catalog.api_get_all_scan_models)
|
|
app.router.add_get('/anomalous/image', media_routes.api_serve_image)
|
|
app.router.add_get('/anomalous/card_cache', media_routes.api_card_cache)
|
|
app.router.add_post('/anomalous/card_cache/clear', media_routes.api_clear_card_cache)
|
|
app.router.add_post('/anomalous/scan', api_scan_folder)
|
|
app.router.add_get('/anomalous/scan_status', api_scan_status)
|
|
app.router.add_get('/anomalous/find_model', model_catalog.api_find_model)
|
|
app.router.add_get('/anomalous/config', api_get_config)
|
|
app.router.add_post('/anomalous/save_config', api_save_config)
|
|
app.router.add_post('/anomalous/delete_model', model_metadata.api_delete_model)
|
|
app.router.add_post('/anomalous/open_model_folder', model_folder.api_open_model_folder)
|
|
app.router.add_get('/anomalous/compatible_models', model_catalog.api_compatible_models)
|
|
app.router.add_get('/anomalous/notebooks', api_get_notebooks)
|
|
app.router.add_post('/anomalous/save_notebook', api_save_notebook)
|
|
app.router.add_post('/anomalous/delete_notebook', api_delete_notebook)
|
|
|
|
# Parameter Routes
|
|
app.router.add_get('/anomalous/parameters', api_get_parameters)
|
|
app.router.add_get('/anomalous/parameters/by_node_type', api_get_parameters_by_type)
|
|
app.router.add_get('/anomalous/parameters/signatures', api_get_parameter_set_signatures)
|
|
app.router.add_post('/anomalous/save_parameter', api_save_parameter)
|
|
app.router.add_post('/anomalous/rename_parameter', api_rename_parameter)
|
|
app.router.add_post('/anomalous/delete_parameter', api_delete_parameter)
|
|
app.router.add_get('/anomalous/parameter_gallery', api_get_parameter_gallery)
|
|
app.router.add_get('/anomalous/parameter_pictures', api_get_parameter_pictures)
|
|
|
|
# Recipe Routes
|
|
app.router.add_get('/anomalous/recipes', recipes.api_get_recipes)
|
|
app.router.add_get('/anomalous/recipe_full', recipes.api_get_recipe_full)
|
|
app.router.add_get('/anomalous/recipe_asset', recipes.api_get_recipe_asset)
|
|
app.router.add_get('/anomalous/recipe_gallery', recipes.api_get_recipe_gallery)
|
|
app.router.add_get('/anomalous/recipe_parameter_gallery', recipes.api_get_recipe_parameter_gallery)
|
|
app.router.add_get('/anomalous/recipe_gallery_compare', recipes.api_get_recipe_gallery_compare)
|
|
app.router.add_post('/anomalous/save_recipe', recipes.api_save_recipe)
|
|
app.router.add_post('/anomalous/update_recipe', recipes.api_update_recipe)
|
|
app.router.add_post('/anomalous/recipe_focus', recipes.api_set_recipe_focus)
|
|
app.router.add_post('/anomalous/set_recipe_gallery_cover', recipes.api_set_recipe_gallery_cover)
|
|
app.router.add_post('/anomalous/delete_recipe', recipes.api_delete_recipe)
|
|
app.router.add_get('/anomalous/recipe_history', recipes.api_get_recipe_history)
|
|
app.router.add_get('/anomalous/recipe_version', recipes.api_get_recipe_version)
|
|
app.router.add_post('/anomalous/restore_recipe_version', recipes.api_restore_recipe_version)
|
|
app.router.add_post('/anomalous/refresh_recipe_identity', recipes.api_refresh_recipe_identity)
|
|
app.router.add_post('/anomalous/export_recipe_package', recipe_packages.api_export_recipe_package)
|
|
app.router.add_post('/anomalous/import_recipe_package_inspect', recipe_packages.api_import_recipe_package_inspect)
|
|
app.router.add_post('/anomalous/import_recipe_package_commit', recipe_packages.api_import_recipe_package_commit)
|
|
|
|
# Curated Material Library Routes
|
|
app.router.add_get('/anomalous/materials', materials.api_get_materials)
|
|
app.router.add_get('/anomalous/material_full', materials.api_get_material_full)
|
|
app.router.add_get('/anomalous/material_asset', materials.api_get_material_asset)
|
|
app.router.add_get('/anomalous/materials/by_node_type', materials.api_get_materials_by_node_type)
|
|
app.router.add_post('/anomalous/inspect_image_material', materials.api_inspect_image_material)
|
|
app.router.add_post('/anomalous/save_image_material', materials.api_save_image_material)
|
|
app.router.add_post('/anomalous/save_prompt_plan', materials.api_save_prompt_plan)
|
|
app.router.add_post('/anomalous/save_node_material', node_material.api_save_node_material)
|
|
app.router.add_post('/anomalous/delete_material', materials.api_delete_material)
|
|
app.router.add_post('/anomalous/update_material', materials.api_update_material)
|
|
app.router.add_post('/anomalous/mark_material_moved', materials.api_mark_material_moved)
|
|
|
|
app.router.add_post('/anomalous/translate', translation_routes.api_translate)
|
|
app.router.add_get('/anomalous/base_models', model_catalog.api_base_models)
|
|
app.router.add_get('/anomalous/gallery_images', gallery_routes.api_get_gallery_images)
|
|
app.router.add_post('/anomalous/delete_gallery_image', gallery_routes.api_delete_gallery_image)
|
|
app.router.add_get('/anomalous/output_thumbnail', gallery_routes.api_output_thumbnail)
|
|
app.router.add_get('/anomalous/output_preview', gallery_routes.api_output_preview)
|
|
app.router.add_get('/anomalous/kept_images', kept_images.api_kept_images)
|
|
app.router.add_get('/anomalous/quick_index', quick_index.api_quick_index)
|
|
app.router.add_get('/anomalous/resolve_hash', model_resolution.api_resolve_hash)
|
|
app.router.add_post('/anomalous/resolve_hash_batch', model_resolution.api_resolve_hash_batch)
|
|
app.router.add_get('/anomalous/all_hashes', model_resolution.api_get_all_hashes)
|
|
app.router.add_post('/anomalous/scan_all', api_scan_all)
|
|
app.router.add_get('/anomalous/global_scan_status', api_global_scan_status)
|
|
app.router.add_post('/anomalous/clear_cache', media_routes.api_clear_cache)
|
|
app.router.add_post('/anomalous/update_metadata', model_metadata.api_update_metadata)
|
|
app.router.add_post('/anomalous/set_custom_cover', model_media.api_set_custom_cover)
|
|
app.router.add_post('/anomalous/upload_custom_cover', model_media.api_upload_custom_cover)
|
|
app.router.add_get('/anomalous/model_covers', model_media.api_model_covers)
|
|
app.router.add_get('/anomalous/model_images', media_routes.api_get_model_images)
|
|
app.router.add_post('/anomalous/resolve_paths_to_previews', model_catalog.api_resolve_paths_to_previews)
|
|
app.router.add_get('/anomalous/scan_summary', scan_summary.api_scan_summary)
|
|
app.router.add_get('/anomalous/scan_matched', scan_summary.api_scan_matched)
|
|
app.router.add_get('/anomalous/scan_pickable', scan_summary.api_scan_pickable)
|
|
app.router.add_get('/anomalous/last_scan', scan_report.api_last_scan)
|
|
app.router.add_get('/anomalous/scan_model', scan_report.api_scan_model)
|
|
app.router.add_post('/anomalous/scan_choice', scan_choice.api_set_scan_choice)
|
|
app.router.add_get('/anomalous/lora_info', lora_info.api_lora_info)
|
|
|
|
# Audio & Voice Studio Routes
|
|
app.router.add_get('/anomalous/audio_stream', audio_catalog.api_serve_audio)
|
|
app.router.add_get('/anomalous/audio_gallery', audio_catalog.api_get_audio_gallery)
|
|
app.router.add_post('/anomalous/delete_audio_gallery', audio_catalog.api_delete_audio_gallery)
|
|
app.router.add_get('/anomalous/audio_previews', audio_catalog.api_get_audio_previews)
|
|
app.router.add_post('/anomalous/save_audio_preview', audio_catalog.api_save_audio_preview)
|
|
version_manager.register_routes(app)
|
|
tts_version.register_routes(app)
|
|
activity_log.register_routes(app)
|
|
mcp_server.register_routes(app)
|
|
ai_tasks_routes.register_routes(app)
|
|
model_download.register_routes(app)
|
|
network_check.register_routes(app)
|
|
model_usage.register_routes(app)
|
|
usage_ledger.register_routes(app)
|
|
sidecar_layout.register_routes(app)
|
|
model_import.register_routes(app)
|
|
model_placement.register_routes(app)
|
|
backup.register_routes(app)
|