Configuration

Guide de configuration et de configuration pour Qwen Image Edit

Configuration

Guide complet pour configurer Qwen Image Edit selon vos besoins, de l'installation de base aux paramètres avancés.

🚀 Configuration Initiale

Variables d'Environnement

Créez un fichier .env à la racine de votre projet :

# Configuration de base
QWEN_API_KEY=votre_cle_api_ici
QWEN_REGION=eu-west-1
QWEN_TIMEOUT=30000

# Configuration avancée
QWEN_MAX_RETRIES=3
QWEN_RETRY_DELAY=1000
QWEN_MAX_CONCURRENCY=5

# Cache
QWEN_CACHE_ENABLED=true
QWEN_CACHE_TTL=3600
QWEN_CACHE_MAX_SIZE=100

# Logging
QWEN_LOG_LEVEL=info
QWEN_LOG_FILE=./logs/qwen.log

# Proxy (optionnel)
QWEN_PROXY_HOST=proxy.example.com
QWEN_PROXY_PORT=8080
QWEN_PROXY_USERNAME=user
QWEN_PROXY_PASSWORD=pass

Configuration du Client

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

// Configuration de base
const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  region: process.env.QWEN_REGION || 'eu-west-1'
});

// Configuration complète
const editorAvance = new QwenImageEdit({
  // Authentification
  apiKey: process.env.QWEN_API_KEY,
  region: 'eu-west-1',
  
  // Timeouts et retries
  timeout: 30000,
  retries: 3,
  retryDelay: 1000,
  
  // Concurrence
  maxConcurrency: 5,
  
  // Cache
  cache: {
    enabled: true,
    ttl: 3600,
    maxSize: 100,
    type: 'memory' // 'memory', 'redis', 'file'
  },
  
  // Proxy
  proxy: {
    host: 'proxy.example.com',
    port: 8080,
    protocol: 'http',
    auth: {
      username: 'user',
      password: 'pass'
    }
  },
  
  // Logging
  logging: {
    level: 'info',
    destination: './logs/qwen.log',
    format: 'json',
    maxFiles: 5,
    maxSize: '10MB'
  },
  
  // Webhooks
  webhooks: {
    endpoint: 'https://votre-site.com/webhook',
    secret: 'votre_secret',
    events: ['processing.completed', 'processing.failed']
  }
});

🗄️ Configuration du Cache

Cache en Mémoire

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  cache: {
    type: 'memory',
    enabled: true,
    ttl: 3600, // 1 heure
    maxSize: 100, // 100 entrées max
    checkPeriod: 600 // Vérification toutes les 10 minutes
  }
});

Cache Redis

import Redis from 'ioredis';

const redis = new Redis({
  host: 'localhost',
  port: 6379,
  password: 'votre_mot_de_passe',
  db: 0
});

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  cache: {
    type: 'redis',
    enabled: true,
    ttl: 7200, // 2 heures
    client: redis,
    keyPrefix: 'qwen:cache:',
    compression: true
  }
});

Cache Fichier

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  cache: {
    type: 'file',
    enabled: true,
    ttl: 86400, // 24 heures
    directory: './cache/qwen',
    maxSize: '1GB',
    compression: true
  }
});

Cache Personnalisé

class CachePersonnalise {
  constructor() {
    this.cache = new Map();
  }
  
  async get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }
    
    return item.value;
  }
  
  async set(key, value, ttl = 3600) {
    this.cache.set(key, {
      value,
      expiry: Date.now() + (ttl * 1000)
    });
  }
  
  async delete(key) {
    this.cache.delete(key);
  }
  
  async clear() {
    this.cache.clear();
  }
}

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  cache: {
    type: 'custom',
    enabled: true,
    client: new CachePersonnalise()
  }
});

🌐 Configuration Proxy

