設定

Qwen Image Edit の設定とセットアップガイド

設定

Qwen Image Editの詳細設定とパフォーマンス最適化について説明します。

🚀 初期設定

環境変数

# .env ファイル
QWEN_API_KEY=qwen_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
QWEN_REGION=ap-northeast-1
QWEN_TIMEOUT=30000
QWEN_MAX_RETRIES=3
QWEN_RETRY_DELAY=1000

基本的なクライアント設定

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

const editor = new QwenImageEdit({
  // 必須設定
  apiKey: process.env.QWEN_API_KEY,
  
  // オプション設定
  region: process.env.QWEN_REGION || 'ap-northeast-1',
  timeout: parseInt(process.env.QWEN_TIMEOUT) || 30000,
  maxRetries: parseInt(process.env.QWEN_MAX_RETRIES) || 3,
  retryDelay: parseInt(process.env.QWEN_RETRY_DELAY) || 1000
});

⚙️ 高度な設定

完全な設定オプション

const editor = new QwenImageEdit({
  // 認証
  apiKey: 'your-api-key',
  region: 'ap-northeast-1',
  
  // ネットワーク設定
  timeout: 30000,           // リクエストタイムアウト(ミリ秒)
  maxRetries: 3,            // 最大再試行回数
  retryDelay: 1000,         // 再試行間隔(ミリ秒)
  retryMultiplier: 2,       // 再試行間隔の倍数
  maxRetryDelay: 10000,     // 最大再試行間隔
  
  // エンドポイント設定
  baseURL: 'https://api.qwen.com/v1',
  apiVersion: 'v1',
  
  // ヘッダー設定
  headers: {
    'User-Agent': 'MyApp/1.0.0',
    'X-Custom-Header': 'custom-value'
  },
  
  // SSL/TLS設定
  ssl: {
    rejectUnauthorized: true,
    ca: fs.readFileSync('ca.pem'),
    cert: fs.readFileSync('cert.pem'),
    key: fs.readFileSync('key.pem')
  },
  
  // プロキシ設定
  proxy: {
    host: 'proxy.example.com',
    port: 8080,
    auth: {
      username: 'proxy-user',
      password: 'proxy-pass'
    }
  },
  
  // キャッシュ設定
  cache: {
    enabled: true,
    ttl: 3600000,           // キャッシュ有効期限(ミリ秒)
    maxSize: 100,           // 最大キャッシュエントリ数
    storage: 'memory'       // 'memory', 'redis', 'file'
  },
  
  // ログ設定
  logging: {
    level: 'info',          // 'debug', 'info', 'warn', 'error'
    format: 'json',         // 'json', 'text'
    destination: 'console'  // 'console', 'file', 'custom'
  }
});

💾 キャッシュ設定

インメモリキャッシュ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  cache: {
    enabled: true,
    storage: 'memory',
    ttl: 3600000,           // 1時間
    maxSize: 100,           // 最大100エントリ
    compression: true       // キャッシュデータを圧縮
  }
});

Redisキャッシュ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  cache: {
    enabled: true,
    storage: 'redis',
    redis: {
      host: 'localhost',
      port: 6379,
      password: 'redis-password',
      db: 0,
      keyPrefix: 'qwen:cache:',
      connectTimeout: 5000,
      lazyConnect: true
    },
    ttl: 7200000,           // 2時間
    compression: true
  }
});

ファイルキャッシュ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  cache: {
    enabled: true,
    storage: 'file',
    file: {
      directory: './cache',
      maxSize: '1GB',
      cleanupInterval: 3600000 // 1時間ごとにクリーンアップ
    },
    ttl: 86400000,          // 24時間
    compression: true
  }
});

カスタムキャッシュ

class CustomCache {
  constructor() {
    this.cache = new Map();
  }
  
  async get(key) {
    const item = this.cache.get(key);
    if (item && Date.now() < item.expiry) {
      return item.value;
    }
    return null;
  }
  
  async set(key, value, ttl) {
    this.cache.set(key, {
      value,
      expiry: Date.now() + ttl
    });
  }
  
  async delete(key) {
    this.cache.delete(key);
  }
  
  async clear() {
    this.cache.clear();
  }
}

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  cache: {
    enabled: true,
    storage: 'custom',
    custom: new CustomCache()
  }
});

🌐 プロキシ設定

HTTPプロキシ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  proxy: {
    protocol: 'http',
    host: 'proxy.company.com',
    port: 8080,
    auth: {
      username: 'proxy-user',
      password: 'proxy-password'
    },
    timeout: 5000
  }
});

