Konfiguration
Konfigurations- und Einrichtungsanleitung für Qwen Image Edit
Konfiguration
Erweiterte Konfiguration und Optimierung von Qwen Image Edit für verschiedene Umgebungen und Anwendungsfälle.
🚀 Grundkonfiguration
Umgebungsvariablen
# .env.development
QWEN_API_KEY=ihr-entwicklungs-api-schluessel
QWEN_REGION=eu-west-1
QWEN_TIMEOUT=30000
QWEN_DEBUG=true
QWEN_CACHE_ENABLED=true
QWEN_MAX_RETRIES=3
# .env.production
QWEN_API_KEY=ihr-produktions-api-schluessel
QWEN_REGION=eu-west-1
QWEN_TIMEOUT=60000
QWEN_DEBUG=false
QWEN_CACHE_ENABLED=true
QWEN_MAX_RETRIES=5
QWEN_RATE_LIMIT_REQUESTS=1000
QWEN_RATE_LIMIT_PERIOD=60000
# .env.test
QWEN_API_KEY=ihr-test-api-schluessel
QWEN_REGION=eu-west-1
QWEN_TIMEOUT=10000
QWEN_DEBUG=true
QWEN_CACHE_ENABLED=false
QWEN_MOCK_ENABLED=true
Client-Setup
import { QwenImageEdit } from 'qwen-image-edit';
// Grundlegende Konfiguration
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
region: process.env.QWEN_REGION || 'eu-west-1',
timeout: parseInt(process.env.QWEN_TIMEOUT) || 30000,
debug: process.env.QWEN_DEBUG === 'true'
});
// Erweiterte Konfiguration
const editor = new QwenImageEdit({
// Authentifizierung
apiKey: process.env.QWEN_API_KEY,
region: 'eu-west-1',
// Netzwerk-Einstellungen
timeout: 60000,
maxRetries: 5,
retryDelay: 2000,
retryMultiplier: 2,
maxRetryDelay: 30000,
// Basis-URL (für Enterprise-Kunden)
baseURL: process.env.QWEN_BASE_URL || 'https://api.qwen.com/v1',
// User-Agent
userAgent: 'MeineApp/1.0.0 (qwen-image-edit)',
// Debug und Logging
debug: process.env.NODE_ENV === 'development',
logger: console,
// Validierung
validateInputs: true,
strictMode: false
});
💾 Cache-Konfiguration
In-Memory Cache
// Einfacher In-Memory Cache
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
cache: {
enabled: true,
type: 'memory',
maxSize: 100, // Maximale Anzahl gecachter Elemente
ttl: 3600000, // Cache-Lebensdauer in ms (1 Stunde)
checkPeriod: 600000 // Aufräumintervall in ms (10 Minuten)
}
});
// Erweiterte Memory-Cache-Konfiguration
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
cache: {
enabled: true,
type: 'memory',
maxSize: 500,
ttl: 7200000, // 2 Stunden
maxMemoryUsage: 100 * 1024 * 1024, // 100MB
compressionEnabled: true,
evictionPolicy: 'lru' // least-recently-used
}
});
Redis Cache
import Redis from 'ioredis';
// Redis-Client erstellen
const redis = new Redis({
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
db: parseInt(process.env.REDIS_DB) || 0,
retryDelayOnFailover: 100,
maxRetriesPerRequest: 3
});
// Editor mit Redis-Cache
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
cache: {
enabled: true,
type: 'redis',
client: redis,
keyPrefix: 'qwen:cache:',
ttl: 86400000, // 24 Stunden
compression: true,
serialization: 'json' // 'json' oder 'msgpack'
}
});
Datei-basierter Cache
import path from 'path';
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
cache: {
enabled: true,
type: 'file',
directory: path.join(process.cwd(), '.cache', 'qwen'),
maxSize: 1000,
ttl: 86400000, // 24 Stunden
cleanupInterval: 3600000, // Aufräumen alle Stunde
compression: true,
fileExtension: '.cache'
}
});
Custom Cache-Implementierung
class CustomCache {
constructor(options = {}) {
this.options = options;
this.storage = new Map();
}
async get(key) {
const item = this.storage.get(key);
if (!item) return null;
if (Date.now() > item.expires) {
this.storage.delete(key);
return null;
}
return item.data;
}
async set(key, data, ttl = this.options.ttl) {
this.storage.set(key, {
data,
expires: Date.now() + ttl,
created: Date.now()
});
}
async delete(key) {
return this.storage.delete(key);
}
async clear() {
this.storage.clear();
}
async size() {
return this.storage.size;
}
}
const customCache = new CustomCache({ ttl: 3600000 });
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
cache: {
enabled: true,
type: 'custom',
implementation: customCache
}
});
🌐 Proxy-Konfiguration
HTTP-Proxy
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
proxy: {
protocol: 'http',
host: 'proxy.unternehmen.com',
port: 8080,
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
},
timeout: 10000
}
});
SOCKS-Proxy
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
proxy: {
protocol: 'socks5',
host: 'socks-proxy.example.com',
port: 1080,
auth: {
username: 'benutzer',
password: 'passwort'
}
}
});
Proxy mit Zertifikaten
import fs from 'fs';
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
proxy: {
protocol: 'https',
host: 'secure-proxy.example.com',
port: 443,
ca: fs.readFileSync('./certs/ca.pem'),
cert: fs.readFileSync('./certs/client.pem'),
key: fs.readFileSync('./certs/client-key.pem'),
rejectUnauthorized: true
}
});
🏗️ Umgebungsspezifische Konfigurationen
Entwicklungsumgebung
// config/development.js
export const developmentConfig = {
apiKey: process.env.QWEN_API_KEY,
region: 'eu-west-1',
// Entwicklungsfreundliche Einstellungen
debug: true,
timeout: 30000,
maxRetries: 2,
// Schneller Cache für Entwicklung
cache: {
enabled: true,
type: 'memory',
maxSize: 50,
ttl: 1800000 // 30 Minuten
},
// Ausführliches Logging
logger: {
level: 'debug',
format: 'pretty',
timestamp: true
},
// Validierung aktiviert
validateInputs: true,
strictMode: true,
// Mock für Tests
mock: {
enabled: process.env.NODE_ENV === 'test',
responses: {
editText: {
imageUrl: 'https://mock.example.com/edited.jpg',
credits: 1,
processingTime: 1000
}
}
}
};
Produktionsumgebung
// config/production.js
export const productionConfig = {
apiKey: process.env.QWEN_API_KEY,
region: process.env.QWEN_REGION || 'eu-west-1',
// Produktionsoptimierte Einstellungen
debug: false,
timeout: 60000,
maxRetries: 5,
retryDelay: 2000,
// Robuster Cache
cache: {
enabled: true,
type: 'redis',
client: redisClient,
ttl: 86400000, // 24 Stunden
compression: true
},
// Strukturiertes Logging
logger: {
level: 'info',
format: 'json',
destination: './logs/qwen.log',
rotation: {
size: '10MB',
keep: 7
}
},
// Rate Limiting
rateLimit: {
requests: parseInt(process.env.QWEN_RATE_LIMIT) || 1000,
period: 60000,
strategy: 'sliding-window'
},
// Monitoring
monitoring: {
enabled: true,
metricsEndpoint: '/metrics',
healthCheckEndpoint: '/health'
},
// Sicherheit
security: {
validateInputs: true,
sanitizeOutputs: true,
maxImageSize: 10 * 1024 * 1024, // 10MB
allowedFormats: ['jpg', 'png', 'webp']
}
};
Testumgebung
// config/test.js
export const testConfig = {
apiKey: 'test-api-key',
region: 'eu-west-1',
// Test-optimierte Einstellungen
debug: true,
timeout: 5000,
maxRetries: 1,
// Kein Cache für Tests
cache: {
enabled: false
},
// Mock aktiviert
mock: {
enabled: true,
latency: 100, // Simulierte Latenz
errorRate: 0.1, // 10% Fehlerrate für Robustheitstests
responses: {
editText: {
imageUrl: 'https://test.example.com/edited.jpg',
credits: 1,
processingTime: 500
},
analyzeImage: {
analysis: {
text: { content: 'Test Text', confidence: 0.95 },
objects: [{ name: 'test-object', confidence: 0.9 }]
},
credits: 1
}
}
},
// Test-Logger
logger: {
level: 'silent' // Keine Logs während Tests
}
};
📊 Logging-Konfiguration
Grundlegendes Logging
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
logger: {
level: 'info', // 'silent', 'error', 'warn', 'info', 'debug'
format: 'pretty', // 'pretty', 'json', 'simple'
timestamp: true,
colorize: true
}
});
Erweiterte Logging-Konfiguration
import winston from 'winston';
// Winston-Logger erstellen
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'
})
]
});
// In Entwicklung auch zur Konsole loggen
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
logger: logger,
logRequests: true,
logResponses: true,
logErrors: true
});
Strukturiertes Logging
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
logger: {
level: 'info',
format: 'json',
fields: {
service: 'qwen-image-edit',
version: '1.0.0',
environment: process.env.NODE_ENV
},
redactSensitive: true, // API-Schlüssel und andere sensible Daten ausblenden
includeRequestId: true,
includeTimestamp: true
}
});
🔒 Sicherheitskonfiguration
Input-Validierung
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
security: {
// Input-Validierung
validateInputs: true,
maxImageSize: 10 * 1024 * 1024, // 10MB
allowedFormats: ['jpg', 'jpeg', 'png', 'webp'],
maxPromptLength: 1000,
// Content-Filtering
contentFilter: {
enabled: true,
blockInappropriate: true,
blockViolence: true,
blockAdult: true
},
// Rate Limiting pro IP
rateLimitByIP: {
enabled: true,
requests: 100,
period: 3600000, // 1 Stunde
blockDuration: 3600000 // 1 Stunde Sperre
},
// API-Schlüssel-Rotation
keyRotation: {
enabled: true,
rotationInterval: 30 * 24 * 60 * 60 * 1000, // 30 Tage
gracePeriod: 7 * 24 * 60 * 60 * 1000 // 7 Tage Übergangszeit
}
}
});
API-Schlüssel-Rotation
class APIKeyManager {
constructor(options = {}) {
this.currentKey = options.primaryKey;
this.backupKey = options.backupKey;
this.rotationInterval = options.rotationInterval || 30 * 24 * 60 * 60 * 1000;
this.lastRotation = options.lastRotation || Date.now();
}
getCurrentKey() {
// Prüfe ob Rotation nötig ist
if (Date.now() - this.lastRotation > this.rotationInterval) {
this.rotateKeys();
}
return this.currentKey;
}
rotateKeys() {
console.log('🔄 Rotiere API-Schlüssel');
// Tausche Schlüssel
const temp = this.currentKey;
this.currentKey = this.backupKey;
this.backupKey = temp;
this.lastRotation = Date.now();
// Speichere neue Konfiguration
this.saveConfiguration();
}
saveConfiguration() {
// Implementierung zum Speichern der Konfiguration
// z.B. in Datenbank oder Konfigurationsdatei
}
}
const keyManager = new APIKeyManager({
primaryKey: process.env.QWEN_API_KEY_PRIMARY,
backupKey: process.env.QWEN_API_KEY_BACKUP
});
const editor = new QwenImageEdit({
apiKey: () => keyManager.getCurrentKey(), // Dynamischer API-Schlüssel
region: 'eu-west-1'
});
⚡ Performance-Konfiguration
Connection Pooling
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
connectionPool: {
enabled: true,
maxConnections: 50,
maxIdleTime: 30000, // 30 Sekunden
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 10,
maxFreeSockets: 5
}
});
Bildkomprimierung
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
imageOptimization: {
enabled: true,
// Automatische Größenanpassung vor Upload
autoResize: {
enabled: true,
maxWidth: 2048,
maxHeight: 2048,
quality: 85
},
// Komprimierung
compression: {
enabled: true,
quality: 85,
progressive: true,
optimizeScans: true
},
// Format-Optimierung
formatOptimization: {
enabled: true,
preferWebP: true,
fallbackToJPEG: true
}
}
});
Memory Management
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
memoryManagement: {
enabled: true,
maxMemoryUsage: 512 * 1024 * 1024, // 512MB
gcInterval: 60000, // Garbage Collection alle Minute
// Buffer-Pool für Bildverarbeitung
bufferPool: {
enabled: true,
maxBuffers: 20,
bufferSize: 10 * 1024 * 1024 // 10MB pro Buffer
},
// Streaming für große Dateien
streaming: {
enabled: true,
threshold: 5 * 1024 * 1024, // 5MB Schwellenwert
chunkSize: 1024 * 1024 // 1MB Chunks
}
}
});
📈 Monitoring-Konfiguration
Metriken
import { createPrometheusMetrics } from 'qwen-image-edit/metrics';
const metrics = createPrometheusMetrics();
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
monitoring: {
enabled: true,
metrics: metrics,
// Metriken-Konfiguration
collectMetrics: {
requests: true,
responses: true,
errors: true,
latency: true,
credits: true,
cacheHits: true
},
// Custom Labels
labels: {
service: 'image-processing',
version: process.env.APP_VERSION,
environment: process.env.NODE_ENV
}
}
});
// Metriken-Endpoint für Prometheus
app.get('/metrics', async (req, res) => {
res.set('Content-Type', metrics.register.contentType);
res.end(await metrics.register.metrics());
});
Health Checks
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
healthCheck: {
enabled: true,
interval: 30000, // Alle 30 Sekunden
timeout: 5000,
endpoint: '/health',
// Health Check Tests
checks: {
api: true, // API-Erreichbarkeit
credits: true, // Credit-Status
cache: true, // Cache-Funktionalität
memory: true, // Speicherverbrauch
disk: true // Festplattenspeicher
},
// Schwellenwerte
thresholds: {
memoryUsage: 0.8, // 80% Speichernutzung
diskUsage: 0.9, // 90% Festplattennutzung
responseTime: 5000 // 5 Sekunden Antwortzeit
}
}
});
// Health Check Endpoint
app.get('/health', async (req, res) => {
const health = await editor.getHealthStatus();
const statusCode = health.status === 'healthy' ? 200 : 503;
res.status(statusCode).json(health);
});
🛠️ Entwicklungstools
Hot Reload
// webpack.config.js oder ähnlich
if (process.env.NODE_ENV === 'development') {
const editor = new QwenImageEdit({
apiKey: process.env.QWEN_API_KEY,
development: {
hotReload: {
enabled: true,
watchFiles: ['./config/**/*.js'],
reloadDelay: 1000
},
// Automatisches Neuladen der Konfiguration
configReload: {
enabled: true,
watchConfig: true,
validateOnReload: true
}
}
});
}
Mock für Tests
// test-utils/mock-editor.js
export class MockQwenImageEdit {
constructor(options = {}) {
this.options = options;
this.mockResponses = options.mockResponses || {};
}
async editText(options) {
// Simuliere Latenz
await new Promise(resolve =>
setTimeout(resolve, this.options.latency || 100)
);
// Simuliere gelegentliche Fehler
if (Math.random() < (this.options.errorRate || 0)) {
throw new Error('Mock-Fehler für Tests');
}
return this.mockResponses.editText || {
imageUrl: 'https://mock.example.com/edited.jpg',
credits: 1,
processingTime: 500
};
}
async analyzeImage(options) {
await new Promise(resolve =>
setTimeout(resolve, this.options.latency || 50)
);
return this.mockResponses.analyzeImage || {
analysis: {
text: { content: 'Mock Text', confidence: 0.95 }
},
credits: 1
};
}
}
// In Tests verwenden
import { MockQwenImageEdit } from './test-utils/mock-editor.js';
const mockEditor = new MockQwenImageEdit({
latency: 100,
errorRate: 0.1,
mockResponses: {
editText: {
imageUrl: 'https://test.example.com/result.jpg',
credits: 2
}
}
});
📋 Best Practices
Konfigurationsmanagement
// config/index.js
import { developmentConfig } from './development.js';
import { productionConfig } from './production.js';
import { testConfig } from './test.js';
const configs = {
development: developmentConfig,
production: productionConfig,
test: testConfig
};
const environment = process.env.NODE_ENV || 'development';
const config = configs[environment];
if (!config) {
throw new Error(`Keine Konfiguration für Umgebung '${environment}' gefunden`);
}
// Konfiguration validieren
function validateConfig(config) {
const required = ['apiKey', 'region'];
for (const field of required) {
if (!config[field]) {
throw new Error(`Erforderliches Konfigurationsfeld fehlt: ${field}`);
}
}
return true;
}
validateConfig(config);
export default config;
Konfigurationsvalidierung
import Joi from 'joi';
const configSchema = 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).default(30000),
maxRetries: Joi.number().min(0).max(10).default(3),
debug: Joi.boolean().default(false),
cache: Joi.object({
enabled: Joi.boolean().default(true),
type: Joi.string().valid('memory', 'redis', 'file', 'custom').default('memory'),
maxSize: Joi.number().min(1).default(100),
ttl: Joi.number().min(1000).default(3600000)
}).optional(),
proxy: Joi.object({
protocol: Joi.string().valid('http', 'https', 'socks5'),
host: Joi.string().required(),
port: Joi.number().port().required(),
auth: Joi.object({
username: Joi.string().required(),
password: Joi.string().required()
}).optional()
}).optional()
});
export function validateConfiguration(config) {
const { error, value } = configSchema.validate(config, {
allowUnknown: true,
stripUnknown: true
});
if (error) {
throw new Error(`Konfigurationsfehler: ${error.details[0].message}`);
}
return value;
}
Secrets Management
// secrets/manager.js
import { SecretsManager } from 'aws-sdk';
class SecretManager {
constructor(region = 'eu-west-1') {
this.client = new SecretsManager({ region });
this.cache = new Map();
this.cacheTTL = 300000; // 5 Minuten
}
async getSecret(secretName) {
// Prüfe Cache
const cached = this.cache.get(secretName);
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
return cached.value;
}
try {
const result = await this.client.getSecretValue({
SecretId: secretName
}).promise();
const secret = JSON.parse(result.SecretString);
// Cache aktualisieren
this.cache.set(secretName, {
value: secret,
timestamp: Date.now()
});
return secret;
} catch (error) {
console.error(`Fehler beim Laden des Secrets ${secretName}:`, error);
throw error;
}
}
}
const secretManager = new SecretManager();
// Verwendung
export async function createEditorWithSecrets() {
const secrets = await secretManager.getSecret('qwen-image-edit-secrets');
return new QwenImageEdit({
apiKey: secrets.apiKey,
region: secrets.region,
// ... weitere Konfiguration
});
}