Skip to Content
Code Demo

Code Demo

JavaScript

import fs from "node:fs"

const BASE_URL = "https://undressme.ai"
// API key from /account/api (Authorization: Bearer <API_KEY>).
const API_KEY = process.env.API_KEY
// Local image path to upload as task source.
const FILE_PATH = process.env.FILE_PATH

if (!API_KEY || !FILE_PATH) {
  console.error("Missing API_KEY or FILE_PATH")
  process.exit(1)
}

// Shared auth header for all API calls that hit our API server.
const headers = {
  Authorization: `Bearer ${API_KEY}`,
}

// Step 1: ask server for presigned upload URL.
async function presign() {
  const res = await fetch(`${BASE_URL}/api/presign`, {
    method: "POST",
    headers,
  })
  if (!res.ok) {
    throw new Error(`presign failed: ${res.status}`)
  }
  // Response shape: { key, uploadUrl }
  return res.json()
}

// Step 2: upload the local file directly to R2 using the presigned URL.
async function uploadToPresignedUrl(uploadUrl, filePath) {
  // Object storage requires a correct Content-Length header.
  const stat = fs.statSync(filePath)
  // Stream the file to avoid loading it fully into memory.
  const body = fs.createReadStream(filePath)

  const res = await fetch(uploadUrl, {
    method: "PUT",
    headers: {
      "Content-Length": stat.size.toString(),
    },
    duplex: "half",
    body,
  })

  if (!res.ok) {
    throw new Error(`upload failed: ${res.status}`)
  }
}

// Step 3: create a task with the source key returned by presign.
async function createTask(type, sourceKey) {
  // "type" must be one of the values returned by /api/task-types.
  const res = await fetch(`${BASE_URL}/api/tasks`, {
    method: "POST",
    headers: {
      ...headers,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type, sourceKey }),
  })
  if (!res.ok) {
    const payload = await res.json().catch(() => null)
    throw new Error(`create task failed: ${res.status} ${payload?.error || ""}`)
  }
  // Response shape: { taskId, status, creditsRemaining }
  return res.json()
}

// Optional: list all available task types.
async function fetchTaskTypes() {
  const res = await fetch(`${BASE_URL}/api/task-types`, {
    headers,
  })
  if (!res.ok) {
    throw new Error(`task types failed: ${res.status}`)
  }
  // Response shape: { types: [...] }
  return res.json()
}

// Step 4: poll until the task is completed or errors.
async function pollTask(taskId) {
  while (true) {
    const res = await fetch(`${BASE_URL}/api/tasks/${taskId}`, {
      headers,
    })
    if (!res.ok) {
      throw new Error(`poll failed: ${res.status}`)
    }
    const data = await res.json()
    // The API returns "processing", "completed", or "error".
    if (data.status === "completed") {
      return data
    }
    if (data.status === "error") {
      throw new Error(`task error: ${JSON.stringify(data)}`)
    }
    // Keep polling under the 5/sec rate limit.
    await new Promise((r) => setTimeout(r, 1500))
  }
}

async function run() {
  // One upload can be used for multiple tasks.
  console.log("Fetching task types...")
  const taskTypes = await fetchTaskTypes()
  console.log("Available task types:", taskTypes.types)

  console.log("Presigning...")
  const { key, uploadUrl } = await presign()

  console.log("Uploading...")
  await uploadToPresignedUrl(uploadUrl, FILE_PATH)

  // Create two tasks: undress (image) and video_blowjob (video).
  console.log("Creating undress task...")
  // Use the "key" returned by presign as the sourceKey for tasks.
  const undress = await createTask("undress", key)

  console.log("Creating video_blowjob task...")
  const video = await createTask("video_blowjob", key)

  console.log("Polling undress...")
  const undressResult = await pollTask(undress.taskId)
  console.log("Undress result:", undressResult.resultUrl)

  console.log("Polling video...")
  const videoResult = await pollTask(video.taskId)
  console.log("Video result:", videoResult.resultUrl)
}

