Dépannage

Solutions aux problèmes courants et conseils de dépannage

Guide de Dépannage

Résolvez rapidement les problèmes les plus courants rencontrés avec Qwen Image Edit.

🔐 Erreurs d'Authentification

Clé API Invalide

Erreur : INVALID_API_KEY

Error: Invalid API key provided
Code: INVALID_API_KEY
Status: 401

Solutions :

  1. Vérifiez votre clé API :

    console.log('Clé API:', process.env.QWEN_API_KEY);
    // Assurez-vous qu'elle commence par 'qwen_' et fait 64 caractères
  2. Vérifiez le fichier .env :

    # .env
    QWEN_API_KEY=qwen_1234567890abcdef...
  3. Régénérez votre clé :

    • Connectez-vous au tableau de bord Qwen
    • Allez dans "API Keys"
    • Créez une nouvelle clé
    • Mettez à jour votre configuration

Région Non Supportée

Erreur : UNSUPPORTED_REGION

Error: Region 'eu-central-1' is not supported
Code: UNSUPPORTED_REGION
Status: 400

Solution :

// Utilisez une région supportée
const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  region: 'eu-west-1' // ✅ Supportée
  // region: 'eu-central-1' // ❌ Non supportée
});

Régions supportées :

  • eu-west-1 (Irlande)
  • us-east-1 (Virginie)
  • ap-southeast-1 (Singapour)
  • ap-northeast-1 (Tokyo)

📊 Problèmes de Quota et Limites

Quota Dépassé

Erreur : QUOTA_EXCEEDED

Error: Monthly quota exceeded. Upgrade your plan or wait for reset.
Code: QUOTA_EXCEEDED
Status: 429

Solutions :

  1. Vérifiez votre quota actuel :

    const quota = await editor.getQuotaInfo();
    console.log('Quota utilisé:', quota.requestsUsed, '/', quota.requestsLimit);
    console.log('Reset le:', new Date(quota.resetDate));
  2. Optimisez vos requêtes :

    // Utilisez le cache pour éviter les requêtes dupliquées
    const editor = new QwenImageEdit({
      apiKey: process.env.QWEN_API_KEY,
      cache: {
        enabled: true,
        ttl: 3600 // 1 heure
      }
    });
  3. Implémentez une gestion gracieuse :

    try {
      const resultat = await editor.editText(options);
    } catch (error) {
      if (error.code === 'QUOTA_EXCEEDED') {
        console.log('Quota dépassé, programmation pour plus tard...');
        // Programmer la requête pour après le reset
        const resetDate = new Date(error.resetDate);
        setTimeout(() => {
          // Réessayer la requête
        }, resetDate.getTime() - Date.now());
      }
    }

Limite de Débit Atteinte

Erreur : RATE_LIMITED

Error: Rate limit exceeded. Try again in 60 seconds.
Code: RATE_LIMITED
Status: 429
Retry-After: 60

Solutions :

  1. Implémentez un retry avec backoff :

    import pRetry from 'p-retry';
    
    async function editTextAvecRetry(options) {
      return pRetry(async () => {
        try {
          return await editor.editText(options);
        } catch (error) {
          if (error.code === 'RATE_LIMITED') {
            const retryAfter = error.retryAfter || 60;
            console.log(`Rate limited, retry dans ${retryAfter}s`);
            await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
            throw error; // Déclenche un retry
          }
          throw new pRetry.AbortError(error); // Pas de retry pour autres erreurs
        }
      }, {
        retries: 3,
        factor: 2
      });
    }
  2. Limitez la concurrence :

    import pLimit from 'p-limit';
    
    const limit = pLimit(2); // Max 2 requêtes simultanées
    
    const promesses = images.map(image => 
      limit(() => editor.editText({ image, prompt: 'Modifier' }))
    );
    
    const resultats = await Promise.allSettled(promesses);

🖼️ Problèmes d'Images

Image Trop Volumineuse

Erreur : IMAGE_TOO_LARGE

Error: Image size exceeds maximum limit of 10MB
Code: IMAGE_TOO_LARGE
Status: 413

