Configuración

Guía de configuración y configuración para Qwen Image Edit

Configuración Inicial

Variables de Entorno

Configura las variables de entorno necesarias para tu aplicación:

# .env.local
QWEN_API_KEY=tu-clave-api-aqui
QWEN_REGION=us-east-1
QWEN_ENDPOINT=https://api.qwen.com/v1
QWEN_TIMEOUT=30000
QWEN_MAX_RETRIES=3

Configuración del Cliente

import { QwenImageEdit } from 'qwen-image-edit';

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  region: 'us-east-1',
  timeout: 30000,
  maxRetries: 3,
  debug: process.env.NODE_ENV === 'development'
});

Configuración Avanzada

Configuración Completa

interface QwenImageEditConfig {
  // Autenticación
  apiKey: string;
  region?: string;
  endpoint?: string;
  
  // Timeouts y Reintentos
  timeout?: number;           // Timeout en ms (por defecto: 30000)
  maxRetries?: number;        // Reintentos máximos (por defecto: 3)
  retryDelay?: number;        // Delay entre reintentos en ms (por defecto: 1000)
  
  // Caché
  cache?: boolean;            // Habilitar caché (por defecto: false)
  cacheConfig?: CacheConfig;
  
  // Logging y Debug
  debug?: boolean;            // Modo debug (por defecto: false)
  logLevel?: 'error' | 'warn' | 'info' | 'debug';
  
  // Límites
  maxImageSize?: number;      // Tamaño máximo en bytes (por defecto: 25MB)
  maxConcurrent?: number;     // Solicitudes concurrentes (por defecto: 5)
  
  // Webhooks
  webhookSecret?: string;     // Secreto para verificar webhooks
  
  // Proxy
  proxy?: ProxyConfig;
}

Configuración de Caché

interface CacheConfig {
  ttl: number;                // Tiempo de vida en segundos
  maxSize: number;            // Máximo elementos en caché
  storage: 'memory' | 'disk' | 'redis';
  
  // Para storage 'disk'
  cacheDir?: string;
  
  // Para storage 'redis'
  redis?: {
    host: string;
    port: number;
    password?: string;
    db?: number;
  };
}

// Ejemplo de configuración de caché
const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  cache: true,
  cacheConfig: {
    ttl: 3600,                // 1 hora
    maxSize: 1000,
    storage: 'redis',
    redis: {
      host: 'localhost',
      port: 6379,
      password: process.env.REDIS_PASSWORD,
      db: 0
    }
  }
});

Configuración de Proxy

interface ProxyConfig {
  host: string;
  port: number;
  protocol?: 'http' | 'https';
  auth?: {
    username: string;
    password: string;
  };
}

// Ejemplo de configuración de proxy
const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  proxy: {
    host: 'proxy.empresa.com',
    port: 8080,
    protocol: 'https',
    auth: {
      username: process.env.PROXY_USER,
      password: process.env.PROXY_PASS
    }
  }
});

Configuración por Entorno

Desarrollo

// config/development.ts
export const developmentConfig: QwenImageEditConfig = {
  apiKey: process.env.QWEN_API_KEY!,
  region: 'us-east-1',
  timeout: 60000,             // Timeout más largo para debug
  maxRetries: 1,              // Menos reintentos para fallar rápido
  debug: true,                // Habilitar logs debug
  logLevel: 'debug',
  cache: false,               // Sin caché en desarrollo
  maxConcurrent: 2            // Menos concurrencia
};

Producción

// config/production.ts
export const productionConfig: QwenImageEditConfig = {
  apiKey: process.env.QWEN_API_KEY!,
  region: process.env.QWEN_REGION || 'us-east-1',
  timeout: 30000,
  maxRetries: 3,
  debug: false,
  logLevel: 'error',
  cache: true,
  cacheConfig: {
    ttl: 3600,
    maxSize: 10000,
    storage: 'redis',
    redis: {
      host: process.env.REDIS_HOST!,
      port: parseInt(process.env.REDIS_PORT || '6379'),
      password: process.env.REDIS_PASSWORD
    }
  },
  maxConcurrent: 10,
  webhookSecret: process.env.WEBHOOK_SECRET
};

