Face Attribute Analysis V4

Description

The caller provides an image file or image URL for face detection and face attribute analysis.

Version

4.0

Media Requirements

Image formats: JPG (JPEG), PNG
Image dimensions: minimum 48 × 48 pixels, maximum 4096 × 4096 pixels
Image file size: 2 MB
Minimum face dimensions: The detectable face bounding box is a square. Its minimum side length is 1/48 of the image's shorter side and must be no less than 48 pixels. For example, for a 4096 × 3200-pixel image, the minimum face dimensions are 66 × 66 pixels.
Face count limit: Up to 10 faces

API URL

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

Method

POST

Content-Type: application/json

Authentication

Open Platform API Signature

Request Parameters

RequiredParameterTypeDescription
YesparamsstringAlgorithm parameters (JSON string)
Yesinit_imagesobject[]Media file list
YestaskstringFixed value: /v1/Face_Analysis_v4/487157
Yestask_typestringFixed value: formula
Nosync_timeoutintDefaults to 30; synchronous timeout duration

The structure of each media file parameter in init_images is described below.

RequiredParameterTypeDescription
YesurlstringImage URL or base64-encoded data
YesprofileobjectAttribute information

profile parameters

RequiredParameterTypeDescription
Yesmedia_profilesobjectMedia attribute information
YesversionstringFixed value: v1

media_profiles parameters

RequiredParameterTypeDescription
Yesmedia_data_typestringurl indicates a URL; types such as jpg indicate base64-encoded data

params inference parameters

params is a JSON string. Its parsed structure is shown below:

{
  "rsp_media_type": "url",
  "parameter": {
    "return_attributes": "src_poseestimation,emotion,poseestimation",
    "return_landmark": 1
  }
}
RequiredFieldTypeDescription
Norsp_media_typestringDefaults to url; jpg indicates base64-encoded data
YesparameterobjectCore algorithm parameter object

parameter details

RequiredParameterTypeDescription
Noreturn_attributesStringWhether to detect and return face attributes. Pass the attributes to detect as a string separated by English commas. Attribute order is unrestricted, and attributes must not contain spaces. If this field is absent or empty, no attributes are detected.
Noreturn_landmarkIntWhether to detect and return facial landmarks; defaults to 0

return_attributes details

The following attribute types are supported. Multiple values may be selected and must be separated by English commas.

AttributeDescription
genderGender
ageAge
raceRace
beautyAttractiveness score
glassesGlasses
mustacheFacial hair
emotionEmotion
eyelidEyelids
facepoints118-point facial landmarks
facepoints171171-point facial landmarks

Internal extended attributes (for specific scenarios only)

AttributeDescription
facevisibilityFace visibility
race_scoreMulti-race probabilities
face_lightFace metering value
poseestimationFace angle information
src_poseestimationOriginal face angle information

return_landmark details

ValueMeaning
0Do not return facial landmarks (default)
1Return 106 landmarks (normalized coordinates)
2Return 106 landmarks (actual pixel coordinates)
3Return 118 landmarks (normalized coordinates)
4Return 118 landmarks (actual pixel coordinates)
5Return 171 landmarks (normalized coordinates)
6Return 171 landmarks (actual pixel coordinates)

Request Example

{
  "task": "/v1/Face_Analysis_v4/487157",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://obs.mtlab.meitu.com/public/EtRGxLI8ulQ43pGhuZfym9aYUD2PUbMP/MTcyMTM2NTIwMA==/d8434efb-97c1-4b7f-7124-a04e1e80b3f0.jpeg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        },
        "version": "v1"
      }
    }
  ],
  "params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"return_attributes\":\"src_poseestimation,emotion,poseestimation\",\"return_landmark\":1}}",
  "sync_timeout": 30
}

Response Fields

Generated results are periodically deleted. Download and save them promptly.
FieldTypeDescription
request_idStringRequest ID
trace_idStringTrace ID
codeNumberHTTP-layer status code; 0 indicates success
error_codeNumberBusiness error code; 0 indicates success. See API Error Codes
messageStringResponse message; success on success
tipsanyAdditional information; may be null
dataObjectReturned business data

data fields