SOCKSプロキシ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  proxy: {
    protocol: 'socks5',
    host: 'socks-proxy.example.com',
    port: 1080,
    auth: {
      username: 'socks-user',
      password: 'socks-password'
    }
  }
});

証明書付きプロキシ

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  proxy: {
    host: 'secure-proxy.example.com',
    port: 8443,
    auth: {
      username: 'user',
      password: 'pass'
    },
    ca: fs.readFileSync('./proxy-ca.pem'),
    cert: fs.readFileSync('./client-cert.pem'),
    key: fs.readFileSync('./client-key.pem')
  }
});

🏗️ 環境別設定

開発環境

// config/development.js
module.exports = {
  qwen: {
    apiKey: process.env.QWEN_API_KEY_DEV,
    region: 'ap-northeast-1',
    timeout: 60000,         // 開発時は長めのタイムアウト
    maxRetries: 1,          // 開発時は再試行を少なく
    
    cache: {
      enabled: false        // 開発時はキャッシュを無効
    },
    
    logging: {
      level: 'debug',       // 詳細なログ
      format: 'text',
      destination: 'console'
    },
    
    // 開発用のモック設定
    mock: {
      enabled: true,
      responses: {
        editText: {
          imageUrl: 'https://example.com/mock-image.jpg',
          credits: 1,
          processingTime: 1000
        }
      }
    }
  }
};

本番環境

// config/production.js
module.exports = {
  qwen: {
    apiKey: process.env.QWEN_API_KEY_PROD,
    region: process.env.QWEN_REGION || 'ap-northeast-1',
    timeout: 30000,
    maxRetries: 3,
    retryDelay: 2000,
    
    cache: {
      enabled: true,
      storage: 'redis',
      redis: {
        host: process.env.REDIS_HOST,
        port: process.env.REDIS_PORT,
        password: process.env.REDIS_PASSWORD,
        db: 1
      },
      ttl: 3600000,         // 1時間
      compression: true
    },
    
    logging: {
      level: 'warn',        // 本番では警告以上のみ
      format: 'json',
      destination: 'file',
      file: {
        path: '/var/log/qwen-image-edit.log',
        maxSize: '100MB',
        maxFiles: 10
      }
    },
    
    // 本番用のセキュリティ設定
    security: {
      validateInput: true,
      sanitizePrompts: true,
      rateLimiting: {
        enabled: true,
        maxRequests: 100,
        windowMs: 60000     // 1分間
      }
    }
  }
};

テスト環境

// config/test.js
module.exports = {
  qwen: {
    apiKey: 'test-api-key',
    region: 'ap-northeast-1',
    timeout: 5000,          // テストは短いタイムアウト
    maxRetries: 0,          // テストでは再試行しない
    
    cache: {
      enabled: false        // テストではキャッシュを無効
    },
    
    logging: {
      level: 'error',       // テストではエラーのみ
      destination: 'console'
    },
    
    // テスト用のモック設定
    mock: {
      enabled: true,
      alwaysSucceed: true,
      delay: 100            // 100msの遅延をシミュレート
    }
  }
};

📝 ログ設定

基本的なログ設定

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  logging: {
    level: 'info',          // debug, info, warn, error
    format: 'text',         // text, json
    destination: 'console', // console, file, custom
    timestamp: true,        // タイムスタンプを含める
    requestId: true         // リクエストIDを含める
  }
});

高度なログ設定

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  logging: {
    level: 'debug',
    format: 'json',
    destination: 'file',
    file: {
      path: './logs/qwen-image-edit.log',
      maxSize: '50MB',
      maxFiles: 5,
      compress: true
    },
    
    // ログフィルター
    filters: {
      excludeHeaders: ['authorization'],
      excludeBody: true,
      includeResponseTime: true
    },
    
    // 構造化ログ
    structured: {
      service: 'qwen-image-edit',
      version: '1.0.0',
      environment: process.env.NODE_ENV
    }
  }
});

カスタムログ設定

const winston = require('winston');

const customLogger = 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: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  logging: {
    destination: 'custom',
    custom: customLogger
  }
});

🔒 セキュリティ設定

入力検証

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  security: {
    validateInput: true,
    
    // 画像検証
    imageValidation: {
      maxSize: 10 * 1024 * 1024,    // 10MB
      allowedFormats: ['jpg', 'png', 'webp'],
      scanForMalware: true
    },
    
    // プロンプト検証
    promptValidation: {
      maxLength: 1000,
      sanitize: true,
      blockSensitiveContent: true,
      allowedLanguages: ['ja', 'en']
    },
    
    // レート制限
    rateLimiting: {
      enabled: true,
      maxRequests: 100,
      windowMs: 60000,              // 1分間
      skipSuccessfulRequests: false
    }
  }
});

