UNPKG

assetmax

Version:

Manifest-driven asset management system with contract-based generation

259 lines • 11.4 kB
"use strict"; /** * Asset Generation CLI * Reads manifest and generates missing assets using AI models */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AssetCLI = void 0; const fs_1 = require("fs"); const path = __importStar(require("path")); const toml = __importStar(require("@iarna/toml")); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const universal_generator_js_1 = require("../models/universal-generator.js"); const model_registry_js_1 = require("../models/model-registry.js"); class AssetCLI { manifest = null; generator; progress = { total: 0, completed: 0, failed: 0, totalCost: 0 }; constructor() { this.generator = new universal_generator_js_1.UniversalImageGenerator(); } async run(options = {}) { const manifestFile = options.manifestFile || 'asset-manifest.toml'; console.log(chalk_1.default.blue.bold('šŸŽØ AssetMax Generator Starting...\n')); await this.loadManifest(manifestFile); await this.initModels(); const assetsToGenerate = await this.getAssetsToGenerate(options.force); if (assetsToGenerate.length === 0) { console.log(chalk_1.default.green('āœ… All assets already exist!')); return; } if (options.dryRun) { this.showDryRun(assetsToGenerate); return; } await this.generateAssets(assetsToGenerate); this.showSummary(); } async loadManifest(manifestPath) { if (!(await fs_1.promises.access(manifestPath).then(() => true).catch(() => false))) { throw new Error(`Manifest not found: ${manifestPath}`); } const content = await fs_1.promises.readFile(manifestPath, 'utf-8'); this.manifest = toml.parse(content); console.log(`šŸ“‹ Loaded manifest: ${this.manifest.meta.name} v${this.manifest.meta.version}`); } async initModels() { // Check if API token is available if (!process.env.REPLICATE_API_TOKEN) { console.warn('āš ļø REPLICATE_API_TOKEN environment variable is required'); return; } // List available models const allModels = (0, model_registry_js_1.getAllModels)(); console.log(`āœ… ${allModels.length} image generation models available`); // Show model categories for user reference const fastest = allModels.filter(m => m.costPerImage <= 0.01); if (fastest.length > 0) { console.log(`⚔ Fastest/cheapest: ${fastest.map(m => m.name).join(', ')}`); } } async getAssetsToGenerate(force = false) { const assets = []; for (const [groupName, groupConfig] of Object.entries(this.manifest.assets)) { const category = groupConfig.category; const subcategory = groupConfig.subcategory; const format = groupConfig.format; const model = groupConfig.generation_model; for (const [assetName, assetConfig] of Object.entries(groupConfig)) { if (typeof assetConfig === 'object' && 'prompt' in assetConfig) { const fileName = `${assetName}.${format}`; const relativePath = subcategory ? `${category}/${subcategory}/${fileName}` : `${category}/${fileName}`; const outputPath = path.join(this.manifest.cli.output_dir, relativePath); const exists = await fs_1.promises.access(outputPath).then(() => true).catch(() => false); if (!exists || force) { assets.push({ name: assetName, groupName, outputPath, relativePath, prompt: assetConfig.prompt, model, aspectRatio: assetConfig.aspect_ratio || groupConfig.aspect_ratio || '1:1', format, cost: (() => { try { return (0, model_registry_js_1.getModelConfig)(model).costPerImage; } catch { return this.manifest?.cli?.pricing?.[model] || 0; } })() }); } } } } return assets; } showDryRun(assets) { console.log(chalk_1.default.cyan.bold('šŸ” DRY RUN - Assets to generate:\n')); const totalCost = assets.reduce((sum, asset) => sum + asset.cost, 0); const modelCounts = assets.reduce((counts, asset) => { counts[asset.model] = (counts[asset.model] || 0) + 1; return counts; }, {}); console.log(`šŸ“Š Summary:`); console.log(` Total assets: ${assets.length}`); console.log(` Estimated cost: $${totalCost.toFixed(3)}`); console.log(` Models:`); for (const [model, count] of Object.entries(modelCounts)) { let unitCost = 0; try { unitCost = (0, model_registry_js_1.getModelConfig)(model).costPerImage; } catch { unitCost = this.manifest?.cli?.pricing?.[model] || 0; } const modelCost = count * unitCost; console.log(` ${model}: ${count} assets ($${modelCost.toFixed(3)})`); } console.log('\nšŸ“‹ Assets:'); for (const asset of assets) { console.log(` ${chalk_1.default.yellow(asset.name)} → ${asset.relativePath} (${asset.model})`); } } async generateAssets(assets) { this.progress.total = assets.length; const spinner = (0, ora_1.default)(`Generating ${assets.length} assets...`).start(); for (const asset of assets) { this.progress.currentAsset = asset.name; spinner.text = `Generating ${asset.name} (${this.progress.completed + 1}/${this.progress.total})`; try { const result = await this.generateSingleAsset(asset); if (result.success) { this.progress.completed++; this.progress.totalCost += result.cost; } else { this.progress.failed++; console.warn(`\nāš ļø Failed to generate ${asset.name}: ${result.error || 'Unknown error'}`); } } catch (error) { this.progress.failed++; console.error(`\nāŒ Error generating ${asset.name}:`, error.message); } } spinner.succeed(`Generated ${this.progress.completed} assets`); } async generateSingleAsset(asset) { const startTime = Date.now(); try { // Ensure output directory exists await fs_1.promises.mkdir(path.dirname(asset.outputPath), { recursive: true }); // Validate model exists (0, model_registry_js_1.getModelConfig)(asset.model); // Generate asset using universal generator const result = await this.generator.generate({ prompt: asset.prompt, model: asset.model, aspectRatio: asset.aspectRatio, outputFormat: asset.format === 'png' ? 'png' : 'jpg' }); // Download generated asset await this.downloadAsset(result.url, asset.outputPath); const duration = Date.now() - startTime; return { success: true, assetPath: asset.outputPath, cost: result.cost, duration }; } catch (error) { return { success: false, assetPath: asset.outputPath, cost: 0, duration: Date.now() - startTime, error: error.message }; } } async downloadAsset(url, outputPath) { const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default; const response = await axios.get(url, { responseType: 'stream' }); const writer = require('fs').createWriteStream(outputPath); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); } async convertToPng(filePath) { // Use sips on macOS to convert to PNG if (process.platform === 'darwin') { const { spawn } = require('child_process'); const newPath = filePath.replace(/\.[^.]+$/, '.png'); return new Promise((resolve, reject) => { const sips = spawn('sips', ['-s', 'format', 'png', filePath, '--out', newPath]); sips.on('close', (code) => { if (code === 0) { // Remove original file fs_1.promises.unlink(filePath).then(resolve).catch(reject); } else { reject(new Error(`sips conversion failed with code ${code}`)); } }); }); } } showSummary() { console.log(chalk_1.default.green.bold('\nšŸŽ‰ Generation Complete!\n')); console.log(`šŸ“Š Summary:`); console.log(` āœ… Generated: ${chalk_1.default.green(this.progress.completed)} assets`); console.log(` āŒ Failed: ${chalk_1.default.red(this.progress.failed)} assets`); console.log(` šŸ’° Total cost: ${chalk_1.default.yellow(`$${this.progress.totalCost.toFixed(3)}`)}`); if (this.progress.failed > 0) { console.log(chalk_1.default.yellow('\nāš ļø Some assets failed to generate. Check the logs above for details.')); } } } exports.AssetCLI = AssetCLI; //# sourceMappingURL=asset-cli.js.map