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