Personen austauschen
Ein Toolkit, zwei Formen. Modelle mit einem Aufruf tauschen Gesicht oder Kopf in einer einzigen Anfrage; Modelle mit zwei Aufrufen analysieren zuerst den Clip, damit Sie auswählen können, wer ausgetauscht wird.
Manche Modelle erzeugen keine neue Szene, sondern ersetzen eine Person: ein Gesicht, das von einem Foto auf ein anderes wandert, ein ganzer Kopf oder eine komplette Figur in einem Videoclip. Der Katalog fasst sie unter einem Label zusammen, toolkit: "subject-swap", und es gibt sie in zwei Formen — ein Aufruf oder zwei Aufrufe mit einer Entscheidung dazwischen.
Sonst ist nichts Besonderes an ihnen. Es sind gewöhnliche asynchrone Tasks, ihre Parameter stehen im jeweils eigenen inputSchema, und ihre Ergebnisse kommen in output.assets[] an.
toolkit verrät, dass ein Modell dazugehört
toolkit ist ein Klassifizierungslabel an einem Katalogeintrag und steht sowohl in der authentifizierten Antwort von GET /api/v1/models als auch im öffentlichen Katalog. Heute gibt es genau einen Wert, subject-swap, und bei Modellen ohne Toolkit fehlt das Feld ganz — prüfen Sie also auf den Wert, nie auf den Schlüssel.
Das Feld ist rein informativ. Es entscheidet weder darüber, welcher Schlüssel ein Modell aufrufen darf, noch wie eine Anfrage bepreist wird oder was das Modell annimmt. Behandeln Sie einen unbekannten Wert wie einen unbekannten Eintrag in badges: ignorieren Sie ihn.
curl -s "https://api.spicyapi.ai/api/v1/models?modality=video" \
-H "Authorization: Bearer $SPICY_API_KEY" \
| jq -r '.data.items[]
| select(.toolkit == "subject-swap" and .enabled and .available)
| [.model, (.tasks | join(",")), .family] | @tsv'Jede Zeile ist ein aufrufbarer Endpunkt. Über den Rest dieser Seite entscheidet die Spalte tasks: Eine family mit einem video-analyze-Endpunkt ist eine family mit zwei Aufrufen, und ihr zugehöriger video-edit-Endpunkt lässt sich nicht allein aufrufen.
Welche Form liegt vor?
| Ein Aufruf | Zwei Aufrufe | |
|---|---|---|
| Endpunkte | Ein einzelner Bearbeitungsendpunkt | video-analyze, dann video-edit, in derselben family |
| Wer ersetzt wird | Was das Modell findet. Die Anfrage hat kein Feld, das eine Person benennt | Die Ziele, die Sie über ihre Position gewählt haben |
| Was Sie senden | Zielbild oder Zielclip plus Ihr Referenzbild, in einer Anfrage | Im ersten Aufruf den Clip; im zweiten die gewählten Positionen mit je eigenen Referenzbildern |
| Was Sie zahlen | Einen Task | Zwei Tasks, getrennt bepreist |
| Geeignet für | Ein offensichtliches Motiv im Bild | Mehrere Personen im Bild, oder wenn ein Fehlgriff teuer wird |
Beide Formen sind async: true: Sie erstellen einen Task und holen das Ergebnis per Polling oder Webhook ab.
Ein Aufruf
Hier unterscheidet sich nichts von anderen Bearbeitungsmodellen. Lesen Sie das inputSchema des Endpunkts, füllen Sie es aus, erstellen Sie den Task:
const created = await fetch('https://api.spicyapi.ai/api/v1/jobs/createTask', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SPICY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'order-8814-swap-1',
},
body: JSON.stringify({
model: swap.model, // ein Eintrag aus der Katalogabfrage oben
input: {
image_url: 'spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3',
reference_image_url: 'spicy://f/fil_01k3m8xb2c3d4e5f6g7h8j9k0m',
},
}),
});Die Feldnamen unterscheiden sich von Endpunkt zu Endpunkt: Manche nehmen einen prompt, einen seed oder ein Ausgabeformat, manche nichts außer den beiden Bildern. Maßgeblich ist allein das Schema; übernehmen Sie Feldnamen nicht von einem Endpunkt auf den nächsten. Referenzen können eine öffentliche HTTPS-URL sein, ein kleines Bild direkt als Base64 oder eine hochgeladene spicy://-URI; siehe Medien.
Zwei Aufrufe
Der erste Aufruf sieht sich Ihren Clip an und meldet, was er gefunden hat — als geordnete Folge von Vorschau-Standbildern. Sie entscheiden, welche davon ersetzt werden. Die eigentliche Arbeit macht der zweite Aufruf.
Ihr Clip ──▶ video-analyze ──▶ output.assets[0], [1], [2] … (ein Standbild je Ziel)
│
Sie wählen die Positionen │ 0 und 2
▼
video-edit (analysis_task_id + swap_targets) ──▶ der fertige ClipWarum nicht in einem Aufruf? Weil ein einzelner Aufruf bei vier Personen im Bild raten müsste, wen Sie meinen — und ein falscher Tipp ergibt ein fertiges, abgerechnetes Video, in dem die falsche Person ersetzt wurde. Die Aufteilung macht die Wahl ausdrücklich und überprüfbar.
Den Clip analysieren
Senden Sie den Clip an den video-analyze-Endpunkt. Setzen Sie resolution ausdrücklich, sofern der Endpunkt das Feld hat — der zweite Aufruf muss mit demselben Wert laufen, wählen Sie hier also die Auflösung, die der fertige Clip haben soll. Auf diesen Endpunkten hängt der Preis der Analyse nicht davon ab.
const analysis = await createTask({
model: analyze.model, // der Eintrag, dessen tasks "video-analyze" enthält
input: {
video_url: 'spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3',
resolution: '720p',
},
});
const analysisTaskId = analysis.taskId;Lesen, was gefunden wurde
Warten Sie wie gewohnt auf den Task. Eine erfolgreiche Analyse liefert ein Vorschau-Standbild je verfolgtem Ziel in output.assets[]:
{
"state": "succeeded",
"output": {
"assets": [
{ "url": "https://…", "expiresAt": "2026-09-20T09:32:11Z", "mime": "image/jpeg" },
{ "url": "https://…", "expiresAt": "2026-09-20T09:32:11Z", "mime": "image/jpeg" }
]
},
"settled": true
}Die Reihenfolge dieses Arrays ist der Vertrag. Der Index eines Eintrags ist der object_index, den Sie im zweiten Aufruf zurücksenden: Das erste Standbild ist 0, das zweite 1 und so weiter. Zeigen Sie die Standbilder der Person, die auswählt, oder ordnen Sie sie selbst zu — die zurückgesendeten Positionen stammen in jedem Fall aus genau diesem Array.
Eine Analyse, die nichts zum Verfolgen findet, endet nicht erfolgreich mit leerem Array: Sie endet als failed mit errorCode: "generation_failed", und die Reservierung wird vollständig freigegeben. Eine Analyse mit succeeded hat also immer mindestens ein Standbild, und Ihr Code muss nur noch eines entscheiden: welches.
Die gewählten Ziele austauschen
Senden Sie die Task-ID der Analyse und je ein swap_targets-Element pro Ziel, das ersetzt werden soll. Nicht genannte Ziele bleiben unangetastet.
const swapped = await createTask({
model: edit.model, // der "video-edit"-Eintrag derselben family
input: {
analysis_task_id: analysisTaskId,
resolution: '720p', // derselbe Wert, mit dem die Analyse lief
swap_targets: [
{ object_index: 0, image_urls: ['spicy://f/fil_01k3m8xb2c3d4e5f6g7h8j9k0m'] },
],
},
});Das Ergebnis ist ein Clip in output.assets[], wie bei jedem anderen Video-Task.
Was der zweite Aufruf vor der Annahme prüft
Diese Prüfungen laufen beim Erstellen, eine abgelehnte Anfrage erzeugt also nichts und reserviert nichts.
| Regel | Warum |
|---|---|
| Die Analyse muss zu Ihrem Konto gehören und erfolgreich gewesen sein | Eine wartende oder fehlgeschlagene Analyse hat nichts, worauf sie verweisen könnte |
| Verwenden Sie für beide Aufrufe denselben API-Schlüssel | Eine Analyse lässt sich nur mit dem Schlüssel zurücklesen, der sie erstellt hat; mit jedem anderen sehen Sie die Standbilder gar nicht, aus denen Sie wählen |
Jeder object_index muss im gültigen Bereich liegen und genau einmal vorkommen | Außerhalb des Bereichs würde stillschweigend die falsche Person ersetzt, doppelt genannt dieselbe zweimal. Beides liefe durch und würde normal abgerechnet |
Preiswirksame Felder wie resolution müssen zur Analyse passen | Würden sie geerbt, bliebe verborgen, in welcher Preisstufe Sie abgerechnet werden |
| Der Quellclip muss derselbe sein | Lassen Sie video_url weg, wird der analysierte Clip verwendet; senden Sie es, muss es identisch sein |
| Die Analyse ist nach ihrem Ende 24 Stunden nutzbar | Danach sind die Tracking-Daten dahinter fort, und oft auch der Quellclip |
Setzen Sie `resolution` in beiden Aufrufen — oder lesen Sie den Standardwert genau
Weggelassene Felder erhalten den default-Wert aus dem Schema, bevor die beiden Anfragen verglichen werden. Eine Analyse im Standard und ein Austausch im Standard passen also zusammen — eine Analyse mit gesetztem Wert und ein Austausch ohne Angabe jedoch nicht, und diese Abweichung wird abgelehnt statt stillschweigend korrigiert. Wer den Wert in beiden Aufrufen ausdrücklich sendet, hat die Frage nicht.
Wenn der zweite Aufruf abgelehnt wird
Alle Fälle sind HTTP 400 mit dem Geschäftscode code: 400. msg ist einer der folgenden Werte:
msg | Was passiert ist | Was zu tun ist |
|---|---|---|
The referenced analysis task was not found. | Kein solcher Task in diesem Konto, oder analysis_task_id ist keine Task-ID | Nehmen Sie die taskId aus Ihrer eigenen Analyse. Ein Task aus einem fremden Konto wird absichtlich genauso gemeldet |
The referenced task belongs to a different model. | Die ID zeigt auf einen anderen Task — oft auf den Austausch-Task selbst oder auf die Analyse einer anderen family | Lassen Sie sie auf den video-analyze-Task derselben family zeigen |
The referenced analysis did not complete successfully. | Die Analyse läuft noch oder endete als failed / expired | Warten Sie sie ab oder starten Sie sie erneut |
That analysis has no reusable result. Run the analysis step again. | Die Analyse war erfolgreich, hat aber nichts hinterlassen, was der Austausch nutzen kann | Führen Sie die Analyse mit demselben Clip erneut aus |
That analysis result has expired. Run the analysis step again. | Es sind mehr als 24 Stunden vergangen | Führen Sie die Analyse erneut aus |
"resolution" must match the analysis step. | Die beiden Aufrufe widersprechen sich in einem preiswirksamen Feld | Senden Sie den Wert der Analyse, oder starten Sie eine neue Analyse mit dem gewünschten Wert |
"video_url" must match the analysis step. | Sie haben einen anderen Clip gesendet | Senden Sie dieselbe URI oder lassen Sie das Feld weg |
That analysis found N target(s); "object_index" is out of range. | Eine Position liegt jenseits dessen, was die Analyse geliefert hat | Positionen beginnen bei null und enden bei assets.length - 1 |
"object_index" is listed more than once. | Zwei Einträge benennen dasselbe Ziel | Geben Sie jedem Ziel einen Eintrag und legen Sie alle seine Referenzbilder in dessen image_urls |
Was die beiden Aufrufe kosten
Analyse und Austausch sind zwei getrennte Tasks mit zwei getrennten Preisen, jeder für sich reserviert und abgerechnet. Ein abgelehnter zweiter Aufruf kostet nichts; eine erfolgreiche Analyse wird berechnet, auch wenn Sie danach auf den Austausch verzichten.
- Die Analyse wird meist
per_requestbepreist — eine Abrechnung je Aufruf, gleich wie lang der Clip ist und wie viele Ziele sie findet. - Der Austausch wird meist
per_secondbepreist, in ganzen Blöcken, und die Länge kommt aus dem Clip statt aus einem Feld, das Sie setzen. Der vorab genannte Betrag gilt deshalb für den längsten Clip, den der Endpunkt annimmt: Der genannte Betrag ist der reservierte Betrag, die endgültige Abrechnung entsteht aus der aufgerundeten Dauer und übersteigt die Reservierung nie, und die Differenz kehrt beim Abrechnen in Ihr Guthaben zurück. Eine Reservierung, die größer ist als die spätere Abrechnung, ist hier zu erwarten. Lesen Sie Abrechnung, bevor Sie damit planen.
Lesen Sie beide Preise aus dem Katalog, statt sie anzunehmen, und holen Sie für jeden Aufruf eine Kostenschätzung ein, wenn es auf den genauen Betrag ankommt.
Nächste Schritte
Modellkatalog und Schemata
toolkit, tasks, Preise und das eigene Eingabeschema jedes Endpunkts lesen
Asynchrone Tasks
Jeden Task erstellen, abfragen und sein Ergebnis lesen
Medien
Clip oder Referenzfoto hochladen und eine spicy://-URI erhalten
Abrechnung
Reservierung, Abrechnung und die Abrechnung der Länge in Blöcken
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.
Integration für den Produktivbetrieb
Eine Checkliste vor dem Start einer Integration, die sich von Fehlern erholt – das richtige Modell, geschützte Schlüssel und geschütztes Guthaben, bestätigte Kosten, dauerhaft verfolgte Tasks, zuverlässige Callbacks und die Tests vor dem Livegang.