APIキーローテーション

class ApiKeyRotator {
  constructor(keys) {
    this.keys = keys;
    this.currentIndex = 0;
  }
  
  getCurrentKey() {
    return this.keys[this.currentIndex];
  }
  
  rotateKey() {
    this.currentIndex = (this.currentIndex + 1) % this.keys.length;
    return this.getCurrentKey();
  }
}

const keyRotator = new ApiKeyRotator([
  'qwen_key_1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'qwen_key_2_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'qwen_key_3_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
]);

const editor = new QwenImageEdit({
  apiKey: keyRotator.getCurrentKey(),
  
  // エラー時のキーローテーション
  onError: (error) => {
    if (error.code === 'RATE_LIMIT_EXCEEDED') {
      const newKey = keyRotator.rotateKey();
      editor.updateApiKey(newKey);
    }
  }
});

🚀 パフォーマンス設定

接続プール

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // HTTP接続プール設定
  connectionPool: {
    maxSockets: 50,         // 最大ソケット数
    maxFreeSockets: 10,     // 最大フリーソケット数
    timeout: 60000,         // アイドルタイムアウト
    keepAlive: true,        // Keep-Aliveを有効
    keepAliveMsecs: 1000    // Keep-Alive間隔
  }
});

画像圧縮

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // 自動画像圧縮
  imageCompression: {
    enabled: true,
    maxSize: 5 * 1024 * 1024,   // 5MB以上で圧縮
    quality: 0.8,               // 圧縮品質
    format: 'webp',             // 圧縮フォーマット
    progressive: true           // プログレッシブJPEG
  }
});

メモリ管理

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // メモリ管理設定
  memory: {
    maxHeapSize: '2GB',         // 最大ヒープサイズ
    gcInterval: 300000,         // GC間隔(5分)
    imageBufferLimit: 100,      // 画像バッファ制限
    autoCleanup: true           // 自動クリーンアップ
  }
});

📊 監視設定

メトリクス収集

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // メトリクス設定
  metrics: {
    enabled: true,
    
    // 収集するメトリクス
    collect: {
      requestCount: true,
      responseTime: true,
      errorRate: true,
      cacheHitRate: true,
      creditsUsed: true
    },
    
    // エクスポート設定
    export: {
      format: 'prometheus',     // prometheus, json, csv
      endpoint: '/metrics',
      interval: 60000           // 1分間隔
    }
  }
});

ヘルスチェック

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // ヘルスチェック設定
  healthCheck: {
    enabled: true,
    endpoint: '/health',
    interval: 30000,            // 30秒間隔
    
    // チェック項目
    checks: {
      apiConnection: true,
      cacheConnection: true,
      memoryUsage: true,
      responseTime: true
    },
    
    // 閾値設定
    thresholds: {
      maxResponseTime: 5000,    // 5秒
      maxMemoryUsage: 0.8,      // 80%
      maxErrorRate: 0.05        // 5%
    }
  }
});

🛠️ 開発ツール

ホットリロード

// 開発環境でのホットリロード設定
if (process.env.NODE_ENV === 'development') {
  const chokidar = require('chokidar');
  
  const editor = new QwenImageEdit({
    apiKey: 'your-api-key',
    
    // ホットリロード設定
    hotReload: {
      enabled: true,
      watchPaths: ['./config', './src'],
      ignorePatterns: ['node_modules', '.git'],
      
      // 設定変更時のコールバック
      onConfigChange: (newConfig) => {
        console.log('設定が更新されました:', newConfig);
        editor.updateConfig(newConfig);
      }
    }
  });
}

テスト用モック

const editor = new QwenImageEdit({
  apiKey: 'your-api-key',
  
  // モック設定(テスト環境用)
  mock: {
    enabled: process.env.NODE_ENV === 'test',
    
    // モックレスポンス
    responses: {
      editText: {
        imageUrl: 'https://example.com/mock-edited-image.jpg',
        credits: 1,
        processingTime: 1000,
        metadata: {
          originalSize: { width: 800, height: 600 },
          outputSize: { width: 800, height: 600 }
        }
      },
      
      editElement: {
        imageUrl: 'https://example.com/mock-element-image.jpg',
        credits: 2,
        processingTime: 1500
      }
    },
    
    // エラーシミュレーション
    simulateErrors: {
      rateLimitError: 0.1,      // 10%の確率でレート制限エラー
      networkError: 0.05,       // 5%の確率でネットワークエラー
      serverError: 0.02         // 2%の確率でサーバーエラー
    },
    
    // 遅延シミュレーション
    delay: {
      min: 500,                 // 最小遅延(ミリ秒)
      max: 2000                 // 最大遅延(ミリ秒)
    }
  }
});