Solutions :

  1. Compressez l'image avant envoi :

    import sharp from 'sharp';
    
    async function compresserImage(cheminImage) {
      const buffer = await sharp(cheminImage)
        .resize(2048, 2048, { fit: 'inside', withoutEnlargement: true })
        .jpeg({ quality: 85 })
        .toBuffer();
      
      return buffer;
    }
    
    const imageCompressee = await compresserImage('./grande-image.jpg');
    const resultat = await editor.editText({
      image: imageCompressee,
      prompt: 'Modifier le texte'
    });
  2. Vérifiez la taille avant traitement :

    import fs from 'fs';
    
    function verifierTailleImage(cheminImage) {
      const stats = fs.statSync(cheminImage);
      const tailleMB = stats.size / (1024 * 1024);
      
      if (tailleMB > 10) {
        throw new Error(`Image trop volumineuse: ${tailleMB.toFixed(2)}MB (max: 10MB)`);
      }
      
      return tailleMB;
    }
    
    try {
      const taille = verifierTailleImage('./image.jpg');
      console.log(`Taille de l'image: ${taille.toFixed(2)}MB`);
    } catch (error) {
      console.error(error.message);
    }

Format Non Supporté

Erreur : UNSUPPORTED_FORMAT

Error: Image format 'bmp' is not supported
Code: UNSUPPORTED_FORMAT
Status: 400

Solutions :

  1. Convertissez au bon format :

    import sharp from 'sharp';
    
    async function convertirFormat(cheminImage, formatSortie = 'jpeg') {
      const buffer = await sharp(cheminImage)
        .toFormat(formatSortie)
        .toBuffer();
      
      return buffer;
    }
    
    // Convertir BMP en JPEG
    const imageConvertie = await convertirFormat('./image.bmp', 'jpeg');
    const resultat = await editor.editText({
      image: imageConvertie,
      prompt: 'Modifier'
    });
  2. Vérifiez le format avant traitement :

    import path from 'path';
    
    const formatsSupports = ['.jpg', '.jpeg', '.png', '.webp'];
    
    function verifierFormat(cheminImage) {
      const extension = path.extname(cheminImage).toLowerCase();
      
      if (!formatsSupports.includes(extension)) {
        throw new Error(`Format non supporté: ${extension}. Utilisez: ${formatsSupports.join(', ')}`);
      }
      
      return extension;
    }

🌐 Problèmes Réseau

Timeout de Connexion

Erreur : CONNECTION_TIMEOUT

Error: Request timeout after 30000ms
Code: CONNECTION_TIMEOUT
Status: 408

Solutions :

  1. Augmentez le timeout :

    const editor = new QwenImageEdit({
      apiKey: process.env.QWEN_API_KEY,
      timeout: 60000 // 60 secondes au lieu de 30
    });
  2. Implémentez un retry avec timeout progressif :

    async function editTextAvecTimeoutProgressif(options, tentative = 1) {
      const timeouts = [30000, 45000, 60000]; // Timeouts progressifs
      const timeout = timeouts[tentative - 1] || 60000;
      
      try {
        const editorAvecTimeout = new QwenImageEdit({
          ...editor.config,
          timeout
        });
        
        return await editorAvecTimeout.editText(options);
      } catch (error) {
        if (error.code === 'CONNECTION_TIMEOUT' && tentative < 3) {
          console.log(`Timeout tentative ${tentative}, retry avec timeout ${timeouts[tentative]}ms`);
          return editTextAvecTimeoutProgressif(options, tentative + 1);
        }
        throw error;
      }
    }

Erreur Réseau

Erreur : NETWORK_ERROR

Error: Network error: ENOTFOUND api.qwen.ai
Code: NETWORK_ERROR
Status: 0

Solutions :

  1. Vérifiez la connectivité :

    import { ping } from 'ping';
    
    async function verifierConnectivite() {
      try {
        const resultat = await ping.promise.probe('api.qwen.ai');
        if (!resultat.alive) {
          throw new Error('Impossible de joindre api.qwen.ai');
        }
        console.log('✅ Connectivité OK');
      } catch (error) {
        console.error('❌ Problème de connectivité:', error.message);
      }
    }
  2. Configurez un proxy si nécessaire :

    const editor = new QwenImageEdit({
      apiKey: process.env.QWEN_API_KEY,
      proxy: {
        host: 'proxy.entreprise.com',
        port: 8080,
        auth: {
          username: process.env.PROXY_USER,
          password: process.env.PROXY_PASS
        }
      }
    });

⚙️ Erreurs de Traitement

Échec du Traitement

Erreur : PROCESSING_FAILED

Error: Failed to process image: Unable to detect text in image
Code: PROCESSING_FAILED
Status: 422