FieldTypeDescription
statusNumber-1: task not found; 0: created; 1: processing; 2: failed; 9: timed out—use the Query API; 10: succeeded
resultObjectTask processing result
progressNumberTask progress, ranging from 0 to 1
predict_elapsedNumberEstimated processing time in milliseconds
create_timeNumberTask creation timestamp in milliseconds
task_idStringTask ID
custom_task_idStringCustom task ID
trace_idStringTrace ID
client_infoStringClient information
init_imagesArrayInitial input media information

result fields

FieldTypeDescription
idStringUnique task identifier
urlsArrayOutput media URL list
imagesArrayOutput media list (equivalent to urls)
parametersObjectEchoed parameters
dataObjectDetailed algorithm response data
mtlab_resObjectUnderlying algorithm result
media_info_listArrayMedia information list

result.parameters fields

FieldTypeDescription
landmark_typeIntFacial landmark type
versionStringAlgorithm version

result.data fields

FieldTypeDescription
ErrorCodeNumberAlgorithm error code; 0 indicates success
ErrorMsgStringAlgorithm error message
error_codeNumberError code (compatibility field)
error_msgStringError message (compatibility field)
media_info_listArrayMedia information list
msg_idStringMessage ID
parameterObjectEchoed parameters

media_info_list fields

FieldTypeDescription
media_dataStringMedia data address
media_extraObjectExtended media information
media_profilesObjectMedia attribute information

media_extra fields

FieldTypeDescription
facesArrayList of detected faces

faces fields

FieldTypeDescription
face_rectangleObjectFace bounding-box position. All numbers are normalized values:
left is the x-coordinate of the bounding box's upper-left corner as a percentage of the image width; top is the y-coordinate as a percentage of the image height; width is the bounding-box width as a percentage of the image width; height is the bounding-box height as a percentage of the image height.
face_attributesObjectFace attribute features. See the table below for details.
face_landmarkListArray of facial landmark coordinates, expressed as normalized image-width and image-height values. For details and diagrams, see Facial Landmark Description.

Elements in face_attributes

FieldTypeDescription
genderObject"gender": {"value": 1,"confidence": 0.999} Gender analysis result. A value of 1 represents male and 0 represents female.
ageObject "age": {"value": 21,"confidence": 1} Age analysis result. The value is a non-negative integer representing the estimated age.
raceObject"race":{"value": 0,"confidence":0.89} Race analysis result. A value of 0 represents White, 1 Asian, 2 Black, 3 North Indian, 4 South Indian, and 5 Southeast Asian.
beauty_scoreObject"beauty_score":{"value": 90,"confidence":0.89} Attractiveness analysis; range: 0–100.
emotionObject"emotion":{"value": 0,"confidence":0.89} Emotion analysis result. A value of 0 represents sadness, 1 neutral, 2 smiling, 3 laughing, 4 surprise, 5 fear, 6 anger, and 7 disgust.
right_eyelidObject"right_eyelid":{"value": 0,"confidence":0.89} Right eyelid analysis result. A value of 0 represents a single eyelid, 1 a double eyelid, and 2 a tapered double eyelid.
left_eyelidObject"left_eyelid":{"value": 0,"confidence":0.89} Left eyelid analysis result. A value of 0 represents a single eyelid, 1 a double eyelid, and 2 a tapered double eyelid.
glasses_typeObject"glasses_type":{"value": 0,"confidence":0.89} Glasses type analysis result. A value of 0 represents no glasses, 1 regular glasses, and 2 sunglasses.
glasses_thickObject"glasses_thick":{"value": 0,"confidence":0.89} Frame thickness analysis result. A value of 0 represents no glasses, 1 thin frames, and 2 thick frames.
glasses_sizeObject"glasses_size":{"value": 0,"confidence":0.89} Frame size analysis result. A value of 0 represents no glasses, 1 large frames, and 2 small frames.
glasses_frameObject"glasses_frame":{"value": 0,"confidence":0.89} Full-rim, semi-rimless, or rimless glasses analysis result. A value of 0 represents no glasses, 1 rimless, 2 full-rim, and 3 semi-rimless.
glasses_shapeObject"glasses_shape":{"value": 0,"confidence":0.89} Frame shape analysis result. A value of 0 represents no glasses, 1 another shape, 2 square frames, and 3 round frames.
mustache_typeObject"mustache_type":{"value": 0,"confidence":0.89} Facial-hair type analysis result. A value of 0 represents no facial hair, 1 stubble, and 2 a beard or mustache.
mustache_lengthObject"mustache_length":{"value": 0,"confidence":0.89} Facial-hair length analysis result. A value of 0 represents no facial hair, 1 short, 2 medium, and 3 long.
mustache_shapeObject"mustache_shape":{"value": 0 ,"confidence":0.89} Facial-hair shape analysis result. A value of 0 represents no facial hair, 1 partial goatee, 2 full goatee, 3 handlebar mustache, 4 full beard, and 5 a full sideburn beard.
mustache_thickObject"mustache_thick":{"value": 0,"confidence":0.89} Facial-hair density analysis result. A value of 0 represents no facial hair, 1 sparse, and 2 dense.
raceScoreObjectFor internal use only. "raceScore": {"value": [7.757839739497285e-06, 0.9929041266441345, 2.8477548767114058e-05, 2.0735371435876004e-05, 1.716807673801668e-05, 0.007021650206297636]} Multi-race probabilities. The six values at indexes 0–5 respectively represent confidence for White, East Asian, Black, North Indian, South Indian, and Southeast Asian.
faceLightObjectFor internal use only. "faceLight": {"value": 115} Face metering value. The value is the metering reading for the face.
roll_angleObject"roll_angle": {"value": 1.1601325273513794} Face left-right rotation angle. The value is the angle in degrees.
yaw_angleObject"yaw_angle": {"value": 6.59846305847168} Face yaw angle. The value is the yaw angle in degrees.
pitch_angleObject"pitch_angle": {"value": 13.970479011535645} Face pitch angle. The value is the pitch angle in degrees.
translate_xObject"translate_x": {"value": -10.500459671020508} Face translation along the X axis. The value is the X-axis translation.
translate_yObject"translate_y": {"value": 1.797804832458496} Face translation along the Y axis. The value is the Y-axis translation.
translate_zObject"translate_z": {"value": 417.212646484375} Face translation along the Z axis. The value is the Z-axis translation.
src_roll_angleObject"src_roll_angle": {"value": 1.1601325273513794} Original face left-right rotation angle. The value is the angle in degrees.
src_yaw_angleObject"src_yaw_angle": {"value": 6.59846305847168} Original face yaw angle. The value is the yaw angle in degrees.
src_pitch_angleObject"src_pitch_angle": {"value": 13.970479011535645} Original face pitch angle. The value is the pitch angle in degrees.

