@bramato/openrouter-mock-generator
Version:
AI-powered mock data generator using OpenRouter API with JSON mode support
294 lines • 13.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockGeneratorService = void 0;
const promises_1 = require("fs/promises");
const fs_1 = require("fs");
const pattern_analyzer_1 = require("../utils/pattern-analyzer");
const post_processing_orchestrator_1 = require("./post-processing-orchestrator");
const progress_manager_1 = require("../utils/progress-manager");
const json_analyzer_1 = require("./json-analyzer");
const MockDataAgent_1 = require("../agents/MockDataAgent");
class MockGeneratorService {
constructor(config, enableImageProcessing) {
const openRouterConfig = {
apiKey: process.env.OPENROUTER_API_KEY || '',
baseURL: 'https://openrouter.ai/api/v1',
model: process.env.OPENROUTER_DEFAULT_MODEL || 'anthropic/claude-3.5-sonnet',
};
const agentConfig = {
name: 'mock-data-generator',
type: 'mock-data',
description: 'Professional mock data generator for testing and development',
openRouter: config || openRouterConfig,
temperature: 0.7,
maxTokens: 4000,
features: {
jsonMode: true,
imageGeneration: true,
schemaValidation: true,
batchProcessing: true,
},
};
this.mockAgent = new MockDataAgent_1.MockDataAgent(agentConfig);
this.progressManager = new progress_manager_1.ProgressManager();
this.jsonAnalyzer = new json_analyzer_1.JsonAnalyzer(config);
// Configura il progress manager nell'agent
this.mockAgent.setProgressManager(this.progressManager);
// Auto-detect se abilitare il post-processing se non specificato
const shouldEnableImageProcessing = enableImageProcessing ?? this.shouldEnableImageProcessing();
if (shouldEnableImageProcessing) {
try {
// Tenta di inizializzare il post-processor con la chiave HuggingFace
const hfKey = this.getHuggingFaceApiKey();
this.postProcessor = new post_processing_orchestrator_1.PostProcessingOrchestrator(hfKey || undefined);
console.log('🎨 AI image processing enabled');
}
catch (error) {
console.warn('⚠️ Image processing disabled: Failed to initialize post-processor');
}
}
else {
console.log('📋 AI image processing disabled - using placeholder images');
}
}
shouldEnableImageProcessing() {
try {
// Controlla se c'è configurazione per image processing nel .env
const hfKey = this.getHuggingFaceApiKey();
const hasStorageProvider = process.env.STORAGE_PROVIDER || this.getEnvValue('STORAGE_PROVIDER');
// Abilita se ha almeno una configurazione di image processing
return !!(hfKey || hasStorageProvider);
}
catch {
return false;
}
}
getEnvValue(key) {
try {
const fs = require('fs');
const path = require('path');
const envPath = path.join(process.cwd(), '.env');
if (fs.existsSync(envPath)) {
const envContent = fs.readFileSync(envPath, 'utf8');
const match = envContent.match(new RegExp(`${key}=(.+)`));
return match ? match[1].trim() : null;
}
}
catch (error) {
// Ignora errori
}
return null;
}
getHuggingFaceApiKey() {
try {
// Cerca nelle variabili d'ambiente
if (process.env.HUGGINGFACE_API_KEY) {
return process.env.HUGGINGFACE_API_KEY;
}
// Cerca nel file .env (sync per compatibilità con costruttore)
const fs = require('fs');
const path = require('path');
const envPath = path.join(process.cwd(), '.env');
if (fs.existsSync(envPath)) {
const envContent = fs.readFileSync(envPath, 'utf8');
const match = envContent.match(/HUGGINGFACE_API_KEY=(.+)/);
return match ? match[1].trim() : null;
}
}
catch (error) {
// Ignora errori, il post-processing funzionerà comunque senza chiave API
}
return null;
}
async fileExists(filePath) {
try {
await (0, promises_1.access)(filePath, fs_1.constants.F_OK);
return true;
}
catch {
return false;
}
}
calculateOptimalBatchSize(sampleItem) {
return this.mockAgent.calculateOptimalBatchSize(sampleItem);
}
async generateSingleBatch(sampleItem, count, preferences, batchNumber, totalBatches) {
return await this.mockAgent.generateMockItems(sampleItem, count, preferences, batchNumber, totalBatches);
}
async appendToJsonFile(filePath, newItems, isFirstBatch) {
if (isFirstBatch) {
const jsonContent = JSON.stringify(newItems, null, 2);
await (0, promises_1.writeFile)(filePath, jsonContent, 'utf8');
}
else {
const existingContent = await (0, promises_1.readFile)(filePath, 'utf8');
const existingData = JSON.parse(existingContent);
if (!Array.isArray(existingData)) {
throw new Error('Output file does not contain a JSON array');
}
const mergedData = [...existingData, ...newItems];
const jsonContent = JSON.stringify(mergedData, null, 2);
await (0, promises_1.writeFile)(filePath, jsonContent, 'utf8');
}
}
async generateMockData(request) {
try {
// Clear output file at the beginning
await (0, promises_1.writeFile)(request.outputFile, '[]', 'utf8');
const inputContent = await (0, promises_1.readFile)(request.inputFile, 'utf8');
const inputData = JSON.parse(inputContent);
const analyses = pattern_analyzer_1.PatternAnalyzer.analyzeJsonStructure(inputData);
if (analyses.length === 0) {
return {
success: false,
generatedCount: 0,
outputFile: request.outputFile,
error: 'No arrays found in input file',
};
}
const targetAnalysis = request.arrayPath
? analyses.find(a => a.arrayPath === request.arrayPath)
: pattern_analyzer_1.PatternAnalyzer.findLargestArray(analyses);
if (!targetAnalysis) {
return {
success: false,
generatedCount: 0,
outputFile: request.outputFile,
error: request.arrayPath
? `No array found at path: ${request.arrayPath}`
: 'No suitable array found for mock generation',
};
}
const sampleItem = targetAnalysis.sampleItem;
const optimalBatchSize = this.calculateOptimalBatchSize(sampleItem);
const totalBatches = Math.ceil(request.count / optimalBatchSize);
let generatedCount = 0;
// Mostra informazioni sul modello AI in uso
const currentModel = this.mockAgent.getCurrentModel();
console.log(`🤖 Modello AI: ${currentModel}`);
if (totalBatches > 1) {
console.log(`📦 Processamento in ${totalBatches} batch (dimensione ottimale: ${optimalBatchSize})`);
}
// Setup progress bars per il nuovo flusso
const enableImageProcessing = this.postProcessor && request.enableImageProcessing !== false;
if (enableImageProcessing) {
this.progressManager.initMultiBar();
}
const mockBar = enableImageProcessing
? this.progressManager.addBar('mock', {
title: '🎲 Dati Mock',
total: request.count,
})
: this.progressManager.createMockGenerationBar(request.count);
// Aggiungi progress bar per immagini se abilitato
let imageBar = null;
if (enableImageProcessing) {
imageBar = this.progressManager.addBar('images', {
title: '🖼️ Immagini AI',
total: request.count, // Approssimiamo con il numero di elementi
});
}
for (let batch = 0; batch < totalBatches; batch++) {
const remainingItems = request.count - generatedCount;
const currentBatchSize = Math.min(optimalBatchSize, remainingItems);
// STEP 1: Genera batch di dati mock
const newItems = await this.generateSingleBatch(sampleItem, currentBatchSize, request.preferences, batch + 1, totalBatches);
// STEP 2: Post-processing per immagini se abilitato
let processedItems = newItems;
if (enableImageProcessing && this.postProcessor) {
try {
processedItems = await this.processBatchImages(newItems, batch + 1, totalBatches);
}
catch (error) {
console.warn(`⚠️ Image processing failed for batch ${batch + 1}:`, error);
// Continua con i dati originali
}
}
// STEP 3: Append dei dati processati al file finale
await this.appendToJsonFile(request.outputFile, processedItems, batch === 0);
generatedCount += processedItems.length;
// Aggiorna progress bar
if (enableImageProcessing) {
this.progressManager.updateBar('mock', generatedCount, {
status: `Batch ${batch + 1}/${totalBatches} processato`,
});
}
else {
mockBar.update(generatedCount, {
status: `Batch ${batch + 1}/${totalBatches} completato`,
});
}
// Dynamic delay based on batch size
const delay = Math.max(500, currentBatchSize * 200);
await new Promise(resolve => setTimeout(resolve, delay));
}
// Completa la progress bar
if (enableImageProcessing) {
this.progressManager.completeBar('mock', '✅ Completato');
this.progressManager.stopAll();
}
else {
mockBar.stop();
}
return {
success: true,
generatedCount,
outputFile: request.outputFile,
};
}
catch (error) {
return {
success: false,
generatedCount: 0,
outputFile: request.outputFile,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
/**
* Processa le immagini di un singolo batch
*/
async processBatchImages(items, batchNumber, totalBatches) {
if (!this.postProcessor || items.length === 0) {
return items;
}
console.log(`\n🎨 Processing images for batch ${batchNumber}/${totalBatches} (${items.length} items)...`);
// STEP 1: Analizza ogni item per generare descrizioni AI personalizzate
const descriptions = await this.jsonAnalyzer.analyzeBatchForImageDescriptions(items, (current, total, item) => {
console.log(` 📝 Analyzing item ${current}/${total} for image descriptions...`);
});
console.log(` ✅ Generated ${descriptions.size} sets of image descriptions`);
// STEP 2: Processa il batch attraverso il PostProcessingOrchestrator
// con le descrizioni personalizzate
try {
// Setup progress callback per immagini
const imageProgressCallback = (current, total, status) => {
this.progressManager.updateBar('images', current, {
status: status || `Batch ${batchNumber}/${totalBatches}`,
});
};
// Configura il post-processor con callback personalizzati
const originalOptions = this.postProcessor['options'];
this.postProcessor['options'] = {
...originalOptions,
onImageProgress: imageProgressCallback,
customDescriptions: descriptions, // Passa le descrizioni personalizzate
};
const result = await this.postProcessor.processData(items);
if (result.success) {
console.log(` ✅ Batch ${batchNumber} processed: ${result.processedImageCount} images`);
return result.processedData;
}
else {
console.warn(` ⚠️ Batch ${batchNumber} processing failed:`, result.errors);
return items; // Fallback ai dati originali
}
}
catch (error) {
console.warn(` ❌ Batch ${batchNumber} processing error:`, error);
return items; // Fallback ai dati originali
}
}
}
exports.MockGeneratorService = MockGeneratorService;
//# sourceMappingURL=mock-generator.js.map