Testing

// config/test.ts
export const testConfig: QwenImageEditConfig = {
  apiKey: 'test-api-key',
  endpoint: 'http://localhost:3001/mock-api',
  timeout: 5000,
  maxRetries: 0,              // Sin reintentos en tests
  debug: false,
  cache: false,
  maxConcurrent: 1            // Secuencial para tests
};

Configuración de Logging

Logger Personalizado

import { Logger } from 'qwen-image-edit';

class CustomLogger implements Logger {
  error(message: string, meta?: any) {
    console.error(`[QWEN ERROR] ${message}`, meta);
    // Enviar a servicio de logging
  }
  
  warn(message: string, meta?: any) {
    console.warn(`[QWEN WARN] ${message}`, meta);
  }
  
  info(message: string, meta?: any) {
    console.info(`[QWEN INFO] ${message}`, meta);
  }
  
  debug(message: string, meta?: any) {
    if (process.env.NODE_ENV === 'development') {
      console.debug(`[QWEN DEBUG] ${message}`, meta);
    }
  }
}

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logger: new CustomLogger()
});

Integración con Winston

import winston from 'winston';
import { QwenImageEdit } from 'qwen-image-edit';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'qwen-error.log', level: 'error' }),
    new winston.transports.File({ filename: 'qwen-combined.log' })
  ]
});

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logger: {
    error: (msg, meta) => logger.error(msg, meta),
    warn: (msg, meta) => logger.warn(msg, meta),
    info: (msg, meta) => logger.info(msg, meta),
    debug: (msg, meta) => logger.debug(msg, meta)
  }
});

Configuración de Seguridad

Validación de Entrada

import Joi from 'joi';

const configSchema = Joi.object({
  apiKey: Joi.string().required(),
  region: Joi.string().valid('us-east-1', 'us-west-2', 'eu-west-1'),
  timeout: Joi.number().min(1000).max(300000),
  maxRetries: Joi.number().min(0).max(10),
  debug: Joi.boolean(),
  maxImageSize: Joi.number().min(1024).max(52428800) // 1KB - 50MB
});

function validateConfig(config: any): QwenImageEditConfig {
  const { error, value } = configSchema.validate(config);
  if (error) {
    throw new Error(`Configuración inválida: ${error.message}`);
  }
  return value;
}

Rotación de Claves API

class RotatingApiKeyProvider {
  private keys: string[];
  private currentIndex = 0;
  
  constructor(keys: string[]) {
    this.keys = keys;
  }
  
  getCurrentKey(): string {
    return this.keys[this.currentIndex];
  }
  
  rotateKey(): void {
    this.currentIndex = (this.currentIndex + 1) % this.keys.length;
  }
}

const keyProvider = new RotatingApiKeyProvider([
  process.env.QWEN_API_KEY_1!,
  process.env.QWEN_API_KEY_2!,
  process.env.QWEN_API_KEY_3!
]);

const editor = new QwenImageEdit({
  apiKey: keyProvider.getCurrentKey(),
  onAuthError: () => {
    keyProvider.rotateKey();
    // Reintentar con nueva clave
  }
});

Configuración de Performance

Pool de Conexiones

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  connectionPool: {
    maxConnections: 20,
    keepAlive: true,
    keepAliveMsecs: 30000,
    timeout: 30000
  }
});

Compresión de Imágenes

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  compression: {
    enabled: true,
    quality: 85,              // Calidad JPEG (1-100)
    format: 'auto',           // 'auto', 'jpeg', 'png', 'webp'
    maxDimension: 2048        // Redimensionar si es mayor
  }
});

Configuración de Memoria

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  memory: {
    maxBufferSize: 100 * 1024 * 1024,  // 100MB
    gcInterval: 60000,                  // Garbage collection cada minuto
    streamThreshold: 10 * 1024 * 1024   // Stream para archivos > 10MB
  }
});

