Beispiele

Praktische Beispiele und Code-Snippets für verschiedene Anwendungsfälle

Praktische Beispiele

Entdecken Sie reale Anwendungsfälle und bewährte Praktiken für Qwen Image Edit.

🎯 Grundlegende Textbearbeitung

Einfache Textmodifikation

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

const editor = new QwenImageEdit({
  apiKey: process.env.QWEN_API_KEY,
  region: 'eu-west-1'
});

// Einfacher Textaustausch
const result = await editor.editText({
  image: './event-poster.jpg',
  prompt: 'Ersetze "Konzert" durch "Festival" im Haupttitel'
});

console.log('Bearbeitetes Poster:', result.imageUrl);

Textübersetzung

// Automatische Übersetzung von Marketingmaterialien
const uebersetzungen = {
  deutsch: 'Übersetze allen Text ins Deutsche',
  franzoesisch: 'Übersetze allen Text ins Französische',
  spanisch: 'Übersetze allen Text ins Spanische',
  italienisch: 'Übersetze allen Text ins Italienische'
};

const lokalisierteVersionen = await Promise.all(
  Object.entries(uebersetzungen).map(async ([sprache, prompt]) => {
    const result = await editor.editText({
      image: './original-kampagne.jpg',
      prompt
    });
    
    return {
      sprache,
      bild: result.imageUrl,
      credits: result.credits
    };
  })
);

console.log('Lokalisierte Kampagnen:', lokalisierteVersionen);

Textkorrektur und -verbesserung

// Rechtschreibfehler korrigieren und Text verbessern
const korrekturen = [
  {
    original: './flyer-mit-fehlern.jpg',
    prompt: 'Korrigiere alle Rechtschreibfehler und verbessere die Grammatik'
  },
  {
    original: './alte-werbung.jpg',
    prompt: 'Modernisiere die Sprache und mache sie zeitgemäßer'
  },
  {
    original: './technisches-diagramm.jpg',
    prompt: 'Vereinfache die technischen Begriffe für ein allgemeines Publikum'
  }
];

for (const korrektur of korrekturen) {
  const result = await editor.editText({
    image: korrektur.original,
    prompt: korrektur.prompt
  });
  
  console.log(`Korrigiert: ${korrektur.original} → ${result.imageUrl}`);
}

🎨 Element-Hinzufügung

Logos und Wasserzeichen

// Firmenlogo zu Produktbildern hinzufügen
const produktBilder = [
  './produkt-smartphone.jpg',
  './produkt-laptop.jpg',
  './produkt-kopfhoerer.jpg'
];

const logoOptionen = {
  position: 'untere rechte Ecke',
  groesse: 'klein',
  transparenz: '20%'
};

const produkteMitLogo = await Promise.all(
  produktBilder.map(async (bild) => {
    const result = await editor.editElement({
      image: bild,
      prompt: `Füge das Firmenlogo diskret in die ${logoOptionen.position} ein, Größe: ${logoOptionen.groesse}, Transparenz: ${logoOptionen.transparenz}`
    });
    
    return {
      original: bild,
      mitLogo: result.imageUrl
    };
  })
);

console.log('Produkte mit Logo:', produkteMitLogo);

Preisschilder und Badges

// Sale-Badges zu E-Commerce-Bildern hinzufügen
const saleProdukte = [
  {
    bild: './winter-jacke.jpg',
    rabatt: '30%',
    farbe: 'rot'
  },
  {
    bild: './sommer-kleid.jpg',
    rabatt: '50%',
    farbe: 'grün'
  },
  {
    bild: './sport-schuhe.jpg',
    rabatt: '25%',
    farbe: 'orange'
  }
];

const produkteMitSale = await Promise.all(
  saleProdukte.map(async (produkt) => {
    const result = await editor.editElement({
      image: produkt.bild,
      prompt: `Füge einen auffälligen ${produkt.farbe}en "${produkt.rabatt} SALE" Badge in die obere linke Ecke ein`
    });
    
    return {
      ...produkt,
      mitBadge: result.imageUrl
    };
  })
);

console.log('Sale-Produkte:', produkteMitSale);

Informative Elemente

