Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions app/__init__.py

This file was deleted.

3 changes: 1 addition & 2 deletions app/alembic_db/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
from sqlalchemy import pool

from alembic import context
from app.assets.database.models import Base

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config


from app.database.models import Base
target_metadata = Base.metadata

# other values from the config, defined by the needs of env.py,
Expand Down
4 changes: 4 additions & 0 deletions app/assets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .api.routes import register_assets_system
from .scanner import sync_seed_assets

__all__ = ["sync_seed_assets", "register_assets_system"]
File renamed without changes.
File renamed without changes.
37 changes: 19 additions & 18 deletions app/api/assets_routes.py → app/assets/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

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

ROUTES = web.RouteTableDef()
Expand All @@ -29,7 +30,7 @@ async def head_asset_by_hash(request: web.Request) -> web.Response:
algo, digest = hash_str.split(":", 1)
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>'")
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)


Expand All @@ -51,7 +52,7 @@ async def list_assets(request: web.Request) -> web.Response:
except ValidationError as ve:
return _validation_error_response("INVALID_QUERY", ve)

payload = await assets_manager.list_assets(
payload = await manager.list_assets(
include_tags=q.include_tags,
exclude_tags=q.exclude_tags,
name_contains=q.name_contains,
Expand All @@ -72,7 +73,7 @@ async def download_asset_content(request: web.Request) -> web.Response:
disposition = "attachment"

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"])),
owner_id=USER_MANAGER.get_request_user_id(request),
)
Expand Down Expand Up @@ -102,7 +103,7 @@ async def create_asset_from_hash(request: web.Request) -> web.Response:
except Exception:
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,
name=body.name,
tags=body.tags,
Expand Down Expand Up @@ -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>'")
provided_hash = f"{algo}:{digest}"
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:
provided_hash_exists = None # do not fail the whole request here

Expand Down Expand Up @@ -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
if spec.hash and provided_hash_exists is True:
try:
result = await assets_manager.create_asset_from_hash(
result = await manager.create_asset_from_hash(
hash_str=spec.hash,
name=spec.name or (spec.hash.split(":", 1)[1]),
tags=spec.tags,
Expand Down Expand Up @@ -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.")

try:
created = await assets_manager.upload_asset_from_temp_path(
created = await manager.upload_asset_from_temp_path(
spec,
temp_path=tmp_path,
client_filename=file_client_name,
Expand Down Expand Up @@ -300,7 +301,7 @@ async def upload_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"]))
try:
result = await assets_manager.get_asset(
result = await manager.get_asset(
asset_info_id=asset_info_id,
owner_id=USER_MANAGER.get_request_user_id(request),
)
Expand All @@ -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.")

try:
result = await assets_manager.update_asset(
result = await manager.update_asset(
asset_info_id=asset_info_id,
name=body.name,
tags=body.tags,
Expand Down Expand Up @@ -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.")

try:
result = await assets_manager.set_asset_preview(
result = await manager.set_asset_preview(
asset_info_id=asset_info_id,
preview_asset_id=body.preview_id,
owner_id=USER_MANAGER.get_request_user_id(request),
Expand All @@ -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"}

try:
deleted = await assets_manager.delete_asset_reference(
deleted = await manager.delete_asset_reference(
asset_info_id=asset_info_id,
owner_id=USER_MANAGER.get_request_user_id(request),
delete_content_if_orphan=delete_content,
Expand Down Expand Up @@ -411,7 +412,7 @@ async def get_tags(request: web.Request) -> web.Response:
status=400,
)

result = await assets_manager.list_tags(
result = await manager.list_tags(
prefix=query.prefix,
limit=query.limit,
offset=query.offset,
Expand All @@ -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.")

try:
result = await assets_manager.add_tags_to_asset(
result = await manager.add_tags_to_asset(
asset_info_id=asset_info_id,
tags=data.tags,
origin="manual",
Expand Down Expand Up @@ -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.")

try:
result = await assets_manager.remove_tags_from_asset(
result = await manager.remove_tags_from_asset(
asset_info_id=asset_info_id,
tags=data.tags,
owner_id=USER_MANAGER.get_request_user_id(request),
Expand Down Expand Up @@ -496,7 +497,7 @@ async def seed_assets(request: web.Request) -> web.Response:
return _validation_error_response("INVALID_BODY", ve)

try:
await assets_scanner.sync_seed_assets(body.roots)
await scanner.sync_seed_assets(body.roots)
except Exception:
LOGGER.exception("sync_seed_assets failed for roots=%s", body.roots)
return _error_response(500, "INTERNAL", "Unexpected server error.")
Expand All @@ -515,14 +516,14 @@ async def schedule_asset_scan(request: web.Request) -> web.Response:
except ValidationError as 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)


@ROUTES.get("/api/assets/scan")
async def get_asset_scan_status(request: web.Request) -> web.Response:
root = request.query.get("root", "").strip().lower()
states = assets_scanner.current_statuses()
states = scanner.current_statuses()
if root in {"models", "input", "output"}:
states = [s for s in states.scans if s.root == root] # type: ignore
states = schemas_out.AssetScanStatusResponse(scans=states)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sqlalchemy as sa
from sqlalchemy import exists

from ..._assets_helpers import normalize_tags
from ..._helpers import normalize_tags
from ..models import AssetInfo, AssetInfoMeta, AssetInfoTag


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy.dialects import sqlite as d_sqlite
from sqlalchemy.ext.asyncio import AsyncSession

from ..._assets_helpers import normalize_tags
from ..._helpers import normalize_tags
from ..models import AssetInfo, AssetInfoTag, Tag
from ..timeutil import utcnow

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from sqlalchemy.ext.asyncio import AsyncSession
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 ..helpers import (
ensure_tags_exist,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from sqlalchemy.ext.asyncio import AsyncSession
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 (
apply_metadata_filter,
apply_tag_filters,
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions app/assets_manager.py → app/assets/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

from comfy_api.internal import async_to_sync

from ._assets_helpers import (
from ..db import create_session
from ._helpers import (
ensure_within_base,
get_name_and_tags_from_asset_path,
resolve_destination_from_tags,
)
from .api import schemas_in, schemas_out
from .database.db import create_session
from .database.models import Asset
from .database.services import (
add_tags_to_asset_info,
Expand Down
4 changes: 2 additions & 2 deletions app/assets_scanner.py → app/assets/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

import folder_paths

from ._assets_helpers import (
from ..db import create_session
from ._helpers import (
collect_models_files,
compute_relative_filename,
get_comfy_models_folders,
Expand All @@ -21,7 +22,6 @@
ts_to_iso,
)
from .api import schemas_in, schemas_out
from .database.db import create_session
from .database.helpers import (
add_missing_tag_for_asset_id,
ensure_tags_exist,
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions app/database/db.py → app/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
def _root_paths():
"""Resolve alembic.ini and migrations script folder."""
root_path = os.path.abspath(os.path.dirname(__file__))
config_path = os.path.abspath(os.path.join(root_path, "../../alembic.ini"))
scripts_path = os.path.abspath(os.path.join(root_path, "../alembic_db"))
config_path = os.path.abspath(os.path.join(root_path, "../alembic.ini"))
scripts_path = os.path.abspath(os.path.join(root_path, "alembic_db"))
return config_path, scripts_path


Expand Down
3 changes: 2 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ def cleanup_temp():
shutil.rmtree(temp_dir, ignore_errors=True)

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()
if not args.disable_assets_autoscan:
Expand Down
2 changes: 1 addition & 1 deletion server.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from app.custom_node_manager import CustomNodeManager
from typing import Optional, Union
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

# Import cache control middleware
Expand Down