[feat] add asset metadata validation utilities

This commit is contained in:
Arjan Singh
2025-09-16 20:44:31 -07:00
parent 4f26b3f3cf
commit 5243ef3528
4 changed files with 103 additions and 5 deletions

View File

@@ -3,6 +3,10 @@ import { computed, ref } from 'vue'
import { t } from '@/i18n'
import type { UUID } from '@/lib/litegraph/src/utils/uuid'
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import {
getAssetBaseModel,
getAssetDescription
} from '@/platform/assets/utils/assetMetadataUtils'
import { formatSize } from '@/utils/formatUtil'
type AssetBadge = {
@@ -37,7 +41,7 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
// Extract description from metadata or create from tags
const typeTag = asset.tags.find((tag) => tag !== 'models')
const description =
asset.user_metadata?.description ||
getAssetDescription(asset) ||
`${typeTag || t('assetBrowser.unknown')} model`
// Format file size
@@ -52,9 +56,10 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
}
// Base model badge from metadata
if (asset.user_metadata?.base_model) {
const baseModel = getAssetBaseModel(asset)
if (baseModel) {
badges.push({
label: asset.user_metadata.base_model,
label: baseModel,
type: 'base'
})
}
@@ -126,9 +131,10 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
const filterByQuery = (query: string) => (asset: AssetItem) => {
if (!query) return true
const lowerQuery = query.toLowerCase()
const description = getAssetDescription(asset)
return (
asset.name.toLowerCase().includes(lowerQuery) ||
asset.user_metadata?.description?.toLowerCase().includes(lowerQuery) ||
(description && description.toLowerCase().includes(lowerQuery)) ||
asset.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))
)
}

View File

@@ -12,7 +12,7 @@ const zAsset = z.object({
created_at: z.string(),
updated_at: z.string(),
last_access_time: z.string(),
user_metadata: z.record(z.any()).optional(),
user_metadata: z.record(z.unknown()).optional(), // API allows arbitrary key-value pairs
preview_id: z.string().nullable().optional()
})

View File

@@ -0,0 +1,27 @@
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
/**
* Type-safe utilities for extracting metadata from assets
*/
/**
* Safely extracts string description from asset metadata
* @param asset - The asset to extract description from
* @returns The description string or null if not present/not a string
*/
export function getAssetDescription(asset: AssetItem): string | null {
return typeof asset.user_metadata?.description === 'string'
? asset.user_metadata.description
: null
}
/**
* Safely extracts string base_model from asset metadata
* @param asset - The asset to extract base_model from
* @returns The base_model string or null if not present/not a string
*/
export function getAssetBaseModel(asset: AssetItem): string | null {
return typeof asset.user_metadata?.base_model === 'string'
? asset.user_metadata.base_model
: null
}

View File

@@ -0,0 +1,65 @@
import { describe, expect, it } from 'vitest'
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import {
getAssetBaseModel,
getAssetDescription
} from '@/platform/assets/utils/assetMetadataUtils'
describe('assetMetadataUtils', () => {
const mockAsset: AssetItem = {
id: 'test-id',
name: 'test-model',
asset_hash: 'hash123',
size: 1024,
mime_type: 'application/octet-stream',
tags: ['models', 'checkpoints'],
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
last_access_time: '2024-01-01T00:00:00Z'
}
describe('getAssetDescription', () => {
it('should return string description when present', () => {
const asset = {
...mockAsset,
user_metadata: { description: 'A test model' }
}
expect(getAssetDescription(asset)).toBe('A test model')
})
it('should return null when description is not a string', () => {
const asset = {
...mockAsset,
user_metadata: { description: 123 }
}
expect(getAssetDescription(asset)).toBeNull()
})
it('should return null when no metadata', () => {
expect(getAssetDescription(mockAsset)).toBeNull()
})
})
describe('getAssetBaseModel', () => {
it('should return string base_model when present', () => {
const asset = {
...mockAsset,
user_metadata: { base_model: 'SDXL' }
}
expect(getAssetBaseModel(asset)).toBe('SDXL')
})
it('should return null when base_model is not a string', () => {
const asset = {
...mockAsset,
user_metadata: { base_model: 123 }
}
expect(getAssetBaseModel(asset)).toBeNull()
})
it('should return null when no metadata', () => {
expect(getAssetBaseModel(mockAsset)).toBeNull()
})
})
})