Wool Curl Effect

Description

This API generates an AI wool curl effect video in the cloud.

Version

1.0

Image Requirements

Image formats: JPG and PNG.

Request URL

    Production environment: https://openapi.meitu.com
    Task submission endpoint: https://openapi.meitu.com/api/v1/sdk/sync/push
    Task name (task): /v1/wool_roll_video/wool_roll/415444
    Task type (task_type): formula

Request Method

POST

Content-Type: application/json

Authorization

Open Platform API Signature

Request Parameters

RequiredParameterTypeDescription
YesparamsstringAlgorithm parameters as a JSON string. The source document does not define specific algorithm fields.
Yesinit_imagesobject[]List of image files
YestaskstringFixed value: /v1/wool_roll_video/wool_roll/415444
Yestask_typestringFixed value: formula
Nosync_timeoutintSynchronization timeout; default: 30

The init_images image parameter has the following structure:

RequiredParameterTypeDescription
YesurlstringImage URL or base64 data
YesprofileobjectAttribute information

The profile attribute has the following structure:

RequiredParameterTypeDescription
Yesmedia_profilesobjectImage media attributes. The source document does not define profile.version; do not add it to the request.

The media_profiles media attributes have the following structure:

RequiredParameterTypeDescription
Yesmedia_data_typestringurl indicates that the url field contains an image URL. jpg indicates that the url field contains base64-encoded JPG data. The default is url.

params is a JSON string with the following structure:

RequiredFieldTypeDescription
YesparameterobjectCore algorithm parameter object. The source document does not define any nested fields, so pass an empty object.

The source document does not define rsp_media_type or a result media type mapping. These fields are therefore not added here.

Request Example

{
  "task": "/v1/wool_roll_video/wool_roll/415444",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://wheeai.meitudata.com/static/666162c4139073547bhMUcLeee3093.jpeg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        }
      }
    }
  ],
  "params": "{\"parameter\":{}}",
  "sync_timeout": 30
}

Response Description

Note: Generated results are periodically deleted after 24 hours. Download and save them promptly.
FieldTypeDescription
request_idstringRequest identifier
trace_idstringTrace identifier
codeintBusiness status code. 0 indicates that the request was accepted successfully.
error_codeintError code; 0 on success
messagestringBusiness message
tipsanyAdditional information; may be null
dataobject/nullTask status and algorithm result; may be null when the request fails

The data field has the following structure:

FieldTypeDescription
statusintStatus code: -1, task not found; 0, task created; 1, processing; 2, failed; 9, query with the status endpoint; 10, succeeded
msgstringDescription of multimedia file attributes
resultobjectAlgorithm result
progressnumberTask progress, for example, 0.1, 0.85, or 1

The result field has the following structure:

FieldTypeDescription
idstringTask ID
urlsstring[]The source document labels this field as "image addresses." Although the API description states that it generates a video, the source document does not define a media mapping, so this field description is preserved.

Response Examples

Successful Response Example

Response Status: 200

content-type: application/json; charset=utf-8

{
  "request_id": "",
  "trace_id": "",
  "code": 0,
  "error_code": 0,
  "message": "success",
  "tips": null,
  "data": {
    "status": 10,
    "result": {
      "id": "50309bd5-a827-4125-bc96-62039c93770b",
      "urls": [
        "..."
      ]
    },
    "progress": 1
  }
}

Query-Required Response Example

When data.status is 9, use the status endpoint and the returned result.id to query the task result.

Response Status: 200

content-type: application/json; charset=utf-8

{
  "request_id": "",
  "trace_id": "",
  "code": 0,
  "error_code": 0,
  "message": "success",
  "tips": null,
  "data": {
    "status": 9,
    "result": {
      "id": "task_id"
    },
    "progress": 0
  }
}

Failed Response Example

Response Status: 400

content-type: application/json; charset=utf-8

{
  "request_id": "",
  "trace_id": "",
  "code": 20008,
  "error_code": 20008,
  "message": "UNSUITABLE_IMAGE",
  "tips": null,
  "data": {
    "status": 2,
    "result": {
      "ErrorCode": 20008,
      "ErrorMsg": "UNSUITABLE_IMAGE",
      "Data": null
    },
    "progress": 0,
    "predict_elapsed": 0,
    "create_time": 0,
    "task_id": "",
    "custom_task_id": "",
    "trace_id": "",
    "client_info": "",
    "init_images": null
  }
}

