spicyapiDokumentation
Anleitungen
Hauptinhalt

Leitfaden: Bilder erzeugen und bearbeiten

Wie sich die Bild-Endpunkte als Gattung verhalten — die zwei Anfrageformen, die drei Schreibweisen für die Ausgabegröße, was ein Referenzbild der Rechnung hinzufügt, Adaptergewichte und wie man eine Ablehnung liest.

Dieser Leitfaden handelt von der Gattung der Bild-Endpunkte, nicht von einem einzelnen Modell. Er erklärt, was bei allen gleich bleibt, und — nützlicher noch — die Stellen, an denen sie so voneinander abweichen, dass ein für einen Endpunkt geschriebener Anfragekörper beim nächsten nicht mehr durchkommt.

Eine Parametertabelle finden Sie hier bewusst nicht. Parameter haben genau eine Quelle: das inputSchema, das der Live-Katalog für genau das Modell zurückgibt, das Sie aufrufen. Diese Seite zeigt, wie man dieses Schema liest und was darin nicht ausgesprochen wird.

Wenn Sie das suchenLesen Sie stattdessen
Ihr erstes Bild, von Schlüssel und Guthaben bis zur fertigen DateiSchnellstart
Denselben Weg für Video, Schritt für SchrittTutorial: Ein Bild in ein Video verwandeln
Jedes Feld eines bestimmten ModellsDessen inputSchema — siehe Modellkatalog und Schemata
Ein Gesicht oder einen Kopf aus einem Bild in ein anderes setzenMotivtausch

MODEL_ID_FROM_CATALOG ist ein Platzhalter

In allen Beispielen unten steht MODEL_ID_FROM_CATALOG dort, wo eine echte Modell-ID hingehört. Holen Sie diese ID aus dem authentifizierten Live-Katalog — GET /api/v1/models?modality=image — und verlangen Sie sowohl enabled: true als auch available: true, bevor Sie etwas ausgeben. Den Katalog zu lesen ist kostenlos. Schicken Sie den Platzhalter selbst, bekommen Sie nur einen "not found"-Fehler.

Zwei Anfrageformen

Bildarbeit kommt als zwei Aufgaben herein, und der Katalog trennt sie:

  • Erzeugende Endpunkte enden auf /text-to-image. Sie schicken Worte und bekommen ein Bild.
  • Bearbeitende Endpunkte enden auf /edit. Sie schicken zusätzlich mindestens ein Bild.

Für Bearbeitung gibt es zwei zulässige Schreibweisen, und es lohnt sich, beide zu kennen, bevor Sie den Katalog filtern: Endpunkte werden mit dem Suffix edit veröffentlicht, während das Array tasks sie als image-to-image einordnet. Der Query-Parameter task nimmt beide an. Siehe Modellkatalog und Schemata.

Beide Formen nutzen denselben Erstellungsumschlag, denselben Aufgabenlebenszyklus und dasselbe Ergebnisformat wie jedes andere Medienmodell. Was sich unterscheidet, ist input.

prompt ist in beiden Formen Pflicht

Es liegt nahe anzunehmen, ein bearbeitender Endpunkt komme mit dem Bild allein aus und prompt sei dort optional. Bei den Endpunkten, die überhaupt einen Prompt annehmen, ist er das nicht: prompt steht in beiden Formen in der required-Liste der Wurzel, und ihn wegzulassen wird abgelehnt, bevor irgendetwas berechnet wird.

Von einem bearbeitenden Endpunkt abgelehnt
{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "image_urls": ["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]
  }
}
prompt: is required

Das Bild sagt, wovon Sie ausgehen; der Prompt sagt, was damit geschehen soll. Ein bearbeitender Endpunkt ohne Anweisung hat nichts, woran er arbeiten könnte.

Es gibt eine Ausnahme, und sie ist eine ganze Familie und kein verirrter Einzelfall: Manche bearbeitenden Endpunkte nehmen gar keinen prompt an und arbeiten nur mit Bildern, weil die Operation vom Endpunkt selbst festgelegt ist. Sie gehören zum Motivtausch-Werkzeugkasten und tragen im Katalog ein Feld toolkit, an dem Sie sie erkennen; siehe Motivtausch. Dort ist prompt: is not a supported field die richtige Antwort und kein Fehler.