// Informative Elemente zu Bildern hinzufügen
const informationsElemente = [
  {
    bild: './restaurant-gericht.jpg',
    element: 'Nährwertangaben',
    prompt: 'Füge eine dezente Nährwerttabelle in die untere linke Ecke ein'
  },
  {
    bild: './hotel-zimmer.jpg',
    element: 'Bewertung',
    prompt: 'Füge 5 goldene Sterne und "4.8/5" Bewertung oben rechts hinzu'
  },
  {
    bild: './auto-verkauf.jpg',
    element: 'Spezifikationen',
    prompt: 'Füge wichtige Fahrzeugdaten (Baujahr, km, PS) als elegante Überlagerung hinzu'
  }
];

for (const item of informationsElemente) {
  const result = await editor.editElement({
    image: item.bild,
    prompt: item.prompt
  });
  
  console.log(`${item.element} hinzugefügt zu ${item.bild}:`, result.imageUrl);
}

🎭 Erweiterte Stil-Übertragung

Künstlerische Stile

// Verschiedene künstlerische Stile anwenden
const stilReferenzen = {
  impressionistisch: './stil-monet.jpg',
  modern: './stil-picasso.jpg',
  fotorealistisch: './stil-foto.jpg',
  vintage: './stil-retro.jpg'
};

const originalBild = './landschaft-foto.jpg';

const stilVarianten = await Promise.all(
  Object.entries(stilReferenzen).map(async ([stilName, stilBild]) => {
    const result = await editor.transferStyle({
      sourceImage: originalBild,
      styleImage: stilBild,
      intensity: 0.7,
      preserveContent: true
    });
    
    return {
      stil: stilName,
      bild: result.imageUrl,
      verarbeitungszeit: result.processingTime
    };
  })
);

console.log('Stil-Varianten:', stilVarianten);

Fotografische Stile

// Fotografische Stile und Filter anwenden
const fotoStile = [
  {
    name: 'Vintage Film',
    prompt: 'Wende einen warmen Vintage-Film-Look mit leichtem Grain an'
  },
  {
    name: 'Schwarz-Weiß',
    prompt: 'Konvertiere zu hochkontrastigem Schwarz-Weiß mit dramatischen Schatten'
  },
  {
    name: 'HDR',
    prompt: 'Wende HDR-Effekt für lebendige Farben und Details an'
  },
  {
    name: 'Cinematic',
    prompt: 'Erstelle einen filmischen Look mit Letterbox und Farbgrading'
  }
];

const originalPortrait = './portrait-original.jpg';

const fotoVarianten = await Promise.all(
  fotoStile.map(async (stil) => {
    const result = await editor.editText({
      image: originalPortrait,
      prompt: stil.prompt
    });
    
    return {
      stil: stil.name,
      bild: result.imageUrl
    };
  })
);

console.log('Foto-Varianten:', fotoVarianten);

📦 Batch-Verarbeitung

E-Commerce Katalog-Update

import pLimit from 'p-limit';

// Begrenzung der gleichzeitigen Anfragen
const limit = pLimit(3);

// Produktkatalog mit Preisänderungen
const produktKatalog = [
  { bild: './katalog/shirt-001.jpg', alterPreis: '29.99€', neuerPreis: '24.99€' },
  { bild: './katalog/hose-002.jpg', alterPreis: '49.99€', neuerPreis: '39.99€' },
  { bild: './katalog/schuhe-003.jpg', alterPreis: '79.99€', neuerPreis: '69.99€' },
  { bild: './katalog/jacke-004.jpg', alterPreis: '99.99€', neuerPreis: '79.99€' },
  { bild: './katalog/muetze-005.jpg', alterPreis: '19.99€', neuerPreis: '14.99€' }
];

const aktualisierterKatalog = await Promise.allSettled(
  produktKatalog.map(produkt => 
    limit(async () => {
      try {
        const result = await editor.editText({
          image: produkt.bild,
          prompt: `Ersetze "${produkt.alterPreis}" durch "${produkt.neuerPreis}" und füge einen roten "SALE" Sticker hinzu`
        });
        
        return {
          ...produkt,
          aktualisiert: result.imageUrl,
          erfolg: true,
          credits: result.credits
        };
      } catch (error) {
        return {
          ...produkt,
          erfolg: false,
          fehler: error.message
        };
      }
    })
  )
);

// Ergebnisse auswerten
const erfolgreich = aktualisierterKatalog
  .filter(r => r.status === 'fulfilled' && r.value.erfolg)
  .map(r => r.value);

const fehlgeschlagen = aktualisierterKatalog
  .filter(r => r.status === 'rejected' || !r.value.erfolg)
  .map(r => r.value || r.reason);

