UNPKG

@bramato/openrouter-mock-generator

Version:

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

196 lines (189 loc) 8.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MockDataAgent = void 0; const openrouter_agents_1 = require("openrouter-agents"); class MockDataAgent { constructor(config) { this.client = new openrouter_agents_1.OpenRouterClient(config.openRouter, 'mockGenerator'); this.config = config; } /** * Configura il progress manager per le chiamate API */ setProgressManager(progressManager) { this.progressManager = progressManager; } /** * Ottiene il modello attualmente in uso */ getCurrentModel() { return this.config.openRouter.model; } getSystemPrompt() { return `You are a professional mock data generator. Generate realistic mock data based on the provided schema and examples. CORE REQUIREMENTS: - Generate realistic values that match the context (names, prices, dates, etc.) - Ensure all required fields are present - Use Italian locale for names, addresses, and text when appropriate - For prices, use realistic values with proper formatting - For IDs, use unique sequential numbers starting from a random high number - Return ONLY valid JSON without any markdown formatting or explanations IMAGE GENERATION RULES: - For image URLs, ALWAYS use https://picsum.photos/ with appropriate dimensions - If you see existing image URLs with specific dimensions, maintain the same format but use Picsum Photos - For NULL image fields, generate appropriate Picsum URLs based on field name: * Fields ending with "_1x1" or containing "square": use 400x400 dimensions * Fields ending with "_4x3": use 800x600 dimensions (4:3 ratio) * Fields ending with "_16x9": use 800x450 dimensions (16:9 ratio) * Fields containing "thumb": use 200x200 dimensions * Fields containing "banner" or "header": use 1200x300 dimensions * Generic image fields: use 800x600 dimensions - Add seed parameter based on item name/description for consistent images: https://picsum.photos/800/600?random=SEED - Use a seed derived from the item name, description, or ID to ensure consistent but varied images You MUST return only parseable JSON. No explanations, no code blocks, no markdown.`; } formatOutput(output) { try { // Clean the response from any markdown formatting const cleaned = typeof output === 'string' ? output.replace(/```json|```/g, '').trim() : output; // If it's already an object, return it if (typeof cleaned === 'object') { return cleaned; } // Parse JSON string const parsed = JSON.parse(cleaned); return parsed; } catch (error) { throw new Error(`Failed to parse generated JSON: ${error instanceof Error ? error.message : 'Unknown error'}`); } } // Specialized method for mock data generation async generateMockItems(sampleItem, count, preferences, batchNumber, totalBatches) { const prompt = this.createMockPrompt(sampleItem, count, preferences); const modelName = this.getCurrentModel(); // Mostra informazioni di progresso const batchInfo = batchNumber ? ` (Batch ${batchNumber}/${totalBatches})` : ''; const progressMessage = `🤖 Chiamata API OpenRouter con modello: ${modelName}${batchInfo}...`; // Mostra il messaggio senza progress bar per ora (da implementare meglio in futuro) console.log(progressMessage); try { const response = await this.client.generate(prompt, { forceJson: true, temperature: 0.7, maxTokens: 4000, }); console.log(`✅ ${modelName}: Generati ${count} elementi con successo`); // Parse and format the response const result = this.formatOutput(response); return Array.isArray(result) ? result : [result]; } catch (error) { console.log(`❌ ${modelName}: Errore durante la generazione`); throw new Error(`Failed to generate mock data with ${modelName}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } createMockPrompt(sampleItem, count, preferences) { const basePrompt = `Generate ${count} realistic mock data items based on this example structure: ${JSON.stringify(sampleItem, null, 2)} Requirements: - Keep the same structure and data types - Generate realistic values that match the context (names, prices, dates, etc.) - Ensure all required fields are present - Use Italian locale for names, addresses, and text when appropriate - For prices, use realistic values with proper formatting - For IDs, use unique sequential numbers starting from a random high number IMAGE GENERATION RULES: - For image URLs, ALWAYS use https://picsum.photos/ with appropriate dimensions - If you see existing image URLs with specific dimensions, maintain the same format but use Picsum Photos - For NULL image fields, generate appropriate Picsum URLs based on field name: * Fields ending with "_1x1" or containing "square": use 400x400 dimensions * Fields ending with "_4x3": use 800x600 dimensions (4:3 ratio) * Fields ending with "_16x9": use 800x450 dimensions (16:9 ratio) * Fields containing "thumb": use 200x200 dimensions * Fields containing "banner" or "header": use 1200x300 dimensions * Generic image fields: use 800x600 dimensions - Add seed parameter based on item name/description for consistent images: https://picsum.photos/800/600?random=SEED - Use a seed derived from the item name, description, or ID to ensure consistent but varied images - Example: if generating for "Nencini Sport Milano", use seed like "milano" or the store ID`; // Add custom preferences if provided const preferencesSection = preferences ? `\n\nCUSTOM PREFERENCES:\n${preferences}\nPlease follow these specific preferences while maintaining the required structure and data types.` : ''; const closingPrompt = `\n\n- Return only the JSON array without any markdown formatting or explanations Generate exactly ${count} item${count > 1 ? 's' : ''}.`; return basePrompt + preferencesSection + closingPrompt; } // Utility method to calculate optimal batch size calculateOptimalBatchSize(sampleItem) { const jsonString = JSON.stringify(sampleItem); const itemSizeInChars = jsonString.length; const fieldCount = this.countFields(sampleItem); let complexityScore = 0; if (itemSizeInChars > 5000) complexityScore += 4; else if (itemSizeInChars > 2000) complexityScore += 3; else if (itemSizeInChars > 1000) complexityScore += 2; else if (itemSizeInChars > 500) complexityScore += 1; if (fieldCount > 50) complexityScore += 3; else if (fieldCount > 30) complexityScore += 2; else if (fieldCount > 15) complexityScore += 1; const nestedComplexity = this.calculateNestedComplexity(sampleItem); complexityScore += Math.min(nestedComplexity, 4); let batchSize; if (complexityScore >= 8) batchSize = 1; else if (complexityScore >= 6) batchSize = 2; else if (complexityScore >= 4) batchSize = 3; else if (complexityScore >= 2) batchSize = 5; else batchSize = 10; return batchSize; } countFields(obj, depth = 0) { if (depth > 10 || obj === null || typeof obj !== 'object') return 0; let count = 0; for (const key in obj) { if (obj.hasOwnProperty(key)) { count++; if (typeof obj[key] === 'object' && obj[key] !== null) { count += this.countFields(obj[key], depth + 1); } } } return count; } calculateNestedComplexity(obj, depth = 0) { if (depth > 10 || obj === null || typeof obj !== 'object') return 0; let complexity = 0; for (const key in obj) { if (obj.hasOwnProperty(key)) { const value = obj[key]; if (Array.isArray(value)) { complexity += 2; if (value.length > 0 && typeof value[0] === 'object') { complexity += 1; } } else if (typeof value === 'object' && value !== null) { complexity += 1; complexity += this.calculateNestedComplexity(value, depth + 1); } } } return complexity; } } exports.MockDataAgent = MockDataAgent; //# sourceMappingURL=MockDataAgent.js.map