run().catch((err) => {
  console.error(err)
  process.exit(1)
})

Python

#!/usr/bin/env python3
import json
import os
import sys
import time
from pathlib import Path

import requests

BASE_URL = "https://undressme.ai"
# API key from /account/api (Authorization: Bearer <API_KEY>).
API_KEY = os.environ.get("API_KEY")
# Local image path to upload as task source.
FILE_PATH = os.environ.get("FILE_PATH")

if not API_KEY or not FILE_PATH:
    print("Missing API_KEY or FILE_PATH", file=sys.stderr)
    sys.exit(1)

headers = {
    "Authorization": f"Bearer {API_KEY}",
}

# Step 1: ask server for presigned upload URL.
def presign():
    res = requests.post(f"{BASE_URL}/api/presign", headers=headers, timeout=30)
    if not res.ok:
        raise RuntimeError(f"presign failed: {res.status_code}")
    # Response shape: { key, uploadUrl }
    return res.json()

# Step 2: upload the local file directly to R2 using the presigned URL.
def upload_to_presigned_url(upload_url: str, file_path: str):
    path = Path(file_path)
    size = path.stat().st_size
    with path.open("rb") as f:
        res = requests.put(
            upload_url,
            data=f,
            headers={
                "Content-Length": str(size),
            },
            timeout=120,
        )
    if not res.ok:
        raise RuntimeError(f"upload failed: {res.status_code}")

# Step 3: create a task with the source key returned by presign.
def create_task(task_type: str, source_key: str):
    res = requests.post(
        f"{BASE_URL}/api/tasks",
        headers={
            **headers,
            "Content-Type": "application/json",
        },
        data=json.dumps({"type": task_type, "sourceKey": source_key}),
        timeout=30,
    )
    if not res.ok:
        payload = None
        try:
            payload = res.json()
        except Exception:
            payload = None
        err = payload.get("error") if isinstance(payload, dict) else ""
        raise RuntimeError(f"create task failed: {res.status_code} {err}")
    # Response shape: { taskId, status, creditsRemaining }
    return res.json()

# Optional: list all available task types.
def fetch_task_types():
    res = requests.get(f"{BASE_URL}/api/task-types", headers=headers, timeout=30)
    if not res.ok:
        raise RuntimeError(f"task types failed: {res.status_code}")
    # Response shape: { types: [...] }
    return res.json()

# Step 4: poll until the task is completed or errors.
def poll_task(task_id: str):
    while True:
        res = requests.get(f"{BASE_URL}/api/tasks/{task_id}", headers=headers, timeout=30)
        if not res.ok:
            raise RuntimeError(f"poll failed: {res.status_code}")
        data = res.json()
        # The API returns "processing", "completed", or "error".
        if data.get("status") == "completed":
            return data
        if data.get("status") == "error":
            raise RuntimeError(f"task error: {json.dumps(data)}")
        # Keep polling under the 5/sec rate limit.
        time.sleep(1.5)


def run():
    # One upload can be used for multiple tasks.
    print("Fetching task types...")
    task_types = fetch_task_types()
    print("Available task types:", task_types.get("types"))

    print("Presigning...")
    presigned = presign()
    key = presigned["key"]
    upload_url = presigned["uploadUrl"]

    print("Uploading...")
    upload_to_presigned_url(upload_url, FILE_PATH)

    # Create two tasks: undress (image) and video_blowjob (video).
    print("Creating undress task...")
    undress = create_task("undress", key)

    print("Creating video_blowjob task...")
    video = create_task("video_blowjob", key)

    print("Polling undress...")
    undress_result = poll_task(undress["taskId"])
    print("Undress result:", undress_result.get("resultUrl"))

    print("Polling video...")
    video_result = poll_task(video["taskId"])
    print("Video result:", video_result.get("resultUrl"))


if __name__ == "__main__":
    try:
        run()
    except Exception as err:
        print(err, file=sys.stderr)
        sys.exit(1)
Last updated on