Das Feld für das Eingabebild hat drei Namen

Welchen ein Endpunkt verwendet, gehört zu seinem Schema und lässt sich nicht aus der Aufgabenart ableiten:

FeldFormWas es üblicherweise bedeutet
image_urleine BildreferenzEs gibt genau ein Motivbild, und der Endpunkt kennt kein zweites
image_urlsArray von BildreferenzenDie Bilder sind das Material, das bearbeitet oder kombiniert wird, in der Reihenfolge, auf die sich die Anweisung bezieht
reference_image_urlsArray von BildreferenzenDie Bilder lenken eine Erzeugung, die sonst rein textbasiert wäre — sie sind Orientierung, nicht das Motiv

reference_image_urls ist das überraschende: Es erscheint an erzeugenden Endpunkten, ein /text-to-image-Endpunkt kann also durchaus Bilder annehmen. Nehmen Sie nicht an, "text-to-image" bedeute "keine Bilder in der Anfrage".

Eine Bildreferenz ist eine öffentliche HTTPS-URL, eine committete spicy://-URI aus einem Upload oder eine kleine data:image/…;base64,…-URI. Zu Uploads siehe Medien, zu den kanonischen Feldnamen den Spicy-Schema-Vertrag.

Array-Grenzen schwanken stärker, als man denkt

Die obigen Arrays tragen minItems und maxItems, der Server setzt beides durch, und die Zahlen unterscheiden sich je Endpunkt — heute reicht die Spanne von einem Array, das genau einen Eintrag annimmt, bis zu Arrays mit zehn. Ein Endpunkt derselben Familie kann bei gleichem Feldnamen eine andere Obergrenze haben.

image_urls: must contain at least 1 items
image_urls: must contain at most 3 items

Lesen Sie minItems und maxItems aus dem Schema des Modells, das Sie aufrufen. Eine Parametertabelle, die ein Array als nacktes array ohne Eintragsform und ohne Längengrenze zeigt, ist genau die Zeile, mit der ein Leser nichts anfangen kann — und genau deshalb liefert diese Seite keine.

Die Ausgabegröße wird auf drei Arten geschrieben

Das ist das Erste, worüber die meisten stolpern, wenn sie einen bestehenden Anfragekörper auf einen zweiten Endpunkt richten.

Im Bildkatalog sind drei Schreibweisen in Gebrauch, und ein Endpunkt nimmt genau eine davon an:

SchreibweiseFelderAnmerkung
Getrenntaspect_ratio und resolutionBildformat und Pixelstufe werden getrennt gewählt
VoreinstellungsizeEin Enum-Wert legt beides auf einmal fest
Explizitwidth und heightGanzzahlige Pixel, jeweils mit eigenem minimum und maximum

Die getrennte Schreibweise ist an neueren Endpunkten die häufigste und die nützlichste der drei: aspect_ratio komponiert das Bild vor der Erzeugung, statt hinterher zu beschneiden, sodass Sie die Form ändern können, ohne das Pixelbudget anzutasten.

Ein Feld aus der falschen Schreibweise wird abgelehnt, nicht ignoriert

Jedes Bild-inputSchema setzt additionalProperties: false. Ein Feld, das der Endpunkt nicht führt, wird zurückgewiesen — ein von einem anderen Endpunkt übernommener Anfragekörper scheitert also rundheraus, statt still auf einen Standardwert zurückzufallen.

Es scheitert in beide Richtungen, und die Meldung nennt das Feld:

size: is not a supported field
aspect_ratio: is not a supported field

Berechnet wird für keines von beiden etwas. Der Preis ist nicht Geld, sondern die Annahme: Sie können nicht ein input-Objekt schreiben und es auf mehrere Bild-Endpunkte richten, und es gibt keine "kompatible" Schreibweise, die alle annehmen.

Welche Schreibweise eine Preisstufe auswählt

An einem getrennten Endpunkt spielen die beiden Felder in der Rechnung meist verschiedene Rollen:

  • resolution wählt normalerweise eine Preisstufe. Es erscheint im Kostenvoranschlag als variant, und wer es verstellt, verstellt den Betrag.
  • aspect_ratio normalerweise nicht. Umkomponieren ist kein Skalieren.