📋 設定のベストプラクティス

設定管理

// config/index.js
const path = require('path');
const fs = require('fs');

class ConfigManager {
  constructor() {
    this.config = this.loadConfig();
    this.watchers = [];
  }
  
  loadConfig() {
    const env = process.env.NODE_ENV || 'development';
    const configPath = path.join(__dirname, `${env}.js`);
    
    if (fs.existsSync(configPath)) {
      return require(configPath);
    }
    
    return require('./default.js');
  }
  
  get(key) {
    return key.split('.').reduce((obj, k) => obj?.[k], this.config);
  }
  
  set(key, value) {
    const keys = key.split('.');
    const lastKey = keys.pop();
    const target = keys.reduce((obj, k) => obj[k] = obj[k] || {}, this.config);
    target[lastKey] = value;
  }
  
  watch(callback) {
    this.watchers.push(callback);
  }
  
  reload() {
    const oldConfig = this.config;
    this.config = this.loadConfig();
    
    this.watchers.forEach(callback => {
      callback(this.config, oldConfig);
    });
  }
}

const configManager = new ConfigManager();

// 設定の使用
const editor = new QwenImageEdit(configManager.get('qwen'));

// 設定変更の監視
configManager.watch((newConfig, oldConfig) => {
  console.log('設定が変更されました');
  editor.updateConfig(newConfig.qwen);
});

module.exports = configManager;

設定検証

const Joi = require('joi');

// 設定スキーマ
const configSchema = Joi.object({
  apiKey: Joi.string().required(),
  region: Joi.string().default('ap-northeast-1'),
  timeout: Joi.number().min(1000).max(300000).default(30000),
  maxRetries: Joi.number().min(0).max(10).default(3),
  
  cache: Joi.object({
    enabled: Joi.boolean().default(true),
    storage: Joi.string().valid('memory', 'redis', 'file').default('memory'),
    ttl: Joi.number().min(1000).default(3600000)
  }).default(),
  
  logging: Joi.object({
    level: Joi.string().valid('debug', 'info', 'warn', 'error').default('info'),
    format: Joi.string().valid('text', 'json').default('text')
  }).default()
});

// 設定検証関数
function validateConfig(config) {
  const { error, value } = configSchema.validate(config, {
    allowUnknown: true,
    stripUnknown: false
  });
  
  if (error) {
    throw new Error(`設定エラー: ${error.details[0].message}`);
  }
  
  return value;
}

// 使用例
try {
  const validatedConfig = validateConfig(rawConfig);
  const editor = new QwenImageEdit(validatedConfig);
} catch (error) {
  console.error('設定が無効です:', error.message);
  process.exit(1);
}

シークレット管理

// secrets/manager.js
const AWS = require('aws-sdk');
const { SecretManagerServiceClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');

class SecretManager {
  constructor() {
    this.client = new SecretManagerServiceClient({
      region: process.env.AWS_REGION || 'ap-northeast-1'
    });
    this.cache = new Map();
  }
  
  async getSecret(secretName) {
    // キャッシュから取得
    if (this.cache.has(secretName)) {
      const cached = this.cache.get(secretName);
      if (Date.now() < cached.expiry) {
        return cached.value;
      }
    }
    
    try {
      const command = new GetSecretValueCommand({
        SecretId: secretName
      });
      
      const response = await this.client.send(command);
      const secret = JSON.parse(response.SecretString);
      
      // 5分間キャッシュ
      this.cache.set(secretName, {
        value: secret,
        expiry: Date.now() + 300000
      });
      
      return secret;
    } catch (error) {
      console.error(`シークレット取得エラー: ${secretName}`, error);
      throw error;
    }
  }
}

// 使用例
const secretManager = new SecretManager();

async function createEditor() {
  const secrets = await secretManager.getSecret('qwen-image-edit-secrets');
  
  return new QwenImageEdit({
    apiKey: secrets.apiKey,
    region: secrets.region
  });
}

🎯 次のステップ

🚀 高度な機能

非同期処理とバッチ操作

高度な機能 →

🛠️ トラブルシューティング

よくある問題と解決方法

トラブルシューティング →

💡 実践例

実用的な使用例とベストプラクティス

例を見る →

📖 API リファレンス

すべてのメソッドとパラメータの詳細

API ドキュメント →

質問がありますか? サポートチームにお気軽にお問い合わせください。