@happyvertical/smrt-images
Image asset management with AI-powered categorization, editing, metadata extraction, and cross-package STI extending Asset.
v0.20.44AI CategorizationImage EditingSTI Asset
Overview
smrt-images extends the base Asset model from smrt-assets via cross-package
STI, adding image-specific dimensions, AI-powered categorization, editing operations, and
metadata extraction. Each editing operation creates a new derivative Image linked to its
source via parentId.
Installation
bash
npm install @happyvertical/smrt-imagesQuick Start
typescript
import {
Image, ImageCollection,
ImageCategorizer, ImageEditor, ImageDeriver,
ImageMetadataExtractor, ImageSearch, UpstreamManager,
} from '@happyvertical/smrt-images';
// Create and query images
const images = new ImageCollection(db);
const image = await images.create({
name: 'hero.jpg',
url: 'https://cdn.example.com/hero.jpg',
mimeType: 'image/jpeg',
width: 1920,
height: 1080,
});
await image.save();
// Computed properties from dimensions
image.isLandscape; // true
image.aspectRatio; // 1.778
image.isHighResolution(); // false (below 4K)
// AI-powered categorization
const categorizer = new ImageCategorizer({ ai: aiConfig });
const result = await categorizer.categorize(image);
// Auto-tag: applies tags and sets description/alt text
await categorizer.autoTag(image, assetCollection);
// AI alt text generation via this.do()
const altText = await image.generateAltText();
// Standard editing (each creates a derivative Image)
const editor = new ImageEditor(store, images, { ai: aiConfig });
const thumb = await editor.thumbnail(image, 256);
const resized = await editor.resize(image, 800, 600);
const webp = await editor.convert(image, 'webp');
// AI-powered editing and variation generation
const edited = await editor.edit(image, 'add warm sunset tones');
const variations = await editor.generateVariation(
image, 'winter theme', { count: 3 }
);Core Models
Image (STI subclass of Asset)
typescript
class Image extends Asset {
width: number
height: number
alt?: string
// Computed properties
get isLandscape(): boolean
get isPortrait(): boolean
get isSquare(): boolean
get aspectRatio(): number
isHighResolution(): boolean
generateAltText(): Promise<string> // AI via this.do()
}ImageCollection
typescript
class ImageCollection extends SmrtCollection<Image> {
getByMinDimensions(width: number, height: number): Promise<Image[]>
getByAspectRatio(ratio: number, tolerance?: number): Promise<Image[]>
getLandscape(): Promise<Image[]>
getPortrait(): Promise<Image[]>
getSquare(): Promise<Image[]>
getHighResolution(): Promise<Image[]>
getMissingAltText(): Promise<Image[]>
}Services
typescript
// ImageCategorizer: AI vision analysis
const categorizer = new ImageCategorizer({ ai: aiConfig });
const result = await categorizer.categorize(image);
// Returns: { tags, description, confidence, subjects }
// ImageEditor: resize/crop/convert + AI editing
// Each operation creates a new Image linked via parentId
const editor = new ImageEditor(store, images, { ai: aiConfig });
// ImageMetadataExtractor: dimensions, format, EXIF
const extractor = new ImageMetadataExtractor();
const meta = await extractor.extract(imageBuffer);
// ImageSearch: text search with orientation filters
const search = new ImageSearch(images);
const results = await search.find({ query: 'sunset', orientation: 'landscape' });
// UpstreamManager: import from external providers
const upstream = new UpstreamManager(images, store);
await upstream.importFromSource(sourceAdapter, { provenance: true });Best Practices
DOs
- Use
generateAltText()to ensure accessibility for all images - Use
autoTag()for consistent AI categorization - Create derivatives through ImageEditor (maintains parentId chain)
- Use dimension-based queries for responsive image selection
- Track provenance when importing from external sources
DON'Ts
- Don't modify the Asset schema without considering cross-package STI impact
- Don't create Image instances directly (use ImageEditor for derivatives)
- Don't assume orientation filtering is indexed (it's in-memory)
- Don't skip the 3 DB calls for derivative creation (create + store + save)