Das "normalerweise" in diesen beiden Sätzen arbeitet wirklich. Die maschinenlesbare Antwort steht am Feld selbst: x-ui.affects_price: true und — wenn der Endpunkt es deklariert — die Mitgliedschaft in x-pricing.variantFields. Prüfen Sie das Schema, nicht die Gewohnheit. Siehe Preise lesen und die Annotationsreferenz im Spicy-Schema-Vertrag.

Auch die erlaubten Werte gelten je Endpunkt. Eine Ablehnung listet sie auf, was ein kostenloser Weg ist, sie zu sehen:

aspect_ratio: must be one of: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "21:9"

Praktisch beim Erkunden, aber kein Ersatz dafür, enum zu lesen, denn im Schema steht auch der default, der gilt, wenn Sie das Feld weglassen.

Was ein Referenzbild der Rechnung hinzufügt

Das ist der leise Posten, und er verdient einen eigenen Abschnitt, weil in der Antwort nichts darauf zeigt.

Die übliche Rechnung für ein Medienmodell lautet Preis × Menge, wobei die Menge der Wert von quantityField in Ihrer Eingabe ist, oder eine Einheit, wenn quantityField leer ist. An Bild-Endpunkten ist quantityField meist num_outputs, und es verhält sich genau so, wie man es erwartet: Bitten Sie um vier Bilder, steht im Kostenvoranschlag quantity auf 4. Diese Dimension ist ehrlich — man sieht sie sich bewegen.

Manche Endpunkte berechnen darüber hinaus einen eigenen Betrag für jedes Eingabebild, und diesen sieht man sich nicht bewegen. Holen Sie für denselben Endpunkt zwei Kostenvoranschläge ein, einen mit einer einzigen Referenz und einen mit vollem Array, dann erhalten Sie:

  • dieselbe unit,
  • dieselbe quantity,
  • dieselbe variant,
  • einen anderen Betrag.

Drei der vier Felder, aus denen man üblicherweise eine Schätzung baut, bleiben exakt stehen. Eine aus Preis × Menge berechnete Schätzung fällt zu niedrig aus, und nichts in der Antwort weist darauf hin.

Die maschinenlesbare Signatur

Ein Feld mit x-ui.affects_price: true, das weder das quantityField ist noch in x-pricing.variantFields steht, bewegt den Betrag, ohne eine Stufe auszuwählen. Lesen Sie bei solchen Endpunkten das pricing des Katalogs als Untergrenze und nehmen Sie den Betrag aus einem Kostenvoranschlag.

Das ist dieselbe Regel, die in Modellkatalog und Schemata steht, und Bildbearbeitung ist die Stelle, an der Sie ihr am häufigsten begegnen: Das Array mit den Eingabebildern ist oft so markiert.

Wie viel dazukommt, hängt am Endpunkt und folgt keinem festen Verhältnis. Im heutigen Katalog gibt es Endpunkte, bei denen ein volles Array ein Vielfaches einer einzelnen Referenz kostet, und Endpunkte, bei denen zusätzliche Referenzen gar nichts kosten — unterscheiden lassen sie sich nur, indem man fragt. Schließen Sie also nicht vom Nachbarendpunkt auf den Preis des Arrays, und rechnen Sie ein volles Array nicht aus einem Kostenvoranschlag mit einer einzigen Referenz hoch.

Holen Sie den Voranschlag für den Körper, den Sie wirklich schicken

Diese eine Anfrage bepreisen, bevor sie etwas kostet
curl -sS https://api.spicyapi.ai/api/v1/jobs/quote \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"MODEL_ID_FROM_CATALOG","input":{"prompt":"your instruction","image_urls":["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]}}'

Ein Kostenvoranschlag führt dieselbe Prüfung durch wie das Anlegen der Aufgabe, kostet nichts, startet nichts und legt nichts zurück. Er liefert estimatedCost, maxCharge, quantity und unit für genau diesen Körper. Ändern Sie das Array, holen Sie einen neuen. Einzelheiten und die Wiederherstellung nach einer verlorenen Antwort stehen in Kostenvoranschläge und Kompatibilität; wo ein Voranschlag in einer echten Integration hingehört, in Produktivintegration.