Solutions :

  1. Améliorez la qualité de l'image :

    import sharp from 'sharp';
    
    async function ameliorerPourOCR(cheminImage) {
      return await sharp(cheminImage)
        .resize(2048, null, { withoutEnlargement: true })
        .sharpen()
        .normalize()
        .toBuffer();
    }
    
    const imageAmelioree = await ameliorerPourOCR('./image-floue.jpg');
    const resultat = await editor.editText({
      image: imageAmelioree,
      prompt: 'Modifier le texte'
    });
  2. Analysez l'image d'abord :

    // Vérifiez si l'image contient du texte détectable
    const analyse = await editor.analyzeImage({
      image: './image.jpg',
      options: {
        detectText: true,
        confidence: 0.5
      }
    });
    
    if (!analyse.text || analyse.text.length === 0) {
      console.warn('Aucun texte détecté dans l\'image');
    } else {
      console.log('Texte détecté:', analyse.text.map(t => t.content));
      // Procéder avec l'édition
    }

Contenu Non Détecté

Erreur : CONTENT_NOT_DETECTED

Error: No editable content found matching the prompt
Code: CONTENT_NOT_DETECTED
Status: 422

Solutions :

  1. Améliorez votre prompt :

    // ❌ Prompt vague
    const mauvais = await editor.editText({
      image: './affiche.jpg',
      prompt: 'Changer le texte'
    });
    
    // ✅ Prompt spécifique
    const bon = await editor.editText({
      image: './affiche.jpg',
      prompt: 'Remplacer le mot "Concert" par "Festival" dans le titre principal'
    });
  2. Utilisez l'analyse pour guider vos prompts :

    const analyse = await editor.analyzeImage({
      image: './image.jpg',
      options: { detectText: true }
    });
    
    console.log('Texte disponible:');
    analyse.text.forEach((texte, index) => {
      console.log(`${index + 1}. "${texte.content}" (confiance: ${texte.confidence})`);
    });
    
    // Utilisez le texte détecté dans votre prompt
    const resultat = await editor.editText({
      image: './image.jpg',
      prompt: `Remplacer "${analyse.text[0].content}" par "Nouveau texte"`
    });

🐌 Problèmes de Performance

Traitement Lent

Symptôme : Les requêtes prennent plus de 30 secondes

Solutions :

  1. Optimisez la taille des images :

    async function optimiserPourVitesse(cheminImage) {
      return await sharp(cheminImage)
        .resize(1024, 1024, { fit: 'inside', withoutEnlargement: true })
        .jpeg({ quality: 80 })
        .toBuffer();
    }
  2. Utilisez le traitement asynchrone pour les gros volumes :

    // Pour les traitements longs
    const job = await editor.editTextAsync({
      image: './grande-image.jpg',
      prompt: 'Traitement complexe',
      callbackUrl: 'https://monsite.com/callback'
    });
    
    console.log('Job démarré:', job.id);
    
    // Vérifier le statut périodiquement
    const interval = setInterval(async () => {
      const statut = await editor.getJobStatus(job.id);
      console.log('Progression:', statut.progress + '%');
      
      if (statut.status === 'completed') {
        clearInterval(interval);
        console.log('Résultat:', statut.result);
      }
    }, 5000);

Mémoire Insuffisante

Erreur : INSUFFICIENT_MEMORY

Error: Insufficient memory to process image
Code: INSUFFICIENT_MEMORY
Status: 507

Solutions :

  1. Traitez les images par lots plus petits :

    import pLimit from 'p-limit';
    
    const limit = pLimit(1); // Une seule image à la fois
    
    async function traiterParLots(images, tailleLot = 5) {
      const resultats = [];
      
      for (let i = 0; i < images.length; i += tailleLot) {
        const lot = images.slice(i, i + tailleLot);
        console.log(`Traitement du lot ${Math.floor(i/tailleLot) + 1}/${Math.ceil(images.length/tailleLot)}`);
        
        const resultatsLot = await Promise.allSettled(
          lot.map(image => limit(() => editor.editText({
            image,
            prompt: 'Modifier'
          })))
        );
        
        resultats.push(...resultatsLot);
        
        // Pause entre les lots pour libérer la mémoire
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
      
      return resultats;
    }
  2. Libérez la mémoire explicitement :

    async function traiterAvecNettoyage(images) {
      for (const image of images) {
        try {
          const resultat = await editor.editText({ image, prompt: 'Modifier' });
          console.log('Traité:', resultat.imageUrl);
        } catch (error) {
          console.error('Erreur:', error.message);
        }
        
        // Forcer le garbage collection si disponible
        if (global.gc) {
          global.gc();
        }
      }
    }

🔧 Outils de Débogage

Logging Détaillé

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  logging: {
    level: 'debug',
    destination: 'console',
    logRequests: true,
    logResponses: true,
    logErrors: true
  }
});

