A new rail page keeps each MCP call as a step of a task (api/ai_tasks.py, one file per task in the user folder, the newest 300): named by the AI with the new begin_task tool, else one app's calls without a long pause. A step keeps what it did and what it made (models, the combo, the canvas change by its activity entry, the pictures a run made, watched in the history until it ends, spoken audio, scans); the new report tool leaves the AI's notes and pictures it made another way. The page shows the tasks and one task's results strip and timeline with links (picture viewer, model page, combo, find or undo on the canvas, audio), updates live, and gives the rail a dot while you are elsewhere; Home lists the last tasks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
151 lines
9.9 KiB
Python
151 lines
9.9 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,
|
|
)
|
|
from .scanner import *
|
|
from .config import *
|
|
from .notebooks import *
|
|
from .parameters import *
|
|
|
|
from aiohttp import web
|
|
|
|
EXTENSION_STATIC_PREFIX = '/extensions/Anomalous_Model_Browser/'
|
|
|
|
|
|
@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)
|
|
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/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.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)
|