console.log(`Katalog-Update abgeschlossen:`);
console.log(`✅ ${erfolgreich.length} Produkte erfolgreich aktualisiert`);
console.log(`❌ ${fehlgeschlagen.length} Produkte fehlgeschlagen`);

// Gesamte Credits berechnen
const gesamtCredits = erfolgreich.reduce((sum, p) => sum + p.credits, 0);
console.log(`💳 Gesamte verwendete Credits: ${gesamtCredits}`);

Mehrsprachige Lokalisierung

// Marketingmaterialien für verschiedene Märkte lokalisieren
const maerkte = [
  { land: 'Deutschland', sprache: 'Deutsch', waehrung: '€' },
  { land: 'Frankreich', sprache: 'Französisch', waehrung: '€' },
  { land: 'Spanien', sprache: 'Spanisch', waehrung: '€' },
  { land: 'USA', sprache: 'Englisch', waehrung: '$' },
  { land: 'Japan', sprache: 'Japanisch', waehrung: '¥' }
];

const originalKampagne = './kampagne-master.jpg';

const lokalisierteKampagnen = await Promise.all(
  maerkte.map(async (markt) => {
    const result = await editor.editText({
      image: originalKampagne,
      prompt: `Lokalisiere für ${markt.land}: Übersetze Text ins ${markt.sprache}, ändere Währung zu ${markt.waehrung}, passe kulturelle Referenzen an`
    });
    
    return {
      markt: markt.land,
      sprache: markt.sprache,
      bild: result.imageUrl,
      verarbeitungszeit: result.processingTime
    };
  })
);

console.log('Lokalisierte Kampagnen:', lokalisierteKampagnen);

// Speichere lokalisierte Versionen
for (const kampagne of lokalisierteKampagnen) {
  console.log(`${kampagne.markt}: ${kampagne.bild}`);
}

🎯 Spezifische Anwendungsfälle

Marketing und Werbung

// A/B-Test Varianten für Werbeanzeigen erstellen
const werbetexte = [
  'Jetzt 50% sparen!',
  'Limitiertes Angebot!',
  'Nur heute: Mega-Rabatt!',
  'Exklusiv für Sie!'
];

const originalAnzeige = './basis-anzeige.jpg';

const abTestVarianten = await Promise.all(
  werbetexte.map(async (text, index) => {
    const result = await editor.editText({
      image: originalAnzeige,
      prompt: `Ersetze den Hauptwerbetext durch "${text}" und optimiere die Schriftgröße für maximale Wirkung`
    });
    
    return {
      variante: `A${index + 1}`,
      werbetext: text,
      bild: result.imageUrl
    };
  })
);

console.log('A/B-Test Varianten:', abTestVarianten);

E-Commerce

// Saisonale Produktvarianten erstellen
const saisonaleThemen = [
  {
    saison: 'Weihnachten',
    farben: 'rot und gold',
    elemente: 'Schneeflocken und Weihnachtsbäume',
    text: 'Frohe Weihnachten!'
  },
  {
    saison: 'Sommer',
    farben: 'hell und sonnig',
    elemente: 'Sonnen und Palmen',
    text: 'Sommer-Special!'
  },
  {
    saison: 'Halloween',
    farben: 'orange und schwarz',
    elemente: 'Kürbisse und Fledermäuse',
    text: 'Gruseliger Rabatt!'
  }
];

const basisProdukt = './produkt-neutral.jpg';

const saisonaleVarianten = await Promise.all(
  saisonaleThemen.map(async (thema) => {
    const result = await editor.editElement({
      image: basisProdukt,
      prompt: `Erstelle eine ${thema.saison}-Version: Verwende ${thema.farben} Farben, füge ${thema.elemente} hinzu und ändere Text zu "${thema.text}"`
    });
    
    return {
      saison: thema.saison,
      bild: result.imageUrl
    };
  })
);

console.log('Saisonale Varianten:', saisonaleVarianten);

Bildung und Training

// Lernmaterialien für verschiedene Altersgruppen anpassen
const altersgruppen = [
  {
    gruppe: 'Grundschule',
    stil: 'bunt und spielerisch',
    sprache: 'einfach und kindgerecht'
  },
  {
    gruppe: 'Mittelstufe',
    stil: 'modern und ansprechend',
    sprache: 'altersgerecht und verständlich'
  },
  {
    gruppe: 'Oberstufe',
    stil: 'professionell und sachlich',
    sprache: 'wissenschaftlich und präzise'
  }
];

const originalDiagramm = './wissenschafts-diagramm.jpg';