// Activer le logging pour une requête spécifique
editor.on('request', (data) => {
  console.log('📤 Requête:', {
    method: data.method,
    url: data.url,
    headers: data.headers,
    body: data.body ? 'Présent' : 'Absent'
  });
});

editor.on('response', (data) => {
  console.log('📥 Réponse:', {
    status: data.status,
    headers: data.headers,
    duration: data.duration + 'ms'
  });
});

Intercepteur de Requêtes

class IntercepteurDebug {
  constructor(editor) {
    this.editor = editor;
    this.requetes = [];
  }
  
  async intercepter(methode, options) {
    const debut = Date.now();
    const id = Math.random().toString(36).substr(2, 9);
    
    console.log(`🚀 [${id}] Début ${methode}:`, {
      image: typeof options.image,
      prompt: options.prompt?.substring(0, 50) + '...',
      options: Object.keys(options.options || {})
    });
    
    try {
      const resultat = await this.editor[methode](options);
      const duree = Date.now() - debut;
      
      console.log(`✅ [${id}] Succès ${methode} (${duree}ms):`, {
        imageUrl: resultat.imageUrl,
        credits: resultat.credits,
        processingTime: resultat.processingTime
      });
      
      this.requetes.push({
        id,
        methode,
        duree,
        succes: true,
        credits: resultat.credits
      });
      
      return resultat;
    } catch (error) {
      const duree = Date.now() - debut;
      
      console.error(`❌ [${id}] Erreur ${methode} (${duree}ms):`, {
        code: error.code,
        message: error.message,
        status: error.statusCode
      });
      
      this.requetes.push({
        id,
        methode,
        duree,
        succes: false,
        erreur: error.code
      });
      
      throw error;
    }
  }
  
  obtenirStatistiques() {
    const total = this.requetes.length;
    const succes = this.requetes.filter(r => r.succes).length;
    const echecs = total - succes;
    const dureemoyenne = this.requetes.reduce((acc, r) => acc + r.duree, 0) / total;
    const creditsTotal = this.requetes.reduce((acc, r) => acc + (r.credits || 0), 0);
    
    return {
      total,
      succes,
      echecs,
      tauxSucces: ((succes / total) * 100).toFixed(2) + '%',
      dureemoyenne: Math.round(dureemoyenne) + 'ms',
      creditsTotal
    };
  }
}

// Utilisation
const intercepteur = new IntercepteurDebug(editor);

// Wrapper pour les méthodes
const editorDebug = {
  editText: (options) => intercepteur.intercepter('editText', options),
  editElement: (options) => intercepteur.intercepter('editElement', options),
  analyzeImage: (options) => intercepteur.intercepter('analyzeImage', options)
};

// Utiliser l'editor avec debug
const resultat = await editorDebug.editText({
  image: './test.jpg',
  prompt: 'Test'
});

console.log('Statistiques:', intercepteur.obtenirStatistiques());

Health Check

async function verifierSanteService() {
  const tests = [
    {
      nom: 'Connectivité API',
      test: async () => {
        const quota = await editor.getQuotaInfo();
        return quota.requestsRemaining > 0;
      }
    },
    {
      nom: 'Traitement simple',
      test: async () => {
        // Utiliser une petite image de test
        const resultat = await editor.editText({
          image: './test-small.jpg',
          prompt: 'Test de santé'
        });
        return resultat.imageUrl !== null;
      }
    },
    {
      nom: 'Analyse d\'image',
      test: async () => {
        const analyse = await editor.analyzeImage({
          image: './test-small.jpg'
        });
        return analyse.metadata !== null;
      }
    }
  ];
  
  console.log('🏥 Vérification de santé du service...');
  
  for (const test of tests) {
    try {
      const debut = Date.now();
      const resultat = await test.test();
      const duree = Date.now() - debut;
      
      if (resultat) {
        console.log(`✅ ${test.nom} (${duree}ms)`);
      } else {
        console.log(`⚠️ ${test.nom} - Test échoué (${duree}ms)`);
      }
    } catch (error) {
      console.log(`❌ ${test.nom} - Erreur: ${error.message}`);
    }
  }
}

// Exécuter le health check
verifierSanteService();

📞 Support et Assistance

Si vous ne trouvez pas de solution à votre problème :

🌐 Ressources en Ligne

💬 Communauté

📧 Contact Direct

Informations à inclure dans votre demande :

  • Version du SDK
  • Code d'erreur exact
  • Exemple de code reproduisant le problème
  • Logs détaillés
  • Environnement (Node.js version, OS, etc.)