The original failure example only provides code=20008, message=UNSUITABLE_IMAGE, and data=null. To present the standardized gateway failure response, this example maps the same error code and message into data.result. Scheduling fields not provided by the source use neutral values such as 0, an empty string, or null; these values do not imply that the source provided them.

API-Specific Error Codes and Messages

ErrorCodeError MessageDescription
20001PROCESS_ERRORProcessing error
20008UNSUITABLE_IMAGEError message from the original failed request example; the source provides no further explanation

Common Error Codes and Messages

See API Error Codes.

SDK Examples

Python

import json

import requests
from sign_sdk import sign

def api_call_example():
    key = "your_api_key"
    secret = "your_api_secret"
    url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
    method = "POST"

    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    inner_params = {
        "parameter": {},
    }
    payload = {
        "task": "/v1/wool_roll_video/wool_roll/415444",
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://wheeai.meitudata.com/static/666162c4139073547bhMUcLeee3093.jpeg",
                "profile": {
                    "media_profiles": {"media_data_type": "url"},
                },
            }
        ],
        "params": json.dumps(inner_params, ensure_ascii=False),
        "sync_timeout": 30,
    }
    body = json.dumps(payload, ensure_ascii=False)

    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, method, headers, body)
    response = requests.Session().send(signed_request)
    print(f"Status: {response.status_code}")
    print(f"Response: {response.text}")

if __name__ == "__main__":
    api_call_example()

Go

package main

import (
	"fmt"
	"io"
	"net/http"

	"github.com/mtlab/api/signer"
)

func main() {
	key := "your_api_key"
	secret := "your_api_secret"
	signObj := signer.NewSigner(key, secret)

	url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
	method := http.MethodPost
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")

	body := `{
  "task": "/v1/wool_roll_video/wool_roll/415444",
  "task_type": "formula",
  "init_images": [{
    "url": "https://wheeai.meitudata.com/static/666162c4139073547bhMUcLeee3093.jpeg",
    "profile": {
      "media_profiles": {"media_data_type": "url"}
    }
  }],
  "params": "{\"parameter\":{}}",
  "sync_timeout": 30
}`

	req, err := signObj.Sign(url, method, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println("Failed to send request:", err)
		return
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Read response failed:", err)
		return
	}
	fmt.Println("Response:", resp.StatusCode, string(responseBody))
}

PHP

<?php
require 'signer.php';

$key = 'your_api_key';
$secret = 'your_api_secret';
$signer = new Signer($key, $secret);

$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$method = 'POST';
$headers = ['Content-Type' => 'application/json'];

$innerParams = json_encode([
    'parameter' => (object) [],
]);

$body = json_encode([
    'task' => '/v1/wool_roll_video/wool_roll/415444',
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://wheeai.meitudata.com/static/666162c4139073547bhMUcLeee3093.jpeg',
            'profile' => [
                'media_profiles' => ['media_data_type' => 'url'],
            ],
        ],
    ],
    'params' => $innerParams,
    'sync_timeout' => 30,
]);

$curl = $signer->sign($url, $method, $headers, $body);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ($status === 0) {
    echo 'Error: ' . curl_error($curl);
} else {
    echo "Status: {$status}\n";
    echo "Response: {$response}\n";
}
curl_close($curl);
?>

Java

package com.meitu.openai.common;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws Exception {
        Signer signer = new Signer("your_api_key", "your_api_secret");
        String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
        String method = "POST";

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");

        String body = "{\n" +
                "  \"task\": \"/v1/wool_roll_video/wool_roll/415444\",\n" +
                "  \"task_type\": \"formula\",\n" +
                "  \"init_images\": [{\n" +
                "    \"url\": \"https://wheeai.meitudata.com/static/666162c4139073547bhMUcLeee3093.jpeg\",\n" +
                "    \"profile\": {\n" +
                "      \"media_profiles\": {\"media_data_type\": \"url\"}\n" +
                "    }\n" +
                "  }],\n" +
                "  \"params\": \"{\\\"parameter\\\":{}}\",\n" +
                "  \"sync_timeout\": 30\n" +
                "}";

        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod(method);
        for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
            connection.setRequestProperty(entry.getKey(), entry.getValue());
        }
        connection.setDoOutput(true);
        connection.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8));

        int status = connection.getResponseCode();
        InputStream stream = status >= 400
                ? connection.getErrorStream()
                : connection.getInputStream();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            System.out.println("Response: " + status + " " + response);
        }
    }
}