const altersgerechteVersionen = await Promise.all(
  altersgruppen.map(async (gruppe) => {
    const result = await editor.editText({
      image: originalDiagramm,
      prompt: `Passe für ${gruppe.gruppe} an: Mache den Stil ${gruppe.stil} und die Sprache ${gruppe.sprache}`
    });
    
    return {
      zielgruppe: gruppe.gruppe,
      bild: result.imageUrl
    };
  })
);

console.log('Altersgerechte Lernmaterialien:', altersgerechteVersionen);

Social Media Content

// Content für verschiedene Social Media Plattformen optimieren
const plattformen = [
  {
    name: 'Instagram',
    format: '1:1',
    stil: 'ästhetisch und trendy',
    hashtags: '#style #fashion #trend'
  },
  {
    name: 'Facebook',
    format: '16:9',
    stil: 'informativ und einladend',
    hashtags: 'Keine Hashtags'
  },
  {
    name: 'LinkedIn',
    format: '16:9',
    stil: 'professionell und geschäftlich',
    hashtags: '#business #professional'
  },
  {
    name: 'TikTok',
    format: '9:16',
    stil: 'dynamisch und jugendlich',
    hashtags: '#viral #trending #fyp'
  }
];

const originalContent = './basis-content.jpg';

const plattformContent = await Promise.all(
  plattformen.map(async (plattform) => {
    // Erst das Format anpassen
    const formatiert = await editor.resizeImage({
      image: originalContent,
      aspectRatio: plattform.format,
      maintainContent: true
    });
    
    // Dann plattformspezifisch optimieren
    const result = await editor.editText({
      image: formatiert.imageUrl,
      prompt: `Optimiere für ${plattform.name}: Stil ${plattform.stil}, füge "${plattform.hashtags}" hinzu`
    });
    
    return {
      plattform: plattform.name,
      format: plattform.format,
      bild: result.imageUrl
    };
  })
);

console.log('Plattform-optimierter Content:', plattformContent);

🔄 Workflow-Automatisierung

Automatisierte Content-Pipeline

class ContentPipeline {
  constructor(editor) {
    this.editor = editor;
    this.verarbeitungsSchritte = [];
  }
  
  schritt(name, verarbeitung) {
    this.verarbeitungsSchritte.push({ name, verarbeitung });
    return this;
  }
  
  async verarbeite(eingabeBild) {
    let aktuellesBild = eingabeBild;
    const ergebnisse = [];
    
    for (const schritt of this.verarbeitungsSchritte) {
      console.log(`🔄 Verarbeite: ${schritt.name}`);
      
      try {
        const result = await schritt.verarbeitung(aktuellesBild);
        aktuellesBild = result.imageUrl || result.image;
        
        ergebnisse.push({
          schritt: schritt.name,
          erfolg: true,
          bild: aktuellesBild,
          credits: result.credits
        });
        
        console.log(`✅ ${schritt.name} abgeschlossen`);
      } catch (error) {
        console.error(`❌ Fehler bei ${schritt.name}:`, error.message);
        ergebnisse.push({
          schritt: schritt.name,
          erfolg: false,
          fehler: error.message
        });
      }
    }
    
    return {
      endBild: aktuellesBild,
      schritte: ergebnisse,
      gesamtCredits: ergebnisse.reduce((sum, r) => sum + (r.credits || 0), 0)
    };
  }
}

// Pipeline für E-Commerce Produktbilder
const produktPipeline = new ContentPipeline(editor)
  .schritt('Qualität verbessern', async (bild) => {
    return await editor.enhanceImage({
      image: bild,
      enhancements: ['sharpen', 'denoise', 'brighten']
    });
  })
  .schritt('Hintergrund entfernen', async (bild) => {
    return await editor.editElement({
      image: bild,
      prompt: 'Entferne den Hintergrund und erstelle einen sauberen weißen Hintergrund'
    });
  })
  .schritt('Logo hinzufügen', async (bild) => {
    return await editor.editElement({
      image: bild,
      prompt: 'Füge das Firmenlogo diskret in die untere rechte Ecke ein'
    });
  })
  .schritt('Für Web optimieren', async (bild) => {
    return await editor.resizeImage({
      image: bild,
      width: 800,
      height: 800,
      quality: 85
    });
  });

// Pipeline ausführen
const rohProduktBild = './roh-produkt.jpg';
const verarbeitetesProdukt = await produktPipeline.verarbeite(rohProduktBild);

