@bramato/openrouter-mock-generator
Version:
AI-powered mock data generator using OpenRouter API with JSON mode support
196 lines (189 loc) • 8.87 kB
JavaScript
;
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