云修美妆技术

该文档指引接入美图云修智能 API 服务,需先申请接口权限后方可接入使用,接口的接入通过 HTTP 异步调用的形式接入。美图云修 API 提供的服务均为异步接口,目前提供了 2 种形式来获取结果:消息通知回调、结果查询

公共参数

权限

使用前需申请 AccessKey 和 SecretKey,并按照开放平台接口签名完成请求签名。

请求头

名称类型必填描述
Content-Typestring是固定值:"application/json"

请求方法

POST

接口列表

预设 ID 接入

请求地址: https://openapi.meitu.com/yunxiu_api/openapi/makeup_async

请求方法: POST

请求头:

名称类型必填描述
Content-Typestring是固定值:"application/json"

请求参数(Body参数):

名称类型是否必填描述示例值
media_codestring是预设 ID(什么是预设ID?)MTyunxiu163aa58942
media_datastring是原图图片地址(不支持base64,只支持url)https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg
repost_urlstring否结果回调地址,接入侧提供https://httpbin.org/

请求示例:

{
    "media_code": "MTyunxiu",
    "media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
    "repost_url": "https://httpbin.org/"
}

响应参数:

名称类型是否必填描述示例值
codeint是业务状态码0
datastruct是结果数据{ "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a" }
messagestring否提示信息success
request_idstring是请求ID30c2194d-049b-4f69-95f8-0e9b440df2eb

响应示例:

{
    "code": 0,
    "data": {
        "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a"
    },
    "message": "",
    "request_id": "30c2194d-049b-4f69-95f8-0e9b440df2eb"
}

原始参数接入

请求地址: https://openapi.meitu.com/yunxiu_api/openapi/makeup_async

请求方法: POST

请求参数(Body参数):

名称类型是否必填描述示例值
parameterstruct是处理参数查看
media_info_listarray是原图图片地址查看
extrastruct否其他信息{}
  • media_info_list 参数结构
名称类型是否必填描述示例值
media_datastring是原图图片地址(不支持base64,只支持url)https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg
media_extrastruct否资源描述额外信息{}
media_profilesstruct是图片地址的资源描述固定值{"media_data_type":"url","media_data_describe": "src"}
[
    {
        "media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
        "media_extra": {},
        "media_profiles": {
            "media_data_type": "url",
            "media_data_describe": "src"
        }
    }
]
  • parameter 参数结构:
名称类型是否必填描述示例值
all_paramsstruct是图片处理参数查看下文
repost_urlstring否结果回调地址,接入侧提供https://httpbin.org/
rsp_mask_versionint是-固定值500
preview_sizeint是-固定值3000
people_typearray是自定义年龄性别属性的数组顺序查看下文
outputstruct是输出结构查看下文
  • filter 参数结构:
名称类型是否必填描述范围示例值
filter_idstring否滤镜ID
filters_lut_alphaint否程度值0~100默认值50
filter_is_blackint否
  • blush、eyesocket等数组中对象结构:
名称类型是否必填描述示例值
idstring是效果名称,默认值空"luozhuang"
colorstring是颜色值,rgba格式,默认值 0;0;0;0""
alphaint是效果程度,默认值 050
  • people_type 参数结构:

该字段用来定义图片中人物性别和年龄的对应关系,目前支持设置 5 种类型的人物性别。

名称类型是否必填描述示例值
agelist是定义该属性的年龄范围[50, 100]
genderint是性别:1男 0女
keystring是性别属性oldman
namestring否性别属性名称老

对于参数支持性别和年龄属性的,那么他的数据结构是一个 array,这个 array 总共有 5 个元素,分别对应 people_type 中的 5 种性别/年龄的定义,比如参数值:

beauty_belly_alpha: [10, 20, 30, 40, 50]

然后 people_type 的定义顺序为(注:people_type数组每一个元素的结构是一个对象,这里用字符串是为了方便阅读,具体的数据结构参考推荐配置):