Adaptergewichte

An manchen Endpunkten können Sie eigene feinabgestimmte Gewichte über das Basismodell legen. Das kanonische Feld heißt loras, oder high_noise_loras und low_noise_loras, wenn ein Endpunkt seine Stufen getrennt anbietet.

Ein Array von Objekten, mit eigenen Regeln im Inneren

Diese Felder tragen x-ui.widget: "object-list": ein Array, dessen items ein vollständiges Objektschema für sich ist. Es hat ein eigenes required, ein eigenes additionalProperties: false sowie eigenen Typ, Bereich und default für jedes Unterfeld. Ein typischer Eintrag benennt einen Satz Gewichte und wie stark er anzuwenden ist.

Zwei Einträge, gemeinsam angewendet
{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "prompt": "your scene",
    "loras": [
      { "path": "https://weights.example.com/style.safetensors", "scale": 1 },
      { "path": "https://weights.example.com/character.safetensors", "scale": 0.6 }
    ]
  }
}

Die Form eines Eintrags ist nicht über alle Endpunkte hinweg festgelegt. Was als Gewichtsdatei zählt — eine direkte Adresse oder ein Schlüssel aus einer eingebauten Bibliothek — engt das items-Teilschema des jeweiligen Endpunkts ein, ebenso die Namen der Unterfelder, wie viele Einträge hineinpassen und welche davon Pflicht sind. Lesen Sie items, nicht dieses Beispiel. Das Widget beschreibt der Spicy-Schema-Vertrag; wie man daraus eine verschachtelte Tabelle macht, zeigt Modellkatalog und Schemata.

Eine Regel im Inneren dieser Einträge wird leicht falsch gelesen: Standardwerte greifen bis in die Array-Einträge hinein. Ein Unterfeld, das in items.required steht und einen default hat, ist praktisch optional — lassen Sie es weg, wird der Standard vor der Prüfung eingesetzt. Ein Unterfeld ohne Standard wird abgelehnt, wenn es fehlt. items.required heißt also nicht "muss in dem JSON stehen, das ich schicke".

Woher die Gewichte kommen

path nimmt eine von drei Angaben entgegen:

  • Ein öffentlicher Link auf die .safetensors-Datei oder, sofern der Endpunkt es zulässt, eine Hugging-Face-Repo-ID wie owner/repo. Das Modell lädt sie zur Erzeugungszeit herunter, deshalb ist der erste Aufruf mit neuen Gewichten merklich langsamer als spätere.
  • Ein Upload. Laden Sie die Datei als application/octet-stream mit dem direkten Upload-Ablauf hoch, bis zu 2 GiB, und verwenden Sie die zurückgegebene spicy://f/…-URI. Beim Commit wird geprüft, ob es sich um eine vollständige Safetensors-Datei handelt.
  • Ein Import. Für eine Datei, die eine Anmeldung erfordert, etwa in einem privaten oder geschützten Hugging-Face-Repository oder eine Civitai-Datei hinter einem API-Schlüssel, senden Sie den Link und ein Zugriffstoken an POST /api/v1/files/import. SpicyAPI lädt die Datei einmal herunter und gibt eine spicy://f/…-URI zurück. Das Token wird nur für diesen Download verwendet und nie gespeichert.
LoRA aus einem privaten Hugging-Face-Repository importieren
curl -sS https://api.spicyapi.ai/api/v1/files/import \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  --data "$(jq -n --arg url "https://huggingface.co/OWNER/REPO/blob/main/your_lora.safetensors" --arg token "$HF_TOKEN" '{url: $url, token: $token}')"

url kann auch die Repo-ID (OWNER/REPO) oder die Repository-Seite sein, wenn das Repository genau eine .safetensors-Datei enthält. Die Antwort hat dieselbe Form wie bei einem Commit; tragen Sie data.uri in loras[].path ein. Hochgeladene und importierte Gewichte werden wie jeder andere Upload einen Tag lang aufbewahrt und nie mit anderen Konten geteilt. Danach laden Sie sie erneut hoch oder importieren sie erneut.

Beim Absenden wird der Link geprüft, nicht die Gewichte darin

