UNPKG

@bramato/openrouter-mock-generator

Version:

AI-powered mock data generator using OpenRouter API with JSON mode support

467 lines 16.1 kB
"use strict"; /** * Microservizio per generare descrizioni contestuali per immagini AI */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DescriptionGenerator = void 0; class DescriptionGenerator { /** * Genera descrizione per una singola immagine */ static generateDescription(imageInfo, options = {}) { const opts = this.normalizeOptions(options); const context = this.analyzeContext(imageInfo); const category = this.determineCategory(imageInfo, context); const basePrompt = this.generateBasePrompt(imageInfo, context, category); const enhancedPrompt = this.enhancePrompt(basePrompt, context, opts); return { prompt: basePrompt, style: opts.style, category, confidence: context.confidence, baseContext: context.description, enhancedPrompt, }; } /** * Genera descrizioni per più immagini ottimizzate per batch processing */ static generateDescriptions(images, options = {}) { const descriptions = new Map(); const opts = this.normalizeOptions(options); // Raggruppa per contesto simile per ottimizzazione const contextGroups = this.groupByContext(images); contextGroups.forEach((groupImages, contextKey) => { const sharedContext = this.extractSharedContext(groupImages); groupImages.forEach(img => { const description = this.generateDescription(img, { ...opts, // Usa contesto condiviso se disponibile ...(sharedContext && { baseContext: sharedContext }), }); descriptions.set(img.path, description); }); }); return descriptions; } /** * Analizza il contesto di un'immagine dai dati circostanti */ static analyzeContext(imageInfo) { const context = imageInfo.context; const fieldName = imageInfo.fieldName; const keywords = []; let description = ''; let confidence = 0.5; // Analizza il nome del campo const fieldAnalysis = this.analyzeFieldName(fieldName); keywords.push(...fieldAnalysis.keywords); confidence += fieldAnalysis.confidence; // Analizza il contesto dei dati if (context && typeof context === 'object') { const contextAnalysis = this.analyzeContextData(context); description = contextAnalysis.description; keywords.push(...contextAnalysis.keywords); confidence += contextAnalysis.confidence; } // Normalizza confidence confidence = Math.min(confidence, 1.0); return { description: description || this.getGenericDescription(fieldName), confidence, keywords: [...new Set(keywords)], // Remove duplicates dataType: this.inferDataType(context), }; } /** * Analizza il nome del campo per estrarre informazioni */ static analyzeFieldName(fieldName) { const name = fieldName.toLowerCase(); const keywords = []; let confidence = 0.1; // Cerca corrispondenze dirette Object.entries(this.FIELD_TYPE_MAPPING).forEach(([key, value]) => { if (name.includes(key)) { keywords.push(key); confidence += 0.2; } }); // Analizza pattern comuni if (name.includes('thumb')) { keywords.push('thumbnail', 'small'); confidence += 0.3; } if (name.includes('_1x1') || name.includes('square')) { keywords.push('square', 'centered'); confidence += 0.2; } if (name.includes('banner') || name.includes('header')) { keywords.push('banner', 'wide', 'header'); confidence += 0.3; } return { keywords, confidence }; } /** * Analizza i dati del contesto per estrarre informazioni semantiche */ static analyzeContextData(context) { const keywords = []; let description = ''; let confidence = 0.2; // Cerca campi descrittivi comuni const descriptiveFields = [ 'name', 'title', 'description', 'caption', 'alt', 'product', 'brand', 'category', 'type', 'style', 'location', 'city', 'address', 'venue', 'place', ]; descriptiveFields.forEach(field => { if (context[field] && typeof context[field] === 'string') { const value = context[field].toLowerCase(); description += ` ${value}`; keywords.push(...this.extractKeywords(value)); confidence += 0.1; } }); // Analizza pattern specifici if (context.price || context.cost || context.amount) { keywords.push('commercial', 'product'); confidence += 0.1; } if (context.author || context.creator || context.artist) { keywords.push('creative', 'professional'); confidence += 0.1; } return { description: description.trim(), keywords: [...new Set(keywords)], confidence: Math.min(confidence, 0.5), }; } /** * Estrae parole chiave da una stringa */ static extractKeywords(text) { const commonWords = new Set([ 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'il', 'la', 'le', 'lo', 'gli', 'un', 'una', 'e', 'o', 'ma', 'in', 'su', 'a', 'per', 'di', 'con', 'da', ]); return text .split(/[\s,.-]+/) .filter(word => word.length > 2 && !commonWords.has(word.toLowerCase())) .slice(0, 5); // Limita a 5 keywords } /** * Determina la categoria principale dell'immagine */ static determineCategory(imageInfo, context) { const fieldName = imageInfo.fieldName.toLowerCase(); // Categorie basate sul nome del campo for (const [key, value] of Object.entries(this.FIELD_TYPE_MAPPING)) { if (fieldName.includes(key)) { return key; } } // Categorie basate sul contesto if (context.keywords.includes('food') || context.keywords.includes('dish')) { return 'food'; } if (context.keywords.includes('fashion') || context.keywords.includes('clothing')) { return 'fashion'; } if (context.keywords.includes('location') || context.keywords.includes('place')) { return 'location'; } return 'generic'; } /** * Genera il prompt base per l'immagine */ static generateBasePrompt(imageInfo, context, category) { const fieldType = this.FIELD_TYPE_MAPPING[category] || 'professional photography'; let prompt = fieldType; // Aggiungi descrizione contestuale se disponibile if (context.description && context.confidence > 0.3) { const cleanDescription = context.description .replace(/[^\w\s]/g, ' ') .replace(/\s+/g, ' ') .trim(); if (cleanDescription.length > 0) { prompt = `${cleanDescription}, ${fieldType}`; } } // Aggiungi specifiche per dimensioni const { width, height } = imageInfo.dimensions; if (width === height) { prompt += ', square composition, centered'; } else if (width > height * 2) { prompt += ', wide banner format, horizontal composition'; } else if (height > width) { prompt += ', vertical composition, portrait orientation'; } return prompt; } /** * Migliora il prompt con stile e preferenze */ static enhancePrompt(basePrompt, context, options) { let enhanced = basePrompt; // Aggiungi stile switch (options.style) { case 'professional': enhanced += ', professional lighting, high quality, clean background'; break; case 'artistic': enhanced += ', artistic composition, creative lighting, aesthetic'; break; case 'realistic': enhanced += ', photorealistic, natural lighting, detailed'; break; case 'casual': enhanced += ', casual style, natural look, everyday setting'; break; } // Aggiungi contesto italiano se richiesto if (options.language === 'italian' && context.keywords.length > 0) { const italianContext = this.getItalianContext(context.keywords); if (italianContext) { enhanced += `, ${italianContext}`; } } // Limita lunghezza se specificato if (options.maxPromptLength && enhanced.length > options.maxPromptLength) { enhanced = enhanced.substring(0, options.maxPromptLength - 3) + '...'; } return enhanced; } /** * Ottiene contesto italiano appropriato */ static getItalianContext(keywords) { for (const [category, contexts] of Object.entries(this.ITALIAN_STYLE_ADDITIONS)) { if (keywords.some(keyword => category.includes(keyword))) { return contexts[Math.floor(Math.random() * contexts.length)]; } } return this.ITALIAN_STYLE_ADDITIONS.italian_context[0]; } /** * Raggruppa immagini per contesto simile */ static groupByContext(images) { const groups = new Map(); images.forEach(img => { const contextKey = this.generateContextKey(img); if (!groups.has(contextKey)) { groups.set(contextKey, []); } groups.get(contextKey).push(img); }); return groups; } /** * Genera chiave di contesto per raggruppamento */ static generateContextKey(imageInfo) { const context = imageInfo.context; const parts = []; // Usa campi identificativi comuni if (context?.category) parts.push(context.category); if (context?.type) parts.push(context.type); if (context?.brand) parts.push(context.brand); // Aggiungi dimensioni per raggruppare formati simili const { width, height } = imageInfo.dimensions; parts.push(`${width}x${height}`); return parts.join('_') || 'generic'; } /** * Estrae contesto condiviso da un gruppo di immagini */ static extractSharedContext(images) { if (images.length < 2) return null; const commonFields = ['category', 'brand', 'type', 'location']; const sharedValues = []; commonFields.forEach(field => { const values = images .map(img => img.context?.[field]) .filter(val => val && typeof val === 'string'); if (values.length === images.length && new Set(values).size === 1) { sharedValues.push(values[0]); } }); return sharedValues.length > 0 ? sharedValues.join(' ') : null; } /** * Normalizza le opzioni con valori di default */ static normalizeOptions(options) { return { language: options.language || 'italian', style: options.style || 'professional', includeBackground: options.includeBackground ?? true, maxPromptLength: options.maxPromptLength || 200, }; } /** * Inferisce il tipo di dati dal contesto */ static inferDataType(context) { if (!context || typeof context !== 'object') return 'unknown'; const fields = Object.keys(context); if (fields.includes('price') && fields.includes('name')) return 'product'; if (fields.includes('author') || fields.includes('creator')) return 'content'; if (fields.includes('address') || fields.includes('location')) return 'place'; if (fields.includes('email') || fields.includes('phone')) return 'person'; return 'generic'; } /** * Ottiene descrizione generica basata sul nome del campo */ static getGenericDescription(fieldName) { const name = fieldName.toLowerCase(); if (name.includes('thumb')) return 'thumbnail image'; if (name.includes('banner')) return 'banner image'; if (name.includes('avatar')) return 'profile picture'; if (name.includes('logo')) return 'logo design'; if (name.includes('background')) return 'background image'; return 'professional image'; } } exports.DescriptionGenerator = DescriptionGenerator; DescriptionGenerator.FIELD_TYPE_MAPPING = { // E-commerce product: 'professional product photography', item: 'clean product shot', article: 'item showcase', goods: 'commercial product', // People avatar: 'professional headshot portrait', profile: 'portrait photography', user: 'person portrait', author: 'professional author photo', customer: 'friendly customer portrait', // Branding logo: 'modern logo design', brand: 'brand identity', company: 'corporate branding', // Content banner: 'professional banner design', header: 'website header image', background: 'clean background texture', hero: 'hero section image', thumbnail: 'preview image', cover: 'cover image design', featured: 'featured content image', // Location location: 'beautiful location photography', place: 'scenic place photograph', destination: 'travel destination', venue: 'venue photography', shop: 'retail store interior', restaurant: 'restaurant ambiance', hotel: 'luxury hotel interior', // Categories specifiche food: 'appetizing food photography', dish: 'gourmet dish presentation', recipe: 'food styling photography', menu: 'restaurant menu photography', fashion: 'fashion photography', clothing: 'clothing product shot', accessory: 'fashion accessory', tech: 'modern technology product', gadget: 'tech gadget photography', sport: 'sports equipment', fitness: 'fitness and wellness', beauty: 'beauty product photography', home: 'home interior design', garden: 'garden and landscape', car: 'automotive photography', book: 'book cover design', art: 'artistic photography', music: 'music related imagery', }; DescriptionGenerator.ITALIAN_STYLE_ADDITIONS = { italian_context: [ 'in Italian style', 'with Italian elegance', 'Italian design aesthetic', 'Mediterranean style', 'classic Italian', ], food: [ 'authentic Italian cuisine', 'traditional Italian dish', 'Italian culinary tradition', 'regional Italian specialty', ], fashion: [ 'Italian fashion style', 'Milano fashion design', 'Italian elegance', 'made in Italy style', ], location: [ 'Italian landscape', 'Italian architecture', 'Italian piazza', 'Mediterranean setting', ], }; //# sourceMappingURL=description-generator.js.map