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): formulaRequest Method
POST
Content-Type: application/json
Authorization
Request Parameters
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | params | string | Algorithm parameters as a JSON string. The source document does not define specific algorithm fields. |
| Yes | init_images | object[] | List of image files |
| Yes | task | string | Fixed value: /v1/wool_roll_video/wool_roll/415444 |
| Yes | task_type | string | Fixed value: formula |
| No | sync_timeout | int | Synchronization timeout; default: 30 |
The init_images image parameter has the following structure:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | url | string | Image URL or base64 data |
| Yes | profile | object | Attribute information |
The profile attribute has the following structure:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_profiles | object | Image 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:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_data_type | string | url 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:
| Required | Field | Type | Description |
|---|---|---|---|
| Yes | parameter | object | Core 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_typeor 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.| Field | Type | Description |
|---|---|---|
| request_id | string | Request identifier |
| trace_id | string | Trace identifier |
| code | int | Business status code. 0 indicates that the request was accepted successfully. |
| error_code | int | Error code; 0 on success |
| message | string | Business message |
| tips | any | Additional information; may be null |
| data | object/null | Task status and algorithm result; may be null when the request fails |
The data field has the following structure:
| Field | Type | Description |
|---|---|---|
| status | int | Status code: -1, task not found; 0, task created; 1, processing; 2, failed; 9, query with the status endpoint; 10, succeeded |
| msg | string | Description of multimedia file attributes |
| result | object | Algorithm result |
| progress | number | Task progress, for example, 0.1, 0.85, or 1 |
The result field has the following structure:
| Field | Type | Description |
|---|---|---|
| id | string | Task ID |
| urls | string[] | 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, anddata=null. To present the standardized gateway failure response, this example maps the same error code and message intodata.result. Scheduling fields not provided by the source use neutral values such as0, an empty string, ornull; these values do not imply that the source provided them.
API-Specific Error Codes and Messages
| ErrorCode | Error Message | Description |
|---|---|---|
| 20001 | PROCESS_ERROR | Processing error |
| 20008 | UNSUITABLE_IMAGE | Error 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);
}
}
}