Generate person
Transform people with our advanced AI model
You will need an API token to send HTTP requests. See Authentication for instructions.
Quick start
Firstly, you'll need to upload the image you want to process. These parameters must be supplied as multipart form data:
| Parameter | Example | Description | 
|---|---|---|
| file | @file.png | The image file as binary data. | 
Please note that we only support the following formats: WEBP, JPEG and PNG. Note down these fields from the response:
{
  "image_id": "67762577...", // IMAGE_ID
  "num_persons": 2,
  "coordinates_list": [
    {
      "id": 0                // PERSON_ID
      "approve": true,       // Usable if true otherwise too blurry
      // ...
    },
    {
      "id": 1                // PERSON_ID
      "approve": true,       // Usable if true otherwise too blurry
      // ...
    }
  ]
}For more information about the data contained in coordinates_list and how to process it, see Coordinates.
To understand how to use the image_id parameter, also see Image ID.
To generate a person, you will have to call the endpoint:
- once for each person you want to replace in the original image
- once for each keyword you want to use for a person
This will start asynchronous processes that will be handled in the next step.
This is an example of request containing all required fields for the person with "id": 0 (zero):
{
  "id_image": "67762577...",      // IMAGE_ID
  "id_person": "0",               // PERSON_ID as string
  "keyword": "{\"Location\":\"Oceania\"}"
}For more information on the usage of the keyword parameter, see Keywords.
Notification objects returned by this endpoint will inform you of the end of a generation on our servers. We recommend sending a request every 3 seconds at most, to not incur in rate limiting.
{
  "name_list": ["edit_generate"]
}After the process is complete, you might see a similar response:
{
  "notifications_list": [
    {
      "data": {
        "id_person": 0,             // PERSON_ID
        "address": "67762577...",   // IMAGE_ID
        "links": [{
          "l": "https://..."        // Download link
          // ...
        }],
      },
      "name": "edit_generate",
    },
  ]
}Where "l" points to a fully ready, modified version of the original image with the specified person replaced as you requested in the previous step.
Uploading an image
Be careful!
All target images are deleted automatically after 24 hours of being uploaded. This action cannot be undone.
You can upload any image containing up to 30 people. Their faces will be automatically detected by the API. Please note that we only support the following formats: WEBP, JPEG and PNG.
import json
import requests
api_url = "https://api.piktid.com/api"
access_token = "your_access_token"
target_path = "path_to_image"
with open(target_path, "rb") as target:
    response = requests.post(
        api_url + "/edit/target",
        headers={"Authorization": "Bearer " + access_token},
        files={
            "file": target
        },
    ).json()
    image_id = response.get("id_image")Generating a person
Our API can generate a single person with a single keyword at a time, but parallel processing is allowed and recommended. To generate multiple people at once, or a single person with multiple keywords, you just have to send multiple requests.
import json
import requests
api_url = "https://api.piktid.com/api"
access_token = "your_access_token"
image_id = "67762577..."
person_id = 0
keywords = [
    {"Location": "East Asia"}, 
    {"Location": "South America"}
]
keyword = keywords[0]
requests.post(
    api_url + "/edit/generate",
    headers={"Authorization": "Bearer " + access_token},
    json={
        "id_image": image_id,
        "id_person": person_id,
        "keyword": json.dumps(keyword),
        "category": "person"
    },
)
# A 15 second timeout is encouraged due to internal API limitations.
# See below for explanation.
time.sleep(15)
for keyword in keywords[1:]:
    requests.post(
        api_url + "/edit/generate",
        headers={"Authorization": "Bearer " + access_token},
        json={
            "id_image": image_id,
            "id_person": person_id,
            "keyword": json.dumps(keyword),
            "category": "person"
        },
    )Why is time.sleep(15) needed?
The first call to /edit/generate creates internal files and data (for example masks for a single person).
This allows all subsequent requests to get a head start because of the already existing data.
If all requests are made in parallel, each one has to generate the initial data, thus taking a lot longer than sending them in a staggered way.
Keywords
A keyword defined as a single key-value pair, where:
- the key is a generic group (for example "Location")
- the value is an expression or physical state of the key (for example "South America")
To better explain this concepts, here are the currently defined prompts as programming language type definitions:
from dataclasses import dataclass
from typing import Literal
@dataclass
class Prompt:
    Location: Literal[
        "Africa",
        "East Asia",
        "Middle East",
        "North America",
        "North Europe",
        "Oceania",
        "South America",
        "South Europe",
    ]type Prompt = Partial<{
  Location:
    | "Africa"
    | "East Asia"
    | "Middle East"
    | "North America"
    | "North Europe"
    | "Oceania"
    | "South America"
    | "South Europe"
}>In both languages, the following are valid prompt objects:
{
  "Location": "North America",
}{
  "Location": "Middle East",
}Waiting for results
Be careful!
Notifications are automatically deleted after exactly 10 minutes (600 seconds) from their creation.
Results are shared to clients via "notifications". Clients are expected to poll for notifications and handle them in the allowed time limit before they are automatically dismissed by the API.
import time
import requests
from pprint import pprint
api_url = "https://api.piktid.com/api"
access_token = "your_access_token"
image_id = "67762577..."
def process_notifications(response, image_id):
    for notification in response.get("notifications_list", []):
        if notification["name"] != "edit_generate":
            return None, None
        if notification["data"]["address"] != image_id:
            return None, None
        return notification["data"], notification["id"]
    return None, None
def delete_notification(notification_id):
    requests.delete(
        api_url + "/notification/delete_json",
        headers={"Authorization": "Bearer " + access_token},
        json={"id": notification_id},
    )
count = 0
# Loops for 10 minutes, even though generating people generally
# takes less time.
for _ in range(600):
    response = requests.post(
        api_url + "/notification_by_name_json",
        headers={"Authorization": "Bearer " + access_token},
        json={"name_list": "edit_generate,error"},
    ).json()
    data, notification_id = process_notifications(response, image_id)
    if data is not None:
        # Delete the notification to avoid reading it again
        delete_notification(notification_id)
        print(
            f"Person with ID {data['id_person']} generated! Keyword: {data['keyword']}"
        )
        link = data["links"][0]
        # The "l" field contains a static link to the final image
        print(link["l"])
        count += 1
        if count == len(keywords):
            break
    time.sleep(1)PRO users can also disable watermark application on the final image.