Proxy HTTP

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  proxy: {
    protocol: 'http',
    host: 'proxy.entreprise.com',
    port: 8080,
    auth: {
      username: 'utilisateur',
      password: 'mot_de_passe'
    },
    timeout: 10000
  }
});

Proxy SOCKS

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  proxy: {
    protocol: 'socks5',
    host: 'socks-proxy.com',
    port: 1080,
    auth: {
      username: 'user',
      password: 'pass'
    }
  }
});

Proxy avec Certificats

import fs from 'fs';

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  proxy: {
    protocol: 'https',
    host: 'secure-proxy.com',
    port: 443,
    ca: fs.readFileSync('./certs/ca.pem'),
    cert: fs.readFileSync('./certs/client.pem'),
    key: fs.readFileSync('./certs/client-key.pem'),
    rejectUnauthorized: true
  }
});

🏗️ Configuration par Environnement

Développement

// config/development.js
export default {
  apiKey: process.env.QWEN_API_KEY,
  region: 'eu-west-1',
  timeout: 60000, // Plus long pour le debug
  retries: 1, // Moins de retries
  cache: {
    enabled: false // Pas de cache en dev
  },
  logging: {
    level: 'debug',
    destination: 'console',
    format: 'pretty'
  },
  webhooks: {
    endpoint: 'http://localhost:3000/webhook'
  }
};

Production

// config/production.js
export default {
  apiKey: process.env.QWEN_API_KEY,
  region: process.env.QWEN_REGION,
  timeout: 30000,
  retries: 3,
  retryDelay: 2000,
  maxConcurrency: 10,
  cache: {
    enabled: true,
    type: 'redis',
    ttl: 7200,
    client: redisClient
  },
  logging: {
    level: 'warn',
    destination: './logs/qwen-prod.log',
    format: 'json',
    maxFiles: 10,
    maxSize: '50MB'
  },
  webhooks: {
    endpoint: 'https://api.monsite.com/webhook',
    secret: process.env.WEBHOOK_SECRET
  }
};

Test

// config/test.js
export default {
  apiKey: 'test_key',
  region: 'eu-west-1',
  timeout: 5000,
  retries: 0,
  cache: {
    enabled: false
  },
  logging: {
    level: 'error',
    destination: 'console'
  },
  mock: true // Utiliser des réponses mockées
};

Chargement de Configuration

// config/index.js
import development from './development.js';
import production from './production.js';
import test from './test.js';

const configs = {
  development,
  production,
  test
};

const env = process.env.NODE_ENV || 'development';
export default configs[env];

// app.js
import config from './config/index.js';
import { QwenImageEdit } from 'qwen-image-edit';

const editor = new QwenImageEdit(config);

📝 Configuration du Logging

Logging Basique

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logging: {
    level: 'info', // 'debug', 'info', 'warn', 'error'
    destination: './logs/qwen.log'
  }
});

Logging Avancé

import winston from 'winston';

// Logger personnalisé
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ 
      filename: './logs/qwen-error.log', 
      level: 'error' 
    }),
    new winston.transports.File({ 
      filename: './logs/qwen-combined.log' 
    }),
    new winston.transports.Console({
      format: winston.format.simple()
    })
  ]
});

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logging: {
    logger: logger,
    logRequests: true,
    logResponses: true,
    logErrors: true,
    sensitiveFields: ['apiKey', 'password'] // Champs à masquer
  }
});

Logging Structuré

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logging: {
    level: 'info',
    format: 'json',
    destination: './logs/qwen.log',
    fields: {
      service: 'qwen-image-edit',
      version: '1.0.0',
      environment: process.env.NODE_ENV
    },
    rotation: {
      maxFiles: 5,
      maxSize: '10MB',
      datePattern: 'YYYY-MM-DD'
    }
  }
});

🔒 Configuration de Sécurité

Validation des Entrées

import Joi from 'joi';