console.log('Pipeline abgeschlossen:');
console.log('Endbild:', verarbeitetesProdukt.endBild);
console.log('Gesamte Credits:', verarbeitetesProdukt.gesamtCredits);
console.log('Schritte:', verarbeitetesProdukt.schritte);

🎨 Performance-Optimierung

Intelligentes Caching

import crypto from 'crypto';

class BildCache {
  constructor() {
    this.cache = new Map();
    this.maxGroesse = 100; // Maximale Anzahl gecachter Bilder
  }
  
  generiereSchluessel(bild, prompt, optionen = {}) {
    const daten = JSON.stringify({ bild, prompt, optionen });
    return crypto.createHash('md5').update(daten).digest('hex');
  }
  
  get(schluessel) {
    if (this.cache.has(schluessel)) {
      const eintrag = this.cache.get(schluessel);
      eintrag.letzterZugriff = Date.now();
      return eintrag.daten;
    }
    return null;
  }
  
  set(schluessel, daten) {
    // Cache-Größe begrenzen
    if (this.cache.size >= this.maxGroesse) {
      this.entferneAeltesten();
    }
    
    this.cache.set(schluessel, {
      daten,
      erstellt: Date.now(),
      letzterZugriff: Date.now()
    });
  }
  
  entferneAeltesten() {
    let aeltesterSchluessel = null;
    let aeltesterZugriff = Date.now();
    
    for (const [schluessel, eintrag] of this.cache.entries()) {
      if (eintrag.letzterZugriff < aeltesterZugriff) {
        aeltesterZugriff = eintrag.letzterZugriff;
        aeltesterSchluessel = schluessel;
      }
    }
    
    if (aeltesterSchluessel) {
      this.cache.delete(aeltesterSchluessel);
    }
  }
  
  statistiken() {
    return {
      groesse: this.cache.size,
      maxGroesse: this.maxGroesse,
      auslastung: (this.cache.size / this.maxGroesse * 100).toFixed(1) + '%'
    };
  }
}

// Cache-fähiger Editor
class CachedEditor {
  constructor(editor) {
    this.editor = editor;
    this.cache = new BildCache();
    this.cacheHits = 0;
    this.cacheMisses = 0;
  }
  
  async editText(optionen) {
    const schluessel = this.cache.generiereSchluessel(
      optionen.image,
      optionen.prompt,
      optionen
    );
    
    // Prüfe Cache
    const gecacht = this.cache.get(schluessel);
    if (gecacht) {
      this.cacheHits++;
      console.log('💾 Cache-Treffer für Textbearbeitung');
      return gecacht;
    }
    
    // Nicht im Cache, verarbeite
    this.cacheMisses++;
    console.log('🔄 Verarbeite neue Textbearbeitung');
    
    const result = await this.editor.editText(optionen);
    this.cache.set(schluessel, result);
    
    return result;
  }
  
  getCacheStatistiken() {
    const gesamt = this.cacheHits + this.cacheMisses;
    return {
      ...this.cache.statistiken(),
      treffer: this.cacheHits,
      verfehlt: this.cacheMisses,
      trefferquote: gesamt > 0 ? (this.cacheHits / gesamt * 100).toFixed(1) + '%' : '0%'
    };
  }
}

// Verwendung
const cachedEditor = new CachedEditor(editor);

// Mehrfache Bearbeitung derselben Bilder
const wiederholteBearbeitungen = [
  { image: './test1.jpg', prompt: 'Übersetze ins Deutsche' },
  { image: './test2.jpg', prompt: 'Füge Logo hinzu' },
  { image: './test1.jpg', prompt: 'Übersetze ins Deutsche' }, // Cache-Treffer
  { image: './test3.jpg', prompt: 'Verbessere Qualität' },
  { image: './test2.jpg', prompt: 'Füge Logo hinzu' } // Cache-Treffer
];

for (const bearbeitung of wiederholteBearbeitungen) {
  const result = await cachedEditor.editText(bearbeitung);
  console.log('Bearbeitet:', result.imageUrl);
}

console.log('Cache-Statistiken:', cachedEditor.getCacheStatistiken());

Robuste Fehlerbehandlung mit Wiederholung

import pRetry from 'p-retry';

class RobusterEditor {
  constructor(editor, optionen = {}) {
    this.editor = editor;
    this.maxWiederholungen = optionen.maxWiederholungen || 3;
    this.wartezeit = optionen.wartezeit || 1000;
    this.statistiken = {
      erfolgreich: 0,
      fehlgeschlagen: 0,
      wiederholungen: 0
    };
  }
  