Bevor eine Aufgabe angelegt wird, wird jeder Gewichtslink geprüft. Ein Link, der eine Anmeldung verlangt, 404 zurückgibt oder eine Webseite öffnet, wird mit 400 abgelehnt, es wird nichts berechnet, und die Meldung nennt den betreffenden Eintrag. Alles andere geht durch: Fällt ein Host später aus oder lassen sich Gewichte nicht laden, erreicht Sie das als fehlgeschlagene Aufgabe.

Probleme, die die Prüfung nicht erkennen kann, kommen später als fehlgeschlagene Aufgabe zurück, mit einem errorCode aus den neun öffentlichen Klassen der Plattform und einer Meldung, die erklärt, was schiefgelaufen ist; der für die Aufgabe reservierte Betrag wird zurückgegeben. Siehe Fehler.

Der schlimmste Fall ist noch leiser: Gewichte, die für ein anderes Basismodell gebaut wurden, können ohne Fehler geladen werden und die Ausgabe fast gar nicht verändern. Es gibt keinen Fehler zu lesen, nur ein Bild, das aussieht wie das des Basismodells.

Prüfen Sie also beim Deployment

Verlagern Sie die Prüfung aus dem Anfragepfad in das, was beim Ausliefern läuft:

  1. Erreichbarkeit. Eine HEAD-Anfrage an jede Gewichtsadresse, die produktiv gehen soll. Die Plattform prüft jeden Link zwar beim Anlegen einer Aufgabe, aber ein Link, der heute funktioniert, kann nächste Woche ausfallen, und eine Prüfung beim Deployment fängt das ab, bevor Ihr Traffic es merkt.
  2. Wirkung. Eine Erzeugung pro neuer Gewichtsdatei, verglichen mit demselben Prompt und demselben Seed ohne sie. Sind die beiden nicht unterscheidbar, tut die Datei nicht, was Sie glauben — klären Sie das, bevor ein Stapellauf darauf baut.
  3. Beständigkeit. Ihre Adressen müssen funktionieren, solange sie produktiv sind. Eine verschwundene Gewichtsdatei wird zu fehlgeschlagenen Aufgaben ohne erkennbare Ursache, Tage nach dem Deployment, dem man sie anlastet.

Endpunktspezifische Hinweise zu diesen Feldern — woran ein Wert tatsächlich gemessen wird, welche Einstellung einen Aufruf spürbar verlangsamt, welche Eingaben das Schema zwar annimmt, Sie aber bereuen werden — stehen in paramNotes des öffentlichen Katalogs, nach Parameternamen geschlüsselt und in allen zehn Dokumentationssprachen verfügbar. Das ist Prosa, nie eine Regel; was angenommen wird, entscheidet weiterhin inputSchema. Siehe Modellkatalog und Schemata.

Asynchron wie jedes andere Medienmodell

Bild-Endpunkte sind Aufgaben, keine Anfrage-Antwort-Aufrufe. Sie legen eine Aufgabe an und holen das Ergebnis per Polling oder Webhook ab; queued und running sind nicht-terminal, succeeded, failed und expired sind terminal. Maßgeblich für die Zustände ist Asynchrone Aufgaben.

Bilder sind schneller fertig als Videos, was dazu verführt, den Aufruf zu schreiben, als wäre er synchron. Widerstehen Sie: Ein begrenztes Polling fühlt sich hier kurz genug an, um synchron zu wirken, aber der Code muss trotzdem mit einer Aufgabe umgehen, die noch läuft, wenn das Wartebudget aufgebraucht ist — und das einem Webhook zu übergeben skaliert besser, als eine Anfrage offen zu halten. Polling nutzt das Lesekontingent des Kontos unabhängig von der Task-Einreichung. Übermäßiges Polling kann Statusabfragen begrenzen; siehe Ratenbegrenzungen.

Das Ergebnis lesen