["man", "woman", "child", "oldwoman", "oldman"]

那么表示 beauty_belly_alpha 对应会生效为:

{
    "man": 10,
    "woman": 20,
    "child": 30,
    "oldwoman": 40,
    "oldman": 50
}

推荐配置参数:

[
    {
        "age":[
            15,
            49
        ],
        "gender":1,
        "key":"man",
        "name":"男"
    },
    {
        "age":[
            15,
            49
        ],
        "gender":0,
        "key":"woman",
        "name":"女"
    },
    {
        "age":[
            0,
            14
        ],
        "gender":0,
        "key":"child",
        "name":"儿童"
    },
    {
        "age":[
            50,
            100
        ],
        "gender":0,
        "key":"oldwoman",
        "name":"老年女"
    },
    {
        "age":[
            50,
            100
        ],
        "gender":1,
        "key":"oldman",
        "name":"老年男"
    }
]
  • output 参数结构:
名称类型是否必填描述示例值
formatstring是输出格式,支持jpg和pngjpg
preview_sizestring是原图分割尺寸,推荐30003000
qualityKeyint是输出图质量,范围1~13,数值越大对应的画质越高;默认值12,对应画质9912
resize_heightint是输出图尺寸(高),0表示原图输出,默认0,保留字段暂不支持配置0
resize_widthint是输出图尺寸(宽),0表示原图输出,默认0,保留字段暂不支持配置0
water_markint是是否水印,0无水印 1有水印0
file_size_limitarray否输出图片大小范围,以示例值来说最小不超过原图的0.8,最大不超过原图的1.3[0.8, 1.3]
  • all_params 参数结构:
客户端模块客户端参数名算法参数类型是否必填范围示例值
妆容调整唇妆增强lipstick_deepenarray是0~100默认值 0
妆容调整高光立体highlight_alphaarray是0~100默认值 0
妆容调整脸颊加深facial_deepenarray是0~100默认值 0
妆容调整亮眼bright_eyearray是0~100默认值 0
妆容调整眉毛增强eyebrow_deepenarray是0~100默认值 0
妆容调整眼妆增强eyeshadow_deepenarray是0~100默认值 0
妆容调整阴影立体shadow_lightarray是0~100默认值 0
妆容调整腮红blusharray是查看
妆容调整卧蚕eyesocketarray是查看
妆容调整睫毛eyelasharray是查看
妆容调整眼影eyeshadowarray是查看
妆容调整唇彩moutharray是查看
妆容调整眉毛eyebrowarray是查看
妆容调整美瞳eyearray是查看
妆容调整修容featurearray是查看
头发调整头发蓬松fluffy_hairarray是0~100默认值 0
头发调整发色加深black_hairarray是0~100默认值 0
肤色调整肤色统一body_dullness_remove_alphaarray是0~100默认值 0
肤色调整明度skin_tone_body_luma_alphaarray是0~100默认值 100
肤色调整色彩skin_tone_body_hue_alphaarray是0~100默认值 100
肤色调整肤色选择skin_color_patharray是0~4
0:原肤
1:冷调
2:粉瓷
3:暖调
4:小麦
默认值 0
肤色调整肤色选择透明度skin_color_hue_skin_alphaarray是0~100默认值 0
肤色调整肤色偏好skin_color_hue_alphaarray是-100~100默认值 0
肤色调整皮肤红润skin_red_alphaarray是0~100默认值 0
肤色调整皮肤美白skin_white_alphaarray是0~100默认值 0
肤色调整皮肤透亮skin_hdr_alphaarray是0~100默认值 0

请求实例:

{
    "parameter": {
        "repost_url": "https://httpbin.org/",
        "all_params": {
            "lipstick_deepen": [
                30,
                30,
                30,
                30,
                30
            ],
            "highlight_alpha": [
                30,
                30,
                30,
                30,
                30
            ],
            "facial_deepen": [
                30,
                30,
                30,
                30,
                30
            ],
            "eyebrow_deepen": [
                30,
                30,
                30,
                30,
                30
            ],
            "eyeshadow_deepen": [
                30,
                30,
                30,
                30,
                30
            ],
            "bright_eye": [
                30,
                30,
                30,
                30,
                30
            ],
            "shadow_light": [
                30,
                30,
                30,
                30,
                30
            ],
            "eyebrow": [
                {
                    "id": "jianmei",
                    "color": "0;0;0;255",
                    "alpha": 50
                },
                {
                    "id": "jianmei",
                    "color": "0;0;0;255",
                    "alpha": 50
                },
                {
                    "id": "jianmei",
                    "color": "0;0;0;255",
                    "alpha": 50
                },
                {
                    "id": "jianmei",
                    "color": "0;0;0;255",
                    "alpha": 50
                },
                {
                    "id": "jianmei",
                    "color": "0;0;0;255",
                    "alpha": 50
                }
            ],
            "eyeshadow": [
                {
                    "id": "diaoxi",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "diaoxi",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "diaoxi",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "diaoxi",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "diaoxi",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "eye": [
                {
                    "id": "qiaokeli",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "qiaokeli",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "qiaokeli",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "qiaokeli",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "qiaokeli",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "eyesocket": [
                {
                    "id": "ziran",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "ziran",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "ziran",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "ziran",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "ziran",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "eyelash": [
                {
                    "id": "eyelash02",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "eyelash02",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "eyelash02",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "eyelash02",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "eyelash02",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "feature": [
                {
                    "id": "Vlian",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "Vlian",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "Vlian",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "Vlian",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "Vlian",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "blush": [
                {
                    "id": "blush02",
                    "color": "255;116;178;255",
                    "alpha": 50
                },
                {
                    "id": "blush02",
                    "color": "255;116;178;255",
                    "alpha": 50
                },
                {
                    "id": "blush02",
                    "color": "255;116;178;255",
                    "alpha": 50
                },
                {
                    "id": "blush02",
                    "color": "255;116;178;255",
                    "alpha": 50
                },
                {
                    "id": "blush02",
                    "color": "255;116;178;255",
                    "alpha": 50
                }
            ],
            "mouth": [
                {
                    "id": "luozhuang",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "luozhuang",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "luozhuang",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "luozhuang",
                    "color": "0;0;0;0",
                    "alpha": 50
                },
                {
                    "id": "luozhuang",
                    "color": "0;0;0;0",
                    "alpha": 50
                }
            ],
            "body_dullness_remove_alpha": [
                30,
                30,
                30,
                30,
                30
            ],
            "skin_tone_body_luma_alpha": [
                100,
                100,
                100,
                100,
                100
            ],
            "skin_tone_body_hue_alpha": [
                100,
                100,
                100,
                100,
                100
            ],
            "skin_color_path": [
                2,
                2,
                2,
                2,
                2
            ],
            "skin_color_hue_skin_alpha": [
                50,
                50,
                50,
                50,
                50
            ],
            "skin_color_hue_alpha": [
                20,
                20,
                20,
                20,
                20
            ],
            "skin_red_alpha": [
                30,
                30,
                30,
                30,
                30
            ],
            "skin_white_alpha": [
                30,
                30,
                30,
                30,
                30
            ],
            "skin_hdr_alpha": [
                30,
                30,
                30,
                30,
                30
            ],
            "fluffy_hair": [
                30,
                30,
                30,
                30,
                30
            ],
            "black_hair": [
                30,
                30,
                30,
                30,
                30
            ]
        },
        "preview_size": 3000,
        "req_mask_version": 0,
        "people_type": [
            {
                "key": "man",
                "gender": 1,
                "name": "男",
                "age": [
                    15,
                    49
                ]
            },
            {
                "key": "woman",
                "gender": 0,
                "name": "女",
                "age": [
                    15,
                    49
                ]
            },
            {
                "key": "child",
                "gender": 0,
                "name": "儿童",
                "age": [
                    0,
                    14
                ]
            },
            {
                "key": "oldwoman",
                "gender": 0,
                "name": "老",
                "age": [
                    50,
                    100
                ]
            },
            {
                "key": "oldman",
                "gender": 1,
                "name": "老",
                "age": [
                    50,
                    100
                ]
            }
        ],
        "output": {
            "file_prefix": "",
            "file_start_no": 0,
            "format": "jpg",
            "preview_size": 3000,
            "quality": 0,
            "qualityKey": 12,
            "resize_height": 0,
            "resize_width": 0,
            "water_mark": 0,
            "file_size_limit": [
                0,
                0
            ]
        }
    },
    "media_info_list": [
        {
            "media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
            "media_extra": {},
            "media_profiles": {
                "media_data_type": "url",
                "media_data_describe": "src"
            }
        }
    ]
}

结果查询

消息通知回调

当异步的任务处理完成后,会通过业务侧请求中的 repost_url 参数来回调通知。业务侧在处理完成后,需响应一个状态码为 200 的响应,响应体不做要求。

注意1:回调请求只会回调一次,业务方需做好服务保障,如没有接收到回调请求,可以通过主动查询来获取结果。

注意2: 同样的通知可能会多次回调给业务方,业务方的系统必须能够正确处理重复的通知。

注意3:处理回调的时候切记要判断回调内容是否正确后,再进行后续的业务逻辑处理,避免损失。

**通知地址:**业务方提供的 repost_url 参数

通知请求方法: POST

**请求头:**Content-Type:application/json

请求参数(Body参数):

名称类型是否必填描述示例值
codeint是业务状态码0
datastruct是结果数据查看
messagestring否提示信息success
  • data 字段结构:
名称类型是否必填描述示例值
msg_idstring是异步任务ID838b1d4a-ba79-44bd-b496-8a5a3b14097e
media_datastring是处理好的效果图地址https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg

请求示例:

{
    "code": 0,
    "data": {
        "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a",
        "media_data": "https://obs-open-platform-photo.obs.cn-north-4.myhuaweicloud.com/mtopen/KxZo7A5mPWTP3FVhVThFu9VlA0s6p59c/MTY5MzE5MTYwMA==/c69a44d6-bace-446e-51e1-2dcd91a606ed.jpeg"
    },
    "message": "success",
    "request_id": "838b1d4a-ba79-44bd-b496-8a5a3b14097e"
}

轮训请求查询

注意:异步任务的结果只保存 12 个小时,请及时查询并转存效果图图片,过期后该异步任务 ID 将无法查询到结果。请求之后切记要解析响应的 Body 来做结果判断。

请求地址: https://openapi.meitu.com/yunxiu_api/openapi/query

请求方法: POST

请求参数(Body参数):

名称类型是否必填描述示例值
msg_idstring是异步任务ID6aca960e-6669-4f39-805e-9bc69705b82d

请求示例:

{
    "msg_id": "6aca960e-6669-4f39-805e-9bc69705b82d"
}

响应参数:

名称类型是否必填描述示例值
codeint是业务状态码0
datastruct是结果数据参考下文示例
messagestring否提示信息success
request_idstring是请求ID838b1d4a-ba79-44bd-b496-8a5a3b14097e

data 字段结构:

名称类型是否必填描述示例值
msg_idstring是异步任务ID838b1d4a-ba79-44bd-b496-8a5a3b14097e
media_datastring是处理好的效果图地址https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg

响应示例:

{
    "code": 0,
    "data": {
        "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a",
        "media_data": "https://obs-open-platform-photo.obs.cn-north-4.myhuaweicloud.com/mtopen/KxZo7A5mPWTP3FVhVThFu9VlA0s6p59c/MTY5MzE5MTYwMA==/c69a44d6-bace-446e-51e1-2dcd91a606ed.jpeg"
    },
    "message": "success",
    "request_id": "838b1d4a-ba79-44bd-b496-8a5a3b14097e"
}

错误码

错误码错误信息描述
0SUCCESS请求成功
29901NOT_RESULT图片还在处理中,结果还没出来
29902RECORD_NOT_FOUND异步任务 ID 已过期
90002GATEWAY_AUTHORIZED_ERROR接口未授权/密钥错误
11201UNKNOW ERROR用户图片地址下载失败
20001UNKNOW ERROR图片处理失败

SDK 调用示例

安装对应语言的签名 SDK。Python 还需安装 requests,PHP 需将 signer.php 放在示例同目录,Java 文件名为 Main.java。

填入 AK、SK、预设 ID 和图片地址即可提交任务。查询时使用提交返回的 data.msg_id。

Python

import json
import requests
from sign_sdk import sign
def api_call_example():
    key = "your_access_key"
    secret = "your_secret_key"
    url = "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async"
    method = "POST"
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    payload = {"media_code": "YOUR_PRESET_ID", "media_data": "https://example.com/portrait.jpg"}
    body = json.dumps(payload, ensure_ascii=False)
    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, method, headers, body)
    with requests.Session() as session:
        response = session.send(signed_request, timeout=60)
        print("Status:", response.status_code)
        print("Response:", response.text)
if __name__ == "__main__":
    api_call_example()

Go

package main

import (
	"fmt"
	"github.com/mtlab/api/signer"
	"io"
	"net/http"
	"time"
)

func main() {
	key := "your_access_key"
	secret := "your_secret_key"
	signObj := signer.NewSigner(key, secret)
	url := "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async"
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")
	body := `{"media_code":"YOUR_PRESET_ID","media_data":"https://example.com/portrait.jpg"}`
	req, err := signObj.Sign(url, http.MethodPost, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.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("Failed to read response:", err)
		return
	}
	fmt.Println("Status:", resp.StatusCode)
	fmt.Println("Response:", string(responseBody))
}

PHP

<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/makeup_async';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];
$payload = ['media_code' => 'YOUR_PRESET_ID', 'media_data' => 'https://example.com/portrait.jpg'];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
    echo 'Error: ' . curl_error($curl);
} else {
    echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
    echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);

Java

import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
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_access_key", "your_secret_key");
        String url = "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async";
        String method = "POST";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");
        String body = "{\"media_code\": \"YOUR_PRESET_ID\", \"media_data\": \"https://example.com/portrait.jpg\"}";
        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
                connection.setRequestProperty(header.getKey(), header.getValue());
            }
            connection.setDoOutput(true);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(body.getBytes(StandardCharsets.UTF_8));
            }
            int status = connection.getResponseCode();
            InputStream stream = status >= 400
                    ? connection.getErrorStream()
                    : connection.getInputStream();
            System.out.println("Status: " + status);
            if (stream != null) {
                try (InputStream input = stream;
                     ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = input.read(buffer)) != -1) {
                        output.write(buffer, 0, length);
                    }
                    System.out.println("Response: " + output.toString("UTF-8"));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}

原始参数提交示例

将上文的完整原始请求体保存为 params.json,替换图片地址和处理参数。

Python

import json
import requests
from sign_sdk import sign
def api_call_example():
    key = "your_access_key"
    secret = "your_secret_key"
    url = "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async"
    method = "POST"
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    with open("params.json", encoding="utf-8") as source:
        body = source.read()
    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, method, headers, body)
    with requests.Session() as session:
        response = session.send(signed_request, timeout=60)
        print("Status:", response.status_code)
        print("Response:", response.text)
if __name__ == "__main__":
    api_call_example()

Go

package main

import (
	"fmt"
	"github.com/mtlab/api/signer"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	key := "your_access_key"
	secret := "your_secret_key"
	signObj := signer.NewSigner(key, secret)
	url := "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async"
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")
	data, err := os.ReadFile("params.json")
	if err != nil { panic(err) }
	body := string(data)
	req, err := signObj.Sign(url, http.MethodPost, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.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("Failed to read response:", err)
		return
	}
	fmt.Println("Status:", resp.StatusCode)
	fmt.Println("Response:", string(responseBody))
}

PHP

<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/makeup_async';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];
$body = file_get_contents(__DIR__ . '/params.json');
if ($body === false) { throw new RuntimeException('Cannot read params.json'); }
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
    echo 'Error: ' . curl_error($curl);
} else {
    echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
    echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);

Java

import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
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_access_key", "your_secret_key");
        String url = "https://openapi.meitu.com/yunxiu_api/openapi/makeup_async";
        String method = "POST";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");
        String body = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get("params.json")), StandardCharsets.UTF_8);
        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
                connection.setRequestProperty(header.getKey(), header.getValue());
            }
            connection.setDoOutput(true);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(body.getBytes(StandardCharsets.UTF_8));
            }
            int status = connection.getResponseCode();
            InputStream stream = status >= 400
                    ? connection.getErrorStream()
                    : connection.getInputStream();
            System.out.println("Status: " + status);
            if (stream != null) {
                try (InputStream input = stream;
                     ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = input.read(buffer)) != -1) {
                        output.write(buffer, 0, length);
                    }
                    System.out.println("Response: " + output.toString("UTF-8"));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}

