always autofill "filename" in the metadata

This commit is contained in:
bigcat88 2025-08-29 19:48:42 +03:00
parent 6b86be320a
commit bf8363ec87
No known key found for this signature in database
GPG Key ID: 1F0BF0EC3CF22721
2 changed files with 116 additions and 10 deletions

View File

@ -145,3 +145,30 @@ def visible_owner_clause(owner_id: str) -> sa.sql.ClauseElement:
if owner_id == "": if owner_id == "":
return AssetInfo.owner_id == "" return AssetInfo.owner_id == ""
return AssetInfo.owner_id.in_(["", owner_id]) return AssetInfo.owner_id.in_(["", owner_id])
def compute_model_relative_filename(file_path: str) -> str | None:
"""
Return the model's path relative to the last well-known folder (the model category),
using forward slashes, eg:
/.../models/checkpoints/flux/123/flux.safetensors -> "flux/123/flux.safetensors"
/.../models/text_encoders/clip_g.safetensors -> "clip_g.safetensors"
For non-model paths, returns None.
NOTE: this is a temporary helper, used only for initializing metadata["filename"] field.
"""
try:
root_category, rel_path = get_relative_to_root_category_path_of_asset(file_path)
except ValueError:
return None
if root_category != "models":
return None
p = Path(rel_path)
# parts[0] is the well-known category (eg "checkpoints" or "text_encoders")
parts = [seg for seg in p.parts if seg not in (".", "..", p.anchor)]
if not parts:
return None
inside = parts[1:] if len(parts) > 1 else [parts[0]]
return "/".join(inside) # normalize to POSIX style for portability

View File

@ -14,7 +14,7 @@ from sqlalchemy.exc import IntegrityError
from .models import Asset, AssetInfo, AssetInfoTag, AssetCacheState, Tag, AssetInfoMeta, AssetLocation from .models import Asset, AssetInfo, AssetInfoTag, AssetCacheState, Tag, AssetInfoMeta, AssetLocation
from .timeutil import utcnow from .timeutil import utcnow
from .._assets_helpers import normalize_tags, visible_owner_clause from .._assets_helpers import normalize_tags, visible_owner_clause, compute_model_relative_filename
async def asset_exists_by_hash(session: AsyncSession, *, asset_hash: str) -> bool: async def asset_exists_by_hash(session: AsyncSession, *, asset_hash: str) -> bool:
@ -251,12 +251,38 @@ async def ingest_fs_asset(
await session.flush() await session.flush()
# 2c) Rebuild metadata projection if provided # 2c) Rebuild metadata projection if provided
if user_metadata is not None and out["asset_info_id"] is not None: # Uncomment next code, and remove code after it, once the hack with "metadata[filename" is not needed anymore
await replace_asset_info_metadata_projection( # if user_metadata is not None and out["asset_info_id"] is not None:
session, # await replace_asset_info_metadata_projection(
asset_info_id=out["asset_info_id"], # session,
user_metadata=user_metadata, # asset_info_id=out["asset_info_id"],
) # user_metadata=user_metadata,
# )
# start of adding metadata["filename"]
if out["asset_info_id"] is not None:
computed_filename = compute_model_relative_filename(abs_path)
# Start from current metadata on this AssetInfo, if any
current_meta = existing_info.user_metadata or {}
new_meta = dict(current_meta)
# Merge caller-provided metadata, if any (caller keys override current)
if user_metadata is not None:
for k, v in user_metadata.items():
new_meta[k] = v
# Enforce correct model-relative filename when known
if computed_filename:
new_meta["filename"] = computed_filename
# Only write when there is a change
if new_meta != current_meta:
await replace_asset_info_metadata_projection(
session,
asset_info_id=out["asset_info_id"],
user_metadata=new_meta,
)
# end of adding metadata["filename"]
return out return out
@ -527,10 +553,33 @@ async def create_asset_info_for_existing_asset(
session.add(info) session.add(info)
await session.flush() # get info.id await session.flush() # get info.id
if user_metadata is not None: # Uncomment next code, and remove code after it, once the hack with "metadata[filename" is not needed anymore
# if user_metadata is not None:
# await replace_asset_info_metadata_projection(
# session, asset_info_id=info.id, user_metadata=user_metadata
# )
# start of adding metadata["filename"]
new_meta = dict(user_metadata or {})
computed_filename = None
try:
state = await get_cache_state_by_asset_hash(session, asset_hash=asset_hash)
if state and state.file_path:
computed_filename = compute_model_relative_filename(state.file_path)
except Exception:
computed_filename = None
if computed_filename:
new_meta["filename"] = computed_filename
if new_meta:
await replace_asset_info_metadata_projection( await replace_asset_info_metadata_projection(
session, asset_info_id=info.id, user_metadata=user_metadata session,
asset_info_id=info.id,
user_metadata=new_meta,
) )
# end of adding metadata["filename"]
if tags is not None: if tags is not None:
await set_asset_info_tags( await set_asset_info_tags(
@ -612,11 +661,41 @@ async def update_asset_info_full(
info.name = name info.name = name
touched = True touched = True
# Uncomment next code, and remove code after it, once the hack with "metadata[filename" is not needed anymore
# if user_metadata is not None:
# await replace_asset_info_metadata_projection(
# session, asset_info_id=asset_info_id, user_metadata=user_metadata
# )
# touched = True
# start of adding metadata["filename"]
computed_filename = None
try:
state = await get_cache_state_by_asset_hash(session, asset_hash=info.asset_hash)
if state and state.file_path:
computed_filename = compute_model_relative_filename(state.file_path)
except Exception:
computed_filename = None
if user_metadata is not None: if user_metadata is not None:
new_meta = dict(user_metadata)
if computed_filename:
new_meta["filename"] = computed_filename
await replace_asset_info_metadata_projection( await replace_asset_info_metadata_projection(
session, asset_info_id=asset_info_id, user_metadata=user_metadata session, asset_info_id=asset_info_id, user_metadata=new_meta
) )
touched = True touched = True
else:
if computed_filename:
current_meta = info.user_metadata or {}
if current_meta.get("filename") != computed_filename:
new_meta = dict(current_meta)
new_meta["filename"] = computed_filename
await replace_asset_info_metadata_projection(
session, asset_info_id=asset_info_id, user_metadata=new_meta
)
touched = True
# end of adding metadata["filename"]
if tags is not None: if tags is not None:
await set_asset_info_tags( await set_asset_info_tags(