  async editTextMitWiederholung(optionen) {
    return pRetry(async () => {
      try {
        const result = await this.editor.editText(optionen);
        this.statistiken.erfolgreich++;
        return result;
      } catch (error) {
        this.statistiken.wiederholungen++;
        
        // Bestimmte Fehler nicht wiederholen
        if (this.istDauerhaferFehler(error)) {
          throw new pRetry.AbortError(error);
        }
        
        console.log(`🔄 Wiederhole wegen Fehler: ${error.message}`);
        throw error;
      }
    }, {
      retries: this.maxWiederholungen,
      factor: 2,
      minTimeout: this.wartezeit,
      maxTimeout: this.wartezeit * 8,
      onFailedAttempt: (error) => {
        console.log(`❌ Versuch ${error.attemptNumber} fehlgeschlagen: ${error.message}`);
      }
    }).catch(error => {
      this.statistiken.fehlgeschlagen++;
      throw error;
    });
  }
  
  istDauerhaferFehler(error) {
    const dauerhafte = [
      'INVALID_API_KEY',
      'UNSUPPORTED_FORMAT',
      'IMAGE_TOO_LARGE',
      'CONTENT_VIOLATION'
    ];
    
    return dauerhafte.includes(error.code);
  }
  
  getStatistiken() {
    const gesamt = this.statistiken.erfolgreich + this.statistiken.fehlgeschlagen;
    return {
      ...this.statistiken,
      erfolgsquote: gesamt > 0 ? (this.statistiken.erfolgreich / gesamt * 100).toFixed(1) + '%' : '0%'
    };
  }
}

// Verwendung
const robusterEditor = new RobusterEditor(editor, {
  maxWiederholungen: 3,
  wartezeit: 2000
});

// Batch-Verarbeitung mit robusten Wiederholungen
const problematischeBilder = [
  './grosses-bild.jpg',
  './komplexes-bild.jpg',
  './beschaedigtes-bild.jpg'
];

for (const bild of problematischeBilder) {
  try {
    const result = await robusterEditor.editTextMitWiederholung({
      image: bild,
      prompt: 'Verbessere und übersetze'
    });
    
    console.log(`✅ Erfolgreich bearbeitet: ${bild}`);
  } catch (error) {
    console.error(`❌ Endgültig fehlgeschlagen: ${bild} - ${error.message}`);
  }
}

console.log('Verarbeitungsstatistiken:', robusterEditor.getStatistiken());

📚 Zusätzliche Ressourcen

Nützliche Hilfsfunktionen

// Bildoptimierung vor der Verarbeitung
export async function optimiereBildFuerVerarbeitung(bildPfad) {
  const sharp = require('sharp');
  
  const optimiert = await sharp(bildPfad)
    .resize(2048, 2048, { fit: 'inside', withoutEnlargement: true })
    .jpeg({ quality: 85 })
    .toBuffer();
  
  return optimiert;
}

// Batch-Verarbeitung mit Fortschrittsanzeige
export async function verarbeiteMitFortschritt(bilder, verarbeitungsFunktion) {
  const ergebnisse = [];
  
  for (let i = 0; i < bilder.length; i++) {
    const bild = bilder[i];
    const fortschritt = ((i + 1) / bilder.length * 100).toFixed(1);
    
    console.log(`📊 Fortschritt: ${fortschritt}% (${i + 1}/${bilder.length})`);
    
    try {
      const result = await verarbeitungsFunktion(bild);
      ergebnisse.push({ bild, result, erfolg: true });
    } catch (error) {
      ergebnisse.push({ bild, error: error.message, erfolg: false });
    }
  }
  
  return ergebnisse;
}

// Kosten-Tracker
export class KostenTracker {
  constructor() {
    this.gesamtCredits = 0;
    this.operationen = [];
  }
  
  verfolge(operation, credits) {
    this.gesamtCredits += credits;
    this.operationen.push({
      operation,
      credits,
      zeitstempel: new Date().toISOString()
    });
  }
  
  getBericht() {
    return {
      gesamtCredits: this.gesamtCredits,
      anzahlOperationen: this.operationen.length,
      durchschnittCredits: this.operationen.length > 0 ? 
        (this.gesamtCredits / this.operationen.length).toFixed(2) : 0,
      operationen: this.operationen
    };
  }
}