# 🪄 API Reference — ID Photo Retoucher **Base URL:** `https://esmailx51-retoucher.hf.space` **Gradio API Prefix:** `/gradio_api` **API Endpoint:** `/gradio_api/run/retouch` **Interactive Docs:** [View on Hugging Face](https://huggingface.co/spaces/esmailx51/retoucher?view=api) --- ## Overview The retoucher exposes its interface and programmatic prediction endpoints through Gradio. > [!WARNING] > **Hugging Face Spaces Queue Requirement (Gradio 5):** > Since this Space runs on ZeroGPU with queueing enabled, direct stateless HTTP `POST` requests (using raw `requests` or `cURL`) to the `/gradio_api/run/retouch` endpoint are blocked with a `404 Not Found` error (`"This API endpoint does not accept direct HTTP POST requests. Please join the queue to use this API."`). > > To consume the API programmatically, **you must use the official client libraries** (`gradio_client` in Python or `@gradio/client` in JavaScript/TypeScript) as shown in Section 1 and Section 3. The clients automatically handle the SSE queue handshake and state tracking. Raw HTTP/cURL calls will only work in local development environments where the queue is disabled. | Field | Value | |-------|-------| | Endpoint (Local/No Queue) | `POST /gradio_api/run/retouch` | | Upload Endpoint (Local/No Queue) | `POST /gradio_api/upload` | | Queue | Enabled (requests are queued) | | GPU | ZeroGPU A10G (allocated on-demand per request) | | Max File Size | No limit | | Cold Start | ~30–60s (first request after idle downloads model weights) | --- ## Parameters | # | Name | Type | Default | Range | Description | |---|------|------|---------|-------|-------------| | 1 | `image` | `Image` | *required* | — | Input face photo (file path, URL, or base64) | | 2 | `strength` | `float` | `0.6` | `0.0 – 1.0` | Skin retouching intensity. 0 = no change, 1 = full GFPGAN restoration | | 3 | `undereye_strength` | `float` | `0.5` | `0.0 – 1.0` | Under-eye correction intensity. 0 = no correction, 1 = maximum brightening | | 4 | `crease_strength` | `float` | `0.4` | `0.0 – 1.0` | Crease/sag softening. Softens smile lines, marionette folds, double chins | | 5 | `jaw_tighten` | `float` | `0.3` | `0.0 – 1.0` | Jawline tightening. Gently warps/lifts sagging jowls inward | | 6 | `show_masks` | `bool` | `false` | — | If true, returns a debug visualization with mask overlays | ## Returns | # | Name | Type | Description | |---|------|------|-------------| | 1 | `retouched_image` | `Image` | The retouched face photo | | 2 | `debug_image` | `Image \| null` | Debug visualization (only if `show_masks=true`). Green = skin, Orange = under-eye, Blue = wrinkle zones | --- ## Usage Examples ### 1. Python — Gradio Client (Recommended) The easiest way. Install with `pip install gradio_client`. ```python from gradio_client import Client # Connect to the Space client = Client("esmailx51/retoucher") # Basic usage — just retouch with defaults result = client.predict( "photo.jpg", # local file path 0.6, # skin strength 0.5, # undereye strength 0.4, # crease strength 0.3, # jaw tighten False, # show debug masks api_name="/retouch" ) retouched_path = result[0] # path to the retouched image debug_path = result[1] # None (since show_masks=False) print(f"Retouched image saved to: {retouched_path}") ``` #### From a URL instead of a local file ```python from gradio_client import Client, handle_file client = Client("esmailx51/retoucher") result = client.predict( handle_file("https://example.com/face.jpg"), 0.7, 0.5, 0.4, 0.3, False, api_name="/retouch" ) ``` #### Aggressive retouching (older subjects) ```python result = client.predict( "photo.jpg", 0.8, # strong skin smoothing 0.7, # strong undereye correction 0.7, # strong wrinkle reduction 0.5, # strong jaw tightening False, api_name="/retouch" ) ``` #### Minimal retouching (young subjects) ```python result = client.predict( "photo.jpg", 0.3, # light skin smoothing 0.2, # light undereye 0.1, # minimal wrinkle reduction 0.0, # no jaw tightening False, api_name="/retouch" ) ``` #### With debug masks ```python result = client.predict( "photo.jpg", 0.6, 0.5, 0.4, 0.3, True, # show debug masks api_name="/retouch" ) retouched = result[0] debug_vis = result[1] # side-by-side: masks overlay | retouched result ``` --- ### 2. Python — requests (Raw HTTP) > [!CAUTION] > **Local/No-Queue only:** This raw HTTP request method will return a `404 / Please join the queue` error on the hosted Hugging Face Space. It only works in local development environments where the Gradio queue is disabled. For hosted Spaces, you must use the `gradio_client` library (Section 1). ```python import requests import json from pathlib import Path # In Gradio 5, endpoints are prefixed with /gradio_api BASE_URL = "http://127.0.0.1:7860/gradio_api" # Step 1: Upload the image to the local Gradio server with open("photo.jpg", "rb") as f: upload_resp = requests.post( f"{BASE_URL}/upload", files={"files": ("photo.jpg", f, "image/jpeg")} ) uploaded_files = upload_resp.json() file_path = uploaded_files[0] # server-side temp path # Step 2: Call the local API prediction endpoint (/run/retouch) payload = { "data": [ {"path": file_path, "meta": {"_type": "gradio.FileData"}}, 0.6, # skin strength 0.5, # undereye strength 0.4, # crease strength 0.3, # jaw tighten False # show masks ] } resp = requests.post(f"{BASE_URL}/run/retouch", json=payload) result = resp.json() # Step 3: Extract & download the result # In Gradio 5, the direct response maps outputs to keys like "output" (or "data" fallback) if "data" in result: retouched_url = result["data"][0]["url"] else: retouched_url = result["output"]["url"] img_data = requests.get(retouched_url).content Path("retouched.jpg").write_bytes(img_data) print("Saved retouched.jpg") ``` --- ### 3. JavaScript / TypeScript Install with `npm install @gradio/client`. ```javascript import { Client } from "@gradio/client"; const client = await Client.connect("esmailx51/retoucher"); const result = await client.predict("/retouch", { image: "https://example.com/face.jpg", // URL or Blob strength: 0.6, undereye_strength: 0.5, crease_strength: 0.4, jaw_tighten: 0.3, show_masks: false, }); console.log(result.data); // [{ url: "https://...retouched.webp", ... }, null] ``` #### With a local file (Node.js) ```javascript import { Client, handle_file } from "@gradio/client"; import fs from "fs"; const client = await Client.connect("esmailx51/retoucher"); const result = await client.predict("/retouch", { image: handle_file("./photo.jpg"), strength: 0.6, undereye_strength: 0.5, crease_strength: 0.4, jaw_tighten: 0.3, show_masks: false, }); // Download the retouched image const imageUrl = result.data[0].url; const response = await fetch(imageUrl); const buffer = Buffer.from(await response.arrayBuffer()); fs.writeFileSync("retouched.jpg", buffer); ``` #### Browser (Fetch from a file input) ```javascript import { Client } from "@gradio/client"; async function retouchPhoto(fileInput) { const client = await Client.connect("esmailx51/retoucher"); const file = fileInput.files[0]; const result = await client.predict("/retouch", { image: new Blob([await file.arrayBuffer()], { type: file.type }), strength: 0.6, undereye_strength: 0.5, crease_strength: 0.4, jaw_tighten: 0.3, show_masks: false, }); // Display the result const imgUrl = result.data[0].url; document.getElementById("result").src = imgUrl; } ``` --- ### 4. cURL > [!CAUTION] > **Local/No-Queue only:** This cURL method will return a `404 / Please join the queue` error on the hosted Hugging Face Space. It only works in local development environments where the Gradio queue is disabled. For hosted Spaces, you must use the official client libraries (Section 1 & 3). ```bash # Step 1: Upload the image (pointing to local Gradio 5 API prefix) FILE_PATH=$(curl -s -X POST \ "http://127.0.0.1:7860/gradio_api/upload" \ -F "files=@photo.jpg" \ | jq -r '.[0]') # Step 2: Call the API prediction endpoint curl -s -X POST \ "http://127.0.0.1:7860/gradio_api/run/retouch" \ -H "Content-Type: application/json" \ -d "{ \"data\": [ {\"path\": \"$FILE_PATH\", \"meta\": {\"_type\": \"gradio.FileData\"}}, 0.6, 0.5, 0.4, 0.3, false ] }" | jq -r '.output.url' ``` --- ## Batch Processing (Python) Process multiple images in sequence: ```python from gradio_client import Client from pathlib import Path client = Client("esmailx51/retoucher") input_dir = Path("./input_photos") output_dir = Path("./retouched") output_dir.mkdir(exist_ok=True) for img_path in input_dir.glob("*.jpg"): print(f"Processing {img_path.name}...") result = client.predict( str(img_path), 0.6, 0.5, 0.4, 0.3, False, api_name="/retouch" ) # Copy result to output directory retouched = Path(result[0]) retouched.rename(output_dir / img_path.name) print(f" → Saved to {output_dir / img_path.name}") ``` --- ## Integration Example: Flask Backend ```python from flask import Flask, request, send_file from gradio_client import Client import tempfile, shutil app = Flask(__name__) gr_client = Client("esmailx51/retoucher") @app.route("/retouch", methods=["POST"]) def retouch(): # Save uploaded file photo = request.files["photo"] strength = float(request.form.get("strength", 0.6)) undereye = float(request.form.get("undereye", 0.5)) creases = float(request.form.get("creases", 0.4)) jaw = float(request.form.get("jaw", 0.3)) with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp: photo.save(tmp.name) result = gr_client.predict( tmp.name, strength, undereye, creases, jaw, False, api_name="/retouch" ) return send_file(result[0], mimetype="image/webp") if __name__ == "__main__": app.run(port=5000) ``` --- ## Error Handling ```python from gradio_client import Client from gradio_client.exceptions import AppError client = Client("esmailx51/retoucher") try: result = client.predict( "photo.jpg", 0.6, 0.5, 0.4, 0.3, False, api_name="/retouch" ) except AppError as e: if "No face detected" in str(e): print("No face found in the image") elif "queue is full" in str(e): print("Server is busy, try again later") else: print(f"API error: {e}") except ConnectionError: print("Space is sleeping — the first request wakes it up (~60s)") ``` --- ## Tuning Guide | Goal | strength | undereye | creases | jaw | |------|----------|----------|---------|-----| | **Natural / Minimal** | 0.3 | 0.2 | 0.1 | 0.0 | | **Balanced (default)** | 0.6 | 0.5 | 0.4 | 0.3 | | **Aggressive (older subjects)** | 0.8 | 0.7 | 0.7 | 0.5 | | **Skin only (no anti-aging)** | 0.6 | 0.0 | 0.0 | 0.0 | | **Under-eye only** | 0.0 | 0.7 | 0.0 | 0.0 | --- ## Rate Limits & Notes - **Cold start**: If the Space has been idle, the first request takes ~30–60 seconds (model download + loading). Subsequent requests are fast (~5–10s on GPU). - **Queue**: Requests are queued. If the Space is busy, your request will wait in line. - **GPU timeout**: ZeroGPU allocates GPU per-request. Very large images may time out. - **Output format**: Retouched images are returned as PNG by default to maintain high-resolution lossless quality. - **No face detected**: If no face is found, the original image is returned unchanged.