Configuración de Monitoreo

Métricas

import { QwenImageEdit, MetricsCollector } from 'qwen-image-edit';

class CustomMetrics implements MetricsCollector {
  onRequestStart(operacion: string) {
    console.time(`qwen-${operacion}`);
  }
  
  onRequestEnd(operacion: string, exito: boolean, duracion: number) {
    console.timeEnd(`qwen-${operacion}`);
    
    // Enviar métricas a servicio de monitoreo
    this.enviarMetrica({
      operacion,
      exito,
      duracion,
      timestamp: Date.now()
    });
  }
  
  private enviarMetrica(metrica: any) {
    // Implementar envío a DataDog, New Relic, etc.
  }
}

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  metrics: new CustomMetrics()
});

Health Checks

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  healthCheck: {
    enabled: true,
    interval: 30000,          // Cada 30 segundos
    timeout: 5000,
    onHealthChange: (healthy: boolean) => {
      if (!healthy) {
        console.error('Qwen Image Edit no está disponible');
        // Alertar sistema de monitoreo
      }
    }
  }
});

Configuración de Desarrollo

Hot Reload

// webpack.config.js
module.exports = {
  // ... otras configuraciones
  devServer: {
    hot: true,
    proxy: {
      '/api/qwen': {
        target: 'https://api.qwen.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api/qwen': ''
        }
      }
    }
  }
};

Mock para Testing

// __mocks__/qwen-image-edit.ts
export class QwenImageEdit {
  async editText(options: any) {
    return {
      imagenUrl: 'http://localhost:3000/mock-image.jpg',
      imagenOriginal: options.imagen,
      metadatos: {
        ancho: 1024,
        alto: 768,
        formato: 'jpeg',
        tamaño: 102400
      },
      procesamiento: {
        tiempoMs: 1000,
        modelo: 'qwen-mock',
        version: '1.0.0'
      }
    };
  }
}

Mejores Prácticas

1. Separación de Configuración

// config/index.ts
const configs = {
  development: () => import('./development'),
  production: () => import('./production'),
  test: () => import('./test')
};

export async function getConfig() {
  const env = process.env.NODE_ENV || 'development';
  const config = await configs[env]();
  return config.default;
}

2. Validación de Configuración

function validateRequiredEnvVars() {
  const required = ['QWEN_API_KEY'];
  const missing = required.filter(key => !process.env[key]);
  
  if (missing.length > 0) {
    throw new Error(`Variables de entorno faltantes: ${missing.join(', ')}`);
  }
}

validateRequiredEnvVars();

3. Configuración Tipada

interface AppConfig {
  qwen: QwenImageEditConfig;
  server: {
    port: number;
    host: string;
  };
  database: {
    url: string;
  };
}

const config: AppConfig = {
  qwen: {
    apiKey: process.env.QWEN_API_KEY!,
    region: process.env.QWEN_REGION as any,
    timeout: parseInt(process.env.QWEN_TIMEOUT || '30000')
  },
  server: {
    port: parseInt(process.env.PORT || '3000'),
    host: process.env.HOST || 'localhost'
  },
  database: {
    url: process.env.DATABASE_URL!
  }
};

Solución de Problemas

Problemas Comunes

  1. Error de Autenticación

    • Verificar que la clave API sea válida
    • Comprobar que la región sea correcta
  2. Timeouts

    • Aumentar el valor de timeout
    • Verificar conectividad de red
  3. Límites de Cuota

    • Verificar uso actual en el dashboard
    • Considerar actualizar el plan
  4. Errores de Caché

    • Limpiar caché manualmente
    • Verificar configuración de Redis

Debug

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  debug: true,
  logLevel: 'debug',
  onRequest: (config) => {
    console.log('Enviando solicitud:', config);
  },
  onResponse: (response) => {
    console.log('Respuesta recibida:', response);
  },
  onError: (error) => {
    console.error('Error en solicitud:', error);
  }
});