const schemaValidation = {
  editText: Joi.object({
    image: Joi.alternatives().try(
      Joi.string().uri(),
      Joi.string().dataUri(),
      Joi.object().instance(Buffer),
      Joi.object().instance(File)
    ).required(),
    prompt: Joi.string().min(1).max(1000).required(),
    options: Joi.object({
      preserveStyle: Joi.boolean(),
      language: Joi.string().length(2),
      fontSize: Joi.string().valid('small', 'medium', 'large'),
      // ... autres validations
    })
  })
};

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  validation: {
    enabled: true,
    schemas: schemaValidation,
    strict: true
  }
});

Rotation des Clés API

class GestionnaireClésAPI {
  constructor() {
    this.cles = [
      process.env.QWEN_API_KEY_1,
      process.env.QWEN_API_KEY_2,
      process.env.QWEN_API_KEY_3
    ];
    this.indexActuel = 0;
  }
  
  obtenirCleActuelle() {
    return this.cles[this.indexActuel];
  }
  
  changerCle() {
    this.indexActuel = (this.indexActuel + 1) % this.cles.length;
    console.log(`Changement vers la clé ${this.indexActuel + 1}`);
  }
  
  marquerCleInvalide() {
    console.warn(`Clé ${this.indexActuel + 1} marquée comme invalide`);
    this.changerCle();
  }
}

const gestionnaireCles = new GestionnaireClésAPI();

const editor = new QwenImageEdit({
  apiKey: gestionnaireCles.obtenirCleActuelle(),
  region: 'eu-west-1',
  onError: (error) => {
    if (error.code === 'INVALID_API_KEY') {
      gestionnaireCles.marquerCleInvalide();
      // Recréer l'instance avec la nouvelle clé
      editor.updateConfig({
        apiKey: gestionnaireCles.obtenirCleActuelle()
      });
    }
  }
});

Limitation de Débit

import { RateLimiter } from 'limiter';

const limiteur = new RateLimiter({
  tokensPerInterval: 10,
  interval: 'minute'
});

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  rateLimiter: {
    enabled: true,
    limiter: limiteur,
    onLimitReached: (retryAfter) => {
      console.log(`Limite atteinte, retry dans ${retryAfter}ms`);
    }
  }
});

⚡ Configuration des Performances

Pool de Connexions

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

Compression d'Images

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  compression: {
    enabled: true,
    quality: 85,
    maxWidth: 2048,
    maxHeight: 2048,
    format: 'webp', // Format de sortie préféré
    progressive: true
  }
});

Gestion Mémoire

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  memory: {
    maxImageSize: 50 * 1024 * 1024, // 50MB
    maxCacheSize: 100 * 1024 * 1024, // 100MB
    gcInterval: 300000, // Garbage collection toutes les 5 minutes
    lowMemoryThreshold: 0.8 // 80% de la mémoire disponible
  }
});

📊 Configuration du Monitoring

Métriques

import { createPrometheusMetrics } from 'prom-client';

const metriques = createPrometheusMetrics();

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  metrics: {
    enabled: true,
    provider: 'prometheus',
    client: metriques,
    labels: {
      service: 'qwen-image-edit',
      version: '1.0.0'
    },
    collectDefaultMetrics: true
  }
});

Health Checks

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  healthCheck: {
    enabled: true,
    interval: 60000, // Vérification toutes les minutes
    timeout: 5000,
    endpoint: '/health',
    onHealthy: () => console.log('✅ Service en bonne santé'),
    onUnhealthy: (error) => console.error('❌ Service défaillant:', error)
  }
});

// Endpoint de health check
app.get('/health', async (req, res) => {
  try {
    const sante = await editor.checkHealth();
    res.status(200).json(sante);
  } catch (error) {
    res.status(503).json({ status: 'unhealthy', error: error.message });
  }
});

🛠️ Configuration de Développement

Hot Reload