Eine erfolgreiche Aufgabe führt ihre Dateien in output.assets[] auf. Drei Dinge dazu an Bild-Endpunkten:

  • Es kann mehr als eine Datei enthalten. Liegt num_outputs über eins, bekommen Sie ein Asset je Bild. Schreiben Sie den Handler von Anfang an als Schleife; ein Handler, der assets[0] liest, verwirft still alles, wofür Sie bezahlt haben.
  • Die Endung bestimmt mime, nicht der Endpunktname und nicht der Prompt. Bietet ein Endpunkt output_format, wählt dieses Feld die Kodierung; bietet er es nicht, ist die Kodierung Sache des Endpunkts, und mime ist der einzige Weg zu erfahren, was Sie bekommen haben.
  • Eine noch kopierte Datei hat pending: true und keine url. Ergebnisse werden in SpicyAPIs eigenen Speicher kopiert, bevor sie herausgegeben werden; das dauert ein paar Sekunden, nachdem die Aufgabe Erfolg gemeldet hat. Lesen Sie die Aufgabe erneut, statt den fehlenden Link als Fehler zu behandeln.

Download-Links gelten etwa zwanzig Minuten und brauchen keinen API-Schlüssel; für einen frischen lesen Sie die Aufgabe erneut. Erzeugte Dateien werden höchstens vierzehn Tage aufbewahrt, kürzer, wenn die Aufbewahrung Ihres Kontos kürzer eingestellt ist. Siehe Ergebnisse und Downloads und Aufbewahrung und Löschung.

Eine Ablehnung lesen

Eine abgelehnte Anfrage kostet nichts und legt nichts an, deshalb taugt der Kostenvoranschlag zugleich als kostenloser Prüfer für den Körper, den Sie gleich abschicken.

Es werden alle Probleme gemeldet, nicht nur das erste. Die Meldung verbindet sie mit ; , ein abgelehnter Voranschlag kann Ihnen also alles nennen, was an einem Körper nicht stimmt:

prompt: is required; loras.0.path: is required; loras.0.scale: must be at most 4; bogus: is not a supported field

Ein Problem innerhalb eines Arrays zeigt auf den Eintrag. Der Zeiger lautet feld.index.unterfeld, mit nullbasiertem Index:

loras.1.scale: must be at most 4

Geben Sie diesen Zeiger an den weiter, der es beheben muss. Wenn mehrere Einträge im Spiel sind, ist das Wissen, welcher außerhalb des Bereichs liegt, der Unterschied zwischen einer Einzeilenkorrektur und einer Bisektion.

Die Formen, denen Sie begegnen werden:

MeldungBedeutungWas tun
X: is requiredX steht in der required-Liste der WurzelErgänzen. An bearbeitenden Endpunkten meist prompt oder das Bildfeld
X: is not a supported fieldX steht nicht in properties; unbekannte Felder werden abgelehnt, nie ignoriertEntfernen oder die Schreibweise dieses Endpunkts verwenden — siehe Ausgabegröße
X: must be one of: …Der Wert liegt außerhalb von enumDie Meldung listet die zulässigen Werte; enum und default stehen im Schema
X: must contain at least N itemsUnter minItemsEin Array, das der Endpunkt verlangt, darf nicht leer geschickt werden
X: must contain at most N itemsÜber maxItemsDie Obergrenze dieses Endpunkts lesen; sie ist nicht überall gleich
X: must be an arrayDer Wert hat nicht den deklarierten TypEinen einzelnen Eintrag in eine Liste packen
X: must be at most N charactersÜber maxLengthAuch Prompts haben je Endpunkt eine Obergrenze
X.<n>.<sub>: is requiredEin Unterfeld von Eintrag <n> ist Pflicht und hat keinen StandardNur in diesem Eintrag ergänzen
X.<n>.<sub>: is not a supported fieldDas Eintragsschema setzt additionalProperties: falseDiesen Schlüssel aus diesem Eintrag entfernen
X.<n>.<sub>: must be at most NDas Unterfeld liegt außerhalb seines eigenen BereichsBegrenzen; Bereiche gelten je Unterfeld, nicht je Array

Kommt die Ablehnung, obwohl Sie mit Erfolg gerechnet hatten, liegt es meist an einem veralteten Schema. Lesen Sie den Katalog nach einem 400 neu und behalten Sie niemals einen dauerhaften Abzug — Den Katalog zwischenspeichern sagt, wie lange eine Kopie gut ist. Den Rest deckt Fehlersuche ab.

Nächste Schritte

Auf dieser Seite