查询结果(Query)

将提交响应中的 data.msg_id 填入以下示例的 YOUR_MSG_ID,签名后发送 POST 请求查询结果。

Python

import json
import requests
from sign_sdk import sign
def api_call_example():
    key = "your_access_key"
    secret = "your_secret_key"
    url = "https://openapi.meitu.com/yunxiu_api/openapi/query"
    method = "POST"
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    payload = {"msg_id": "YOUR_MSG_ID"}
    body = json.dumps(payload, ensure_ascii=False)
    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, method, headers, body)
    with requests.Session() as session:
        response = session.send(signed_request, timeout=60)
        print("Status:", response.status_code)
        print("Response:", response.text)
if __name__ == "__main__":
    api_call_example()

Go

package main

import (
	"fmt"
	"github.com/mtlab/api/signer"
	"io"
	"net/http"
	"time"
)

func main() {
	key := "your_access_key"
	secret := "your_secret_key"
	signObj := signer.NewSigner(key, secret)
	url := "https://openapi.meitu.com/yunxiu_api/openapi/query"
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")
	body := `{"msg_id":"YOUR_MSG_ID"}`
	req, err := signObj.Sign(url, http.MethodPost, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.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("Failed to read response:", err)
		return
	}
	fmt.Println("Status:", resp.StatusCode)
	fmt.Println("Response:", string(responseBody))
}

PHP

<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/query';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];
$payload = ['msg_id' => 'YOUR_MSG_ID'];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
    echo 'Error: ' . curl_error($curl);
} else {
    echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
    echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);

Java

import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
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_access_key", "your_secret_key");
        String url = "https://openapi.meitu.com/yunxiu_api/openapi/query";
        String method = "POST";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");
        String body = "{\"msg_id\":\"YOUR_MSG_ID\"}";
        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
                connection.setRequestProperty(header.getKey(), header.getValue());
            }
            connection.setDoOutput(true);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(body.getBytes(StandardCharsets.UTF_8));
            }
            int status = connection.getResponseCode();
            InputStream stream = status >= 400
                    ? connection.getErrorStream()
                    : connection.getInputStream();
            System.out.println("Status: " + status);
            if (stream != null) {
                try (InputStream input = stream;
                     ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = input.read(buffer)) != -1) {
                        output.write(buffer, 0, length);
                    }
                    System.out.println("Response: " + output.toString("UTF-8"));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}