// En mode développement
if (process.env.NODE_ENV === 'development') {
  const editor = new QwenImageEdit({
    apiKey: process.env.QWEN_API_KEY,
    hotReload: {
      enabled: true,
      watchFiles: ['./config/**/*.js'],
      onReload: (newConfig) => {
        console.log('🔄 Configuration rechargée');
        editor.updateConfig(newConfig);
      }
    }
  });
}

Mock pour Tests

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  mock: {
    enabled: process.env.NODE_ENV === 'test',
    responses: {
      editText: {
        imageUrl: 'https://example.com/mock-image.jpg',
        credits: 1,
        processingTime: 100
      },
      analyzeImage: {
        text: [{ content: 'Mock text', confidence: 0.95 }],
        objects: [{ name: 'mock object', confidence: 0.9 }]
      }
    },
    delay: 500 // Simuler la latence réseau
  }
});

📋 Bonnes Pratiques

Configuration Centralisée

// config/qwen.js
class ConfigurationQwen {
  constructor() {
    this.config = this.chargerConfiguration();
  }
  
  chargerConfiguration() {
    const env = process.env.NODE_ENV || 'development';
    
    const configBase = {
      apiKey: process.env.QWEN_API_KEY,
      region: process.env.QWEN_REGION || 'eu-west-1'
    };
    
    const configsEnv = {
      development: {
        ...configBase,
        timeout: 60000,
        logging: { level: 'debug' },
        cache: { enabled: false }
      },
      production: {
        ...configBase,
        timeout: 30000,
        logging: { level: 'warn' },
        cache: { enabled: true, type: 'redis' }
      },
      test: {
        ...configBase,
        mock: { enabled: true },
        logging: { level: 'error' }
      }
    };
    
    return configsEnv[env] || configsEnv.development;
  }
  
  obtenirConfig() {
    return this.config;
  }
  
  mettreAJourConfig(nouvelleConfig) {
    this.config = { ...this.config, ...nouvelleConfig };
  }
}

export default new ConfigurationQwen();

Validation de Configuration

import Joi from 'joi';

const schemaConfig = Joi.object({
  apiKey: Joi.string().required(),
  region: Joi.string().valid('eu-west-1', 'us-east-1', 'ap-southeast-1').required(),
  timeout: Joi.number().min(1000).max(300000),
  retries: Joi.number().min(0).max(10),
  cache: Joi.object({
    enabled: Joi.boolean(),
    type: Joi.string().valid('memory', 'redis', 'file'),
    ttl: Joi.number().min(60)
  }),
  logging: Joi.object({
    level: Joi.string().valid('debug', 'info', 'warn', 'error'),
    destination: Joi.string()
  })
});

function validerConfiguration(config) {
  const { error, value } = schemaConfig.validate(config);
  
  if (error) {
    throw new Error(`Configuration invalide: ${error.message}`);
  }
  
  return value;
}

// Utilisation
try {
  const configValidee = validerConfiguration(config);
  const editor = new QwenImageEdit(configValidee);
} catch (error) {
  console.error('Erreur de configuration:', error.message);
  process.exit(1);
}

Gestion des Secrets

// Utilisation d'un gestionnaire de secrets
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';

class GestionnaireSecrets {
  constructor() {
    this.client = new SecretManagerServiceClient();
  }
  
  async obtenirSecret(nom) {
    const [version] = await this.client.accessSecretVersion({
      name: `projects/mon-projet/secrets/${nom}/versions/latest`
    });
    
    return version.payload.data.toString();
  }
}

const gestionnaire = new GestionnaireSecrets();

// Configuration avec secrets sécurisés
const editor = new QwenImageEdit({
  apiKey: await gestionnaire.obtenirSecret('qwen-api-key'),
  region: 'eu-west-1',
  webhooks: {
    secret: await gestionnaire.obtenirSecret('webhook-secret')
  }
});

Configuration terminée ! Votre instance Qwen Image Edit est maintenant optimisée pour votre environnement.