mirror of
https://git.datalinker.icu/comfyanonymous/ComfyUI
synced 2025-12-09 22:14:34 +08:00
move assets related stuff to "app/assets" folder (#10184)
This commit is contained in:
parent
fd6ac0a765
commit
917177e821
@ -1,5 +0,0 @@
|
|||||||
from .api.assets_routes import register_assets_system
|
|
||||||
from .assets_scanner import sync_seed_assets
|
|
||||||
from .database.db import init_db_engine
|
|
||||||
|
|
||||||
__all__ = ["init_db_engine", "sync_seed_assets", "register_assets_system"]
|
|
||||||
@ -2,13 +2,12 @@ from sqlalchemy import engine_from_config
|
|||||||
from sqlalchemy import pool
|
from sqlalchemy import pool
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
from app.assets.database.models import Base
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
config = context.config
|
config = context.config
|
||||||
|
|
||||||
|
|
||||||
from app.database.models import Base
|
|
||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
|||||||
4
app/assets/__init__.py
Normal file
4
app/assets/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from .api.routes import register_assets_system
|
||||||
|
from .scanner import sync_seed_assets
|
||||||
|
|
||||||
|
__all__ = ["sync_seed_assets", "register_assets_system"]
|
||||||
@ -10,7 +10,8 @@ from pydantic import ValidationError
|
|||||||
|
|
||||||
import folder_paths
|
import folder_paths
|
||||||
|
|
||||||
from .. import assets_manager, assets_scanner, user_manager
|
from ... import user_manager
|
||||||
|
from .. import manager, scanner
|
||||||
from . import schemas_in, schemas_out
|
from . import schemas_in, schemas_out
|
||||||
|
|
||||||
ROUTES = web.RouteTableDef()
|
ROUTES = web.RouteTableDef()
|
||||||
@ -29,7 +30,7 @@ async def head_asset_by_hash(request: web.Request) -> web.Response:
|
|||||||
algo, digest = hash_str.split(":", 1)
|
algo, digest = hash_str.split(":", 1)
|
||||||
if algo != "blake3" or not digest or any(c for c in digest if c not in "0123456789abcdef"):
|
if algo != "blake3" or not digest or any(c for c in digest if c not in "0123456789abcdef"):
|
||||||
return _error_response(400, "INVALID_HASH", "hash must be like 'blake3:<hex>'")
|
return _error_response(400, "INVALID_HASH", "hash must be like 'blake3:<hex>'")
|
||||||
exists = await assets_manager.asset_exists(asset_hash=hash_str)
|
exists = await manager.asset_exists(asset_hash=hash_str)
|
||||||
return web.Response(status=200 if exists else 404)
|
return web.Response(status=200 if exists else 404)
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ async def list_assets(request: web.Request) -> web.Response:
|
|||||||
except ValidationError as ve:
|
except ValidationError as ve:
|
||||||
return _validation_error_response("INVALID_QUERY", ve)
|
return _validation_error_response("INVALID_QUERY", ve)
|
||||||
|
|
||||||
payload = await assets_manager.list_assets(
|
payload = await manager.list_assets(
|
||||||
include_tags=q.include_tags,
|
include_tags=q.include_tags,
|
||||||
exclude_tags=q.exclude_tags,
|
exclude_tags=q.exclude_tags,
|
||||||
name_contains=q.name_contains,
|
name_contains=q.name_contains,
|
||||||
@ -72,7 +73,7 @@ async def download_asset_content(request: web.Request) -> web.Response:
|
|||||||
disposition = "attachment"
|
disposition = "attachment"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
abs_path, content_type, filename = await assets_manager.resolve_asset_content_for_download(
|
abs_path, content_type, filename = await manager.resolve_asset_content_for_download(
|
||||||
asset_info_id=str(uuid.UUID(request.match_info["id"])),
|
asset_info_id=str(uuid.UUID(request.match_info["id"])),
|
||||||
owner_id=USER_MANAGER.get_request_user_id(request),
|
owner_id=USER_MANAGER.get_request_user_id(request),
|
||||||
)
|
)
|
||||||
@ -102,7 +103,7 @@ async def create_asset_from_hash(request: web.Request) -> web.Response:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
||||||
|
|
||||||
result = await assets_manager.create_asset_from_hash(
|
result = await manager.create_asset_from_hash(
|
||||||
hash_str=body.hash,
|
hash_str=body.hash,
|
||||||
name=body.name,
|
name=body.name,
|
||||||
tags=body.tags,
|
tags=body.tags,
|
||||||
@ -154,7 +155,7 @@ async def upload_asset(request: web.Request) -> web.Response:
|
|||||||
return _error_response(400, "INVALID_HASH", "hash must be like 'blake3:<hex>'")
|
return _error_response(400, "INVALID_HASH", "hash must be like 'blake3:<hex>'")
|
||||||
provided_hash = f"{algo}:{digest}"
|
provided_hash = f"{algo}:{digest}"
|
||||||
try:
|
try:
|
||||||
provided_hash_exists = await assets_manager.asset_exists(asset_hash=provided_hash)
|
provided_hash_exists = await manager.asset_exists(asset_hash=provided_hash)
|
||||||
except Exception:
|
except Exception:
|
||||||
provided_hash_exists = None # do not fail the whole request here
|
provided_hash_exists = None # do not fail the whole request here
|
||||||
|
|
||||||
@ -241,7 +242,7 @@ async def upload_asset(request: web.Request) -> web.Response:
|
|||||||
# Fast path: if a valid provided hash exists, create AssetInfo without writing anything
|
# Fast path: if a valid provided hash exists, create AssetInfo without writing anything
|
||||||
if spec.hash and provided_hash_exists is True:
|
if spec.hash and provided_hash_exists is True:
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.create_asset_from_hash(
|
result = await manager.create_asset_from_hash(
|
||||||
hash_str=spec.hash,
|
hash_str=spec.hash,
|
||||||
name=spec.name or (spec.hash.split(":", 1)[1]),
|
name=spec.name or (spec.hash.split(":", 1)[1]),
|
||||||
tags=spec.tags,
|
tags=spec.tags,
|
||||||
@ -269,7 +270,7 @@ async def upload_asset(request: web.Request) -> web.Response:
|
|||||||
return _error_response(404, "ASSET_NOT_FOUND", "Provided hash not found and no file uploaded.")
|
return _error_response(404, "ASSET_NOT_FOUND", "Provided hash not found and no file uploaded.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
created = await assets_manager.upload_asset_from_temp_path(
|
created = await manager.upload_asset_from_temp_path(
|
||||||
spec,
|
spec,
|
||||||
temp_path=tmp_path,
|
temp_path=tmp_path,
|
||||||
client_filename=file_client_name,
|
client_filename=file_client_name,
|
||||||
@ -300,7 +301,7 @@ async def upload_asset(request: web.Request) -> web.Response:
|
|||||||
async def get_asset(request: web.Request) -> web.Response:
|
async def get_asset(request: web.Request) -> web.Response:
|
||||||
asset_info_id = str(uuid.UUID(request.match_info["id"]))
|
asset_info_id = str(uuid.UUID(request.match_info["id"]))
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.get_asset(
|
result = await manager.get_asset(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
owner_id=USER_MANAGER.get_request_user_id(request),
|
owner_id=USER_MANAGER.get_request_user_id(request),
|
||||||
)
|
)
|
||||||
@ -327,7 +328,7 @@ async def update_asset(request: web.Request) -> web.Response:
|
|||||||
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.update_asset(
|
result = await manager.update_asset(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
name=body.name,
|
name=body.name,
|
||||||
tags=body.tags,
|
tags=body.tags,
|
||||||
@ -357,7 +358,7 @@ async def set_asset_preview(request: web.Request) -> web.Response:
|
|||||||
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.set_asset_preview(
|
result = await manager.set_asset_preview(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
preview_asset_id=body.preview_id,
|
preview_asset_id=body.preview_id,
|
||||||
owner_id=USER_MANAGER.get_request_user_id(request),
|
owner_id=USER_MANAGER.get_request_user_id(request),
|
||||||
@ -381,7 +382,7 @@ async def delete_asset(request: web.Request) -> web.Response:
|
|||||||
delete_content = True if delete_content is None else delete_content.lower() not in {"0", "false", "no"}
|
delete_content = True if delete_content is None else delete_content.lower() not in {"0", "false", "no"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
deleted = await assets_manager.delete_asset_reference(
|
deleted = await manager.delete_asset_reference(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
owner_id=USER_MANAGER.get_request_user_id(request),
|
owner_id=USER_MANAGER.get_request_user_id(request),
|
||||||
delete_content_if_orphan=delete_content,
|
delete_content_if_orphan=delete_content,
|
||||||
@ -411,7 +412,7 @@ async def get_tags(request: web.Request) -> web.Response:
|
|||||||
status=400,
|
status=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
result = await assets_manager.list_tags(
|
result = await manager.list_tags(
|
||||||
prefix=query.prefix,
|
prefix=query.prefix,
|
||||||
limit=query.limit,
|
limit=query.limit,
|
||||||
offset=query.offset,
|
offset=query.offset,
|
||||||
@ -434,7 +435,7 @@ async def add_asset_tags(request: web.Request) -> web.Response:
|
|||||||
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.add_tags_to_asset(
|
result = await manager.add_tags_to_asset(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
tags=data.tags,
|
tags=data.tags,
|
||||||
origin="manual",
|
origin="manual",
|
||||||
@ -465,7 +466,7 @@ async def delete_asset_tags(request: web.Request) -> web.Response:
|
|||||||
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
return _error_response(400, "INVALID_JSON", "Request body must be valid JSON.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await assets_manager.remove_tags_from_asset(
|
result = await manager.remove_tags_from_asset(
|
||||||
asset_info_id=asset_info_id,
|
asset_info_id=asset_info_id,
|
||||||
tags=data.tags,
|
tags=data.tags,
|
||||||
owner_id=USER_MANAGER.get_request_user_id(request),
|
owner_id=USER_MANAGER.get_request_user_id(request),
|
||||||
@ -496,7 +497,7 @@ async def seed_assets(request: web.Request) -> web.Response:
|
|||||||
return _validation_error_response("INVALID_BODY", ve)
|
return _validation_error_response("INVALID_BODY", ve)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await assets_scanner.sync_seed_assets(body.roots)
|
await scanner.sync_seed_assets(body.roots)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOGGER.exception("sync_seed_assets failed for roots=%s", body.roots)
|
LOGGER.exception("sync_seed_assets failed for roots=%s", body.roots)
|
||||||
return _error_response(500, "INTERNAL", "Unexpected server error.")
|
return _error_response(500, "INTERNAL", "Unexpected server error.")
|
||||||
@ -515,14 +516,14 @@ async def schedule_asset_scan(request: web.Request) -> web.Response:
|
|||||||
except ValidationError as ve:
|
except ValidationError as ve:
|
||||||
return _validation_error_response("INVALID_BODY", ve)
|
return _validation_error_response("INVALID_BODY", ve)
|
||||||
|
|
||||||
states = await assets_scanner.schedule_scans(body.roots)
|
states = await scanner.schedule_scans(body.roots)
|
||||||
return web.json_response(states.model_dump(mode="json"), status=202)
|
return web.json_response(states.model_dump(mode="json"), status=202)
|
||||||
|
|
||||||
|
|
||||||
@ROUTES.get("/api/assets/scan")
|
@ROUTES.get("/api/assets/scan")
|
||||||
async def get_asset_scan_status(request: web.Request) -> web.Response:
|
async def get_asset_scan_status(request: web.Request) -> web.Response:
|
||||||
root = request.query.get("root", "").strip().lower()
|
root = request.query.get("root", "").strip().lower()
|
||||||
states = assets_scanner.current_statuses()
|
states = scanner.current_statuses()
|
||||||
if root in {"models", "input", "output"}:
|
if root in {"models", "input", "output"}:
|
||||||
states = [s for s in states.scans if s.root == root] # type: ignore
|
states = [s for s in states.scans if s.root == root] # type: ignore
|
||||||
states = schemas_out.AssetScanStatusResponse(scans=states)
|
states = schemas_out.AssetScanStatusResponse(scans=states)
|
||||||
@ -3,7 +3,7 @@ from typing import Optional, Sequence
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import exists
|
from sqlalchemy import exists
|
||||||
|
|
||||||
from ..._assets_helpers import normalize_tags
|
from ..._helpers import normalize_tags
|
||||||
from ..models import AssetInfo, AssetInfoMeta, AssetInfoTag
|
from ..models import AssetInfo, AssetInfoMeta, AssetInfoTag
|
||||||
|
|
||||||
|
|
||||||
@ -5,7 +5,7 @@ from sqlalchemy.dialects import postgresql as d_pg
|
|||||||
from sqlalchemy.dialects import sqlite as d_sqlite
|
from sqlalchemy.dialects import sqlite as d_sqlite
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from ..._assets_helpers import normalize_tags
|
from ..._helpers import normalize_tags
|
||||||
from ..models import AssetInfo, AssetInfoTag, Tag
|
from ..models import AssetInfo, AssetInfoTag, Tag
|
||||||
from ..timeutil import utcnow
|
from ..timeutil import utcnow
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ from sqlalchemy.exc import IntegrityError
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import noload
|
from sqlalchemy.orm import noload
|
||||||
|
|
||||||
from ..._assets_helpers import compute_relative_filename
|
from ..._helpers import compute_relative_filename
|
||||||
from ...storage import hashing as hashing_mod
|
from ...storage import hashing as hashing_mod
|
||||||
from ..helpers import (
|
from ..helpers import (
|
||||||
ensure_tags_exist,
|
ensure_tags_exist,
|
||||||
@ -8,7 +8,7 @@ from sqlalchemy.exc import IntegrityError
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import contains_eager, noload
|
from sqlalchemy.orm import contains_eager, noload
|
||||||
|
|
||||||
from ..._assets_helpers import compute_relative_filename, normalize_tags
|
from ..._helpers import compute_relative_filename, normalize_tags
|
||||||
from ..helpers import (
|
from ..helpers import (
|
||||||
apply_metadata_filter,
|
apply_metadata_filter,
|
||||||
apply_tag_filters,
|
apply_tag_filters,
|
||||||
@ -6,13 +6,13 @@ from typing import Optional, Sequence
|
|||||||
|
|
||||||
from comfy_api.internal import async_to_sync
|
from comfy_api.internal import async_to_sync
|
||||||
|
|
||||||
from ._assets_helpers import (
|
from ..db import create_session
|
||||||
|
from ._helpers import (
|
||||||
ensure_within_base,
|
ensure_within_base,
|
||||||
get_name_and_tags_from_asset_path,
|
get_name_and_tags_from_asset_path,
|
||||||
resolve_destination_from_tags,
|
resolve_destination_from_tags,
|
||||||
)
|
)
|
||||||
from .api import schemas_in, schemas_out
|
from .api import schemas_in, schemas_out
|
||||||
from .database.db import create_session
|
|
||||||
from .database.models import Asset
|
from .database.models import Asset
|
||||||
from .database.services import (
|
from .database.services import (
|
||||||
add_tags_to_asset_info,
|
add_tags_to_asset_info,
|
||||||
@ -10,7 +10,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
import folder_paths
|
import folder_paths
|
||||||
|
|
||||||
from ._assets_helpers import (
|
from ..db import create_session
|
||||||
|
from ._helpers import (
|
||||||
collect_models_files,
|
collect_models_files,
|
||||||
compute_relative_filename,
|
compute_relative_filename,
|
||||||
get_comfy_models_folders,
|
get_comfy_models_folders,
|
||||||
@ -21,7 +22,6 @@ from ._assets_helpers import (
|
|||||||
ts_to_iso,
|
ts_to_iso,
|
||||||
)
|
)
|
||||||
from .api import schemas_in, schemas_out
|
from .api import schemas_in, schemas_out
|
||||||
from .database.db import create_session
|
|
||||||
from .database.helpers import (
|
from .database.helpers import (
|
||||||
add_missing_tag_for_asset_id,
|
add_missing_tag_for_asset_id,
|
||||||
ensure_tags_exist,
|
ensure_tags_exist,
|
||||||
@ -27,8 +27,8 @@ SESSION: Optional[async_sessionmaker] = None
|
|||||||
def _root_paths():
|
def _root_paths():
|
||||||
"""Resolve alembic.ini and migrations script folder."""
|
"""Resolve alembic.ini and migrations script folder."""
|
||||||
root_path = os.path.abspath(os.path.dirname(__file__))
|
root_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
config_path = os.path.abspath(os.path.join(root_path, "../../alembic.ini"))
|
config_path = os.path.abspath(os.path.join(root_path, "../alembic.ini"))
|
||||||
scripts_path = os.path.abspath(os.path.join(root_path, "../alembic_db"))
|
scripts_path = os.path.abspath(os.path.join(root_path, "alembic_db"))
|
||||||
return config_path, scripts_path
|
return config_path, scripts_path
|
||||||
|
|
||||||
|
|
||||||
3
main.py
3
main.py
@ -279,7 +279,8 @@ def cleanup_temp():
|
|||||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
|
|
||||||
async def setup_database():
|
async def setup_database():
|
||||||
from app import init_db_engine, sync_seed_assets
|
from app.assets import sync_seed_assets
|
||||||
|
from app.db import init_db_engine
|
||||||
|
|
||||||
await init_db_engine()
|
await init_db_engine()
|
||||||
if not args.disable_assets_autoscan:
|
if not args.disable_assets_autoscan:
|
||||||
|
|||||||
@ -37,7 +37,7 @@ from app.model_manager import ModelFileManager
|
|||||||
from app.custom_node_manager import CustomNodeManager
|
from app.custom_node_manager import CustomNodeManager
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from api_server.routes.internal.internal_routes import InternalRoutes
|
from api_server.routes.internal.internal_routes import InternalRoutes
|
||||||
from app import sync_seed_assets, register_assets_system
|
from app.assets import sync_seed_assets, register_assets_system
|
||||||
from protocol import BinaryEventTypes
|
from protocol import BinaryEventTypes
|
||||||
|
|
||||||
# Import cache control middleware
|
# Import cache control middleware
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user