UNPKG

@bramato/openrouter-mock-generator

Version:

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

253 lines (246 loc) 9.89 kB
"use strict"; /** * JsonAnalyzer - Servizio per analizzare singoli oggetti JSON * e generare descrizioni dettagliate per immagini AI * * Utilizza OpenRouter per analizzare il contesto di ogni dato mock * e creare prompt descrittivi per la generazione di immagini AI appropriate */ Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonAnalyzer = void 0; const openrouter_agents_1 = require("openrouter-agents"); class JsonAnalyzer { constructor(config) { const defaultConfig = { apiKey: process.env.OPENROUTER_API_KEY || '', baseURL: 'https://openrouter.ai/api/v1', model: process.env.OPENROUTER_DEFAULT_MODEL || 'anthropic/claude-3.5-sonnet', }; this.client = new openrouter_agents_1.OpenRouterClient(config || defaultConfig, 'custom'); } /** * Analizza un singolo oggetto JSON per generare descrizioni immagini */ async analyzeForImageDescription(request) { const analysisPrompt = this.createAnalysisPrompt(request); try { const systemPrompt = `Sei un esperto di analisi dati e generazione di immagini AI. Analizza l'oggetto JSON fornito e genera una descrizione dettagliata per creare un'immagine AI appropriata per il campo specificato. Rispondi SEMPRE in formato JSON valido con questa struttura: { "prompt": "descrizione dettagliata per AI image generation", "style": "stile fotografico (es: professional, lifestyle, artistic)", "category": "categoria immagine (es: product, person, landscape)", "confidence": 0.8, "reasoning": "spiegazione del ragionamento", "enhancedPrompt": "prompt ottimizzato con dettagli tecnici" }`; const fullPrompt = `${systemPrompt}\n\n${analysisPrompt}`; const response = await this.client.generate(fullPrompt, { forceJson: true, temperature: 0.3, maxTokens: 1500, }); const content = response; if (!content) { throw new Error('No response content from AI analysis'); } const analysis = JSON.parse(content); // Validation e fallback if (!analysis.prompt || !analysis.enhancedPrompt) { return this.createFallbackDescription(request); } return analysis; } catch (error) { console.warn(`⚠️ AI analysis failed for ${request.fieldName}:`, error); return this.createFallbackDescription(request); } } /** * Analizza batch di oggetti JSON per efficienza */ async analyzeBatchForImageDescriptions(items, onProgress) { const results = new Map(); for (let i = 0; i < items.length; i++) { const item = items[i]; const itemKey = `item_${i}`; const descriptions = []; // Trova tutti i campi immagine nell'oggetto const imageFields = this.findImageFields(item); for (const field of imageFields) { try { const description = await this.analyzeForImageDescription({ jsonData: item, fieldName: field.name, imageUrl: field.url, dimensions: field.dimensions, }); descriptions.push(description); } catch (error) { console.warn(`Failed to analyze ${field.name} for item ${i}:`, error); } } results.set(itemKey, descriptions); // Progress callback if (onProgress) { onProgress(i + 1, items.length, item); } // Rate limiting await new Promise(resolve => setTimeout(resolve, 200)); } return results; } /** * Trova tutti i campi immagine in un oggetto JSON */ findImageFields(obj, prefix = '') { const fields = []; const traverse = (current, path) => { if (typeof current === 'object' && current !== null) { if (Array.isArray(current)) { current.forEach((item, index) => { traverse(item, `${path}[${index}]`); }); } else { Object.keys(current).forEach(key => { const value = current[key]; const fullPath = path ? `${path}.${key}` : key; if (typeof value === 'string' && this.isImageUrl(value)) { const dimensions = this.extractDimensions(value); fields.push({ name: fullPath, url: value, dimensions, }); } else if (typeof value === 'object') { traverse(value, fullPath); } }); } } }; traverse(obj, prefix); return fields; } /** * Verifica se una stringa è un URL di immagine */ isImageUrl(url) { if (typeof url !== 'string') return false; // Check per Picsum URLs if (url.includes('picsum.photos')) return true; // Check per altri URL immagini comuni const imageExtensions = /\.(jpg|jpeg|png|gif|webp|svg)(\?.*)?$/i; const imageHosts = /(images\.|img\.|cdn\.|static\.)/i; return imageExtensions.test(url) || imageHosts.test(url); } /** * Estrae dimensioni da URL Picsum */ extractDimensions(url) { const picsumMatch = url.match(/picsum\.photos\/(\d+)\/(\d+)/); if (picsumMatch) { return { width: parseInt(picsumMatch[1]), height: parseInt(picsumMatch[2]), }; } return undefined; } /** * Crea prompt per analisi AI */ createAnalysisPrompt(request) { const { jsonData, fieldName, imageUrl, dimensions } = request; const contextInfo = this.extractContextInfo(jsonData); const fieldInfo = this.analyzeFieldName(fieldName); const dimensionInfo = dimensions ? `${dimensions.width}x${dimensions.height}` : 'non specificata'; return `Analizza questo oggetto JSON e genera una descrizione per l'immagine AI del campo "${fieldName}": DATI JSON: ${JSON.stringify(jsonData, null, 2)} CAMPO IMMAGINE: ${fieldName} URL ATTUALE: ${imageUrl} DIMENSIONI: ${dimensionInfo} CONTESTO RILEVATO: ${contextInfo} ANALISI CAMPO: ${fieldInfo} Genera una descrizione dettagliata per creare un'immagine AI appropriata che: 1. Rifletta il contesto dell'oggetto JSON 2. Sia coerente con il nome del campo 3. Sia appropriata per le dimensioni specificate 4. Usi uno stile fotografico professionale 5. Includa dettagli specifici basati sui dati Fornisci il risultato in formato JSON come richiesto.`; } /** * Estrae informazioni di contesto dall'oggetto JSON */ extractContextInfo(data) { const info = []; // Cerca campi chiave comuni const keyFields = ['name', 'title', 'type', 'category', 'brand', 'description', 'tags']; keyFields.forEach(field => { if (data[field]) { info.push(`${field}: ${data[field]}`); } }); // Cerca campi prezzo/valuta const priceFields = ['price', 'cost', 'value', 'amount']; priceFields.forEach(field => { if (data[field]) { info.push(`${field}: ${data[field]}`); } }); return info.length > 0 ? info.join(', ') : 'Nessun contesto specifico rilevato'; } /** * Analizza il nome del campo per inferire il tipo di immagine */ analyzeFieldName(fieldName) { const lower = fieldName.toLowerCase(); if (lower.includes('thumb') || lower.includes('thumbnail')) { return 'Immagine thumbnail/miniatura - dovrebbe essere semplice e riconoscibile anche in piccole dimensioni'; } if (lower.includes('banner') || lower.includes('header')) { return 'Immagine banner/header - dovrebbe essere panoramica e visivamente impattante'; } if (lower.includes('profile') || lower.includes('avatar')) { return 'Immagine profilo/avatar - dovrebbe essere centrata su persona o logo'; } if (lower.includes('gallery') || lower.includes('photo')) { return 'Immagine galleria/foto - dovrebbe essere dettagliata e di alta qualità'; } if (lower.includes('icon')) { return 'Icona - dovrebbe essere semplice, simbolica e riconoscibile'; } return 'Immagine generica - dovrebbe rappresentare chiaramente il soggetto'; } /** * Crea descrizione di fallback quando l'AI analysis fallisce */ createFallbackDescription(request) { const contextInfo = this.extractContextInfo(request.jsonData); const fieldAnalysis = this.analyzeFieldName(request.fieldName); const prompt = `${contextInfo}, professional photography, high quality, clean background`; return { prompt, style: 'professional', category: 'generic', confidence: 0.5, reasoning: 'Fallback description generated due to AI analysis failure', enhancedPrompt: `${prompt}, professional lighting, studio setup, commercial grade`, }; } } exports.JsonAnalyzer = JsonAnalyzer; //# sourceMappingURL=json-analyzer.js.map