Note: The Euler angles use the center as the origin, while the 3D coordinate system uses the upper-left corner as the origin.

face_landmark fields

  • A two-dimensional array in the form [x, y]
  • Coordinates are normalized values ranging from 0 to 1
  • The number of points is determined by landmark_type

Example:

[
  [0.273677, 0.342657],
  [0.274561, 0.363718]
]

face_rectangle fields

The face region bounding box uses normalized coordinates.

FieldTypeDescription
leftFloatX-coordinate of the upper-left corner of the face bounding box
topFloatY-coordinate of the upper-left corner of the face bounding box
widthFloatWidth of the face bounding box
heightFloatHeight of the face bounding box

landmark_type details

ValueMeaning
1Return 106 landmarks (normalized coordinates)
2Return 106 landmarks (actual pixel coordinates)
3Return 118 landmarks (normalized coordinates)
4Return 118 landmarks (actual pixel coordinates)
5Return 171 landmarks (normalized coordinates)
6Return 171 landmarks (actual pixel coordinates)

result error fields

FieldTypeDescription
error_codeNumberAlgorithm error code
error_msgStringAlgorithm error message

Error codes specific to this API

ErrorCodeError MessageDescription
20001PROCESS_ERRORProcessing error

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": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
      "parameters": {
        "landmark_type": 1,
        "version": "3.0.0"
      },
      "media_info_list": [
        {
          "media_data": "",
          "media_extra": {
            "faces": [
              {
                "face_attributes": {
                  "emotion": {
                    "value": 2
                  }
                },
                "face_landmark": [
                  [0.273677, 0.342657],
                  [0.274561, 0.363718]
                ],
                "face_rectangle": {
                  "height": 0.334112,
                  "left": 0.273677,
                  "top": 0.269994,
                  "width": 0.430651
                }
              }
            ]
          },
          "media_profiles": null
        }
      ]
    },
    "progress": 0,
    "predict_elapsed": 10000,
    "create_time": 1770281556447,
    "task_id": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
    "custom_task_id": "",
    "trace_id": "",
    "client_info": "",
    "init_images": null
  }
}

Query-Required Response Example

Use the Query API to retrieve the 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": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c"
    },
    "progress": 0,
    "predict_elapsed": 10000,
    "create_time": 1770281556447,
    "task_id": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
    "custom_task_id": "",
    "trace_id": "e7ba37e7-73b3-xxxx-b989-d2c1a9d1be9b",
    "client_info": "",
    "init_images": null
  }
}

Additional 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": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
      "urls": [
        ""
      ],
      "parameters": {
        "landmark_type": 1,
        "version": "3.0.0"
      },
      "data": {
        "ErrorCode": 0,
        "ErrorMsg": "",
        "error_code": 0,
        "error_msg": "",
        "media_info_list": [
          {
            "media_data": "",
            "media_extra": {
              "faces": [
                {
                  "face_attributes": {
                    "emotion": {
                      "value": 2
                    },
                    "pitch_angle": {
                      "value": 4.932263
                    },
                    "roll_angle": {
                      "value": -2.673754
                    },
                    "src_pitch_angle": {
                      "value": 0.156139
                    },
                    "src_roll_angle": {
                      "value": -0.09442
                    },
                    "src_yaw_angle": {
                      "value": 0.179733
                    },
                    "translate_x": {
                      "value": -14.378762
                    },
                    "translate_y": {
                      "value": -28.107843
                    },
                    "translate_z": {
                      "value": 450.773773
                    },
                    "yaw_angle": {
                      "value": 8.631838
                    }
                  },
                  "face_landmark": [
                    [
                      0.273677,
                      0.342657
                    ],
                    [
                      0.274561,
                      0.363718
                    ],
                    [
                      0.274855,
                      0.384612
                    ],
                    [
                      0.27542,
                      0.405405
                    ]
                  ],
                  "face_rectangle": {
                    "height": 0.334112,
                    "left": 0.273677,
                    "top": 0.269994,
                    "width": 0.430651
                  }
                }
              ]
            },
            "media_profiles": null
          }
        ],
        "msg_id": "",
        "parameter": {
          "landmark_type": 1,
          "version": "3.0.0"
        }
      },
      "images": [
        ""
      ],
      "mtlab_res": {
        "ErrorCode": 0,
        "ErrorMsg": "",
        "error_code": 0,
        "error_msg": "",
        "media_info_list": [
          {
            "media_data": "",
            "media_extra": {
              "faces": [
                {
                  "face_attributes": {
                    "emotion": {
                      "value": 2
                    },
                    "pitch_angle": {
                      "value": 4.932263
                    },
                    "roll_angle": {
                      "value": -2.673754
                    },
                    "src_pitch_angle": {
                      "value": 0.156139
                    },
                    "src_roll_angle": {
                      "value": -0.09442
                    },
                    "src_yaw_angle": {
                      "value": 0.179733
                    },
                    "translate_x": {
                      "value": -14.378762
                    },
                    "translate_y": {
                      "value": -28.107843
                    },
                    "translate_z": {
                      "value": 450.773773
                    },
                    "yaw_angle": {
                      "value": 8.631838
                    }
                  },
                  "face_landmark": [
                    [
                      0.273677,
                      0.342657
                    ],
                    [
                      0.274561,
                      0.363718
                    ]
                  ],
                  "face_rectangle": {
                    "height": 0.334112,
                    "left": 0.273677,
                    "top": 0.269994,
                    "width": 0.430651
                  }
                }
              ]
            },
            "media_profiles": null
          }
        ],
        "msg_id": "",
        "parameter": {
          "landmark_type": 1,
          "version": "3.0.0"
        }
      },
      "media_info_list": [
        {
          "media_data": "",
          "media_extra": {
            "faces": [
              {
                "face_attributes": {
                  "emotion": {
                    "value": 2
                  },
                  "pitch_angle": {
                    "value": 4.932263
                  },
                  "roll_angle": {
                    "value": -2.673754
                  },
                  "src_pitch_angle": {
                    "value": 0.156139
                  },
                  "src_roll_angle": {
                    "value": -0.09442
                  },
                  "src_yaw_angle": {
                    "value": 0.179733
                  },
                  "translate_x": {
                    "value": -14.378762
                  },
                  "translate_y": {
                    "value": -28.107843
                  },
                  "translate_z": {
                    "value": 450.773773
                  },
                  "yaw_angle": {
                    "value": 8.631838
                  }
                },
                "face_landmark": [
                  [
                    0.273677,
                    0.342657
                  ],
                  [
                    0.274561,
                    0.363718
                  ],
                  [
                    0.274855,
                    0.384612
                  ]
                ],
                "face_rectangle": {
                  "height": 0.334112,
                  "left": 0.273677,
                  "top": 0.269994,
                  "width": 0.430651
                }
              }
            ]
          },
          "media_profiles": null
        }
      ]
    },
    "progress": 0,
    "predict_elapsed": 10000,
    "create_time": 1770281556447,
    "task_id": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
    "custom_task_id": "",
    "trace_id": "",
    "client_info": "",
    "init_images": null
  }
}

Failed Response Example

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

{
  "request_id": "",
  "trace_id": "",
  "code": 0,
  "error_code": 20001,
  "message": "PROCESS_ERROR",
  "tips": null,
  "data": {
    "status": 2,
    "result": {
      "error_code": 20001,
      "error_msg": "PROCESS_ERROR"
    },
    "progress": 0,
    "predict_elapsed": 0,
    "create_time": 1770281556447,
    "task_id": "t_mt1a3i5n7b3283da1d-xxxx-4078-bfb4-14a9a0d8b23c",
    "custom_task_id": "",
    "trace_id": "",
    "client_info": "",
    "init_images": null
  }
}

General Error Codes

See API Error Codes.

Error specific to this API: 20001 PROCESS_ERROR, indicating a processing error.

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 = {
        "rsp_media_type": "url",
        "parameter": {
            "return_attributes": "src_poseestimation,emotion,poseestimation",
            "return_landmark": 1,
        },
    }
    payload = {
        "task": "/v1/Face_Analysis_v4/487157",
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://obs.mtlab.meitu.com/public/EtRGxLI8ulQ43pGhuZfym9aYUD2PUbMP/MTcyMTM2NTIwMA==/d8434efb-97c1-4b7f-7124-a04e1e80b3f0.jpeg",
                "profile": {
                    "media_profiles": {"media_data_type": "url"},
                    "version": "v1",
                },
            }
        ],
        "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/Face_Analysis_v4/487157",
  "task_type": "formula",
  "init_images": [{
    "url": "https://obs.mtlab.meitu.com/public/EtRGxLI8ulQ43pGhuZfym9aYUD2PUbMP/MTcyMTM2NTIwMA==/d8434efb-97c1-4b7f-7124-a04e1e80b3f0.jpeg",
    "profile": {
      "media_profiles": {"media_data_type": "url"},
      "version": "v1"
    }
  }],
  "params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"return_attributes\":\"src_poseestimation,emotion,poseestimation\",\"return_landmark\":1}}",
  "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([
    'rsp_media_type' => 'url',
    'parameter' => [
        'return_attributes' => 'src_poseestimation,emotion,poseestimation',
        'return_landmark' => 1,
    ],
]);

$body = json_encode([
    'task' => '/v1/Face_Analysis_v4/487157',
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://obs.mtlab.meitu.com/public/EtRGxLI8ulQ43pGhuZfym9aYUD2PUbMP/MTcyMTM2NTIwMA==/d8434efb-97c1-4b7f-7124-a04e1e80b3f0.jpeg',
            'profile' => [
                'media_profiles' => ['media_data_type' => 'url'],
                'version' => 'v1',
            ],
        ],
    ],
    '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/Face_Analysis_v4/487157\",\n" +
                "  \"task_type\": \"formula\",\n" +
                "  \"init_images\": [{\n" +
                "    \"url\": \"https://obs.mtlab.meitu.com/public/EtRGxLI8ulQ43pGhuZfym9aYUD2PUbMP/MTcyMTM2NTIwMA==/d8434efb-97c1-4b7f-7124-a04e1e80b3f0.jpeg\",\n" +
                "    \"profile\": {\n" +
                "      \"media_profiles\": {\"media_data_type\": \"url\"},\n" +
                "      \"version\": \"v1\"\n" +
                "    }\n" +
                "  }],\n" +
                "  \"params\": \"{\\\"rsp_media_type\\\":\\\"url\\\",\\\"parameter\\\":{\\\"return_attributes\\\":\\\"src_poseestimation,emotion,poseestimation\\\",\\\"return_landmark\\\":1}}\",\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);
        }
    }
}