云修美颜技术
该文档指引接入美图云修智能 API 服务,需先申请接口权限后方可接入使用,接口的接入通过 HTTP 异步调用的形式接入。美图云修 API 提供的服务均为异步接口,目前提供了 2 种形式来获取结果:消息通知回调、结果查询
公共参数
权限
使用前需申请 AccessKey 和 SecretKey,并按照开放平台接口签名完成请求签名。
请求头
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| Content-Type | string | 是 | 固定值:"application/json" |
请求方法
POST
接口列表
预设 ID 接入
请求地址: https://openapi.meitu.com/yunxiu_api/openapi/beauty_async
请求方法: POST
请求头:
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| Content-Type | string | 是 | 固定值:"application/json" |
请求参数(Body参数):
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| media_code | string | 是 | 预设 ID(什么是预设ID?) | MTyunxiu163aa58942 |
| media_data | string | 是 | 原图图片地址(不支持base64,只支持url) | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
| repost_url | string | 否 | 结果回调地址,接入侧提供 | https://httpbin.org/ |
请求示例:
{
"media_code": "MTyunxiu",
"media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
"repost_url": "https://httpbin.org/"
}响应参数:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | { "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a" } |
| message | string | 否 | 提示信息 | success |
| request_id | string | 是 | 请求ID | 30c2194d-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/beauty_async
请求方法: POST
请求参数(Body参数):
- media_info_list 参数结构
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| media_data | string | 是 | 原图图片地址(不支持base64,只支持url) | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
| media_extra | struct | 否 | 资源描述额外信息 | {} |
| media_profiles | struct | 是 | 图片地址的资源描述 | 固定值{"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_params | struct | 是 | 图片处理参数 | 查看下文 |
| repost_url | string | 否 | 结果回调地址,接入侧提供 | https://httpbin.org/ |
| rsp_mask_version | int | 是 | - | 固定值500 |
| preview_size | int | 是 | - | 固定值3000 |
| people_type | array | 是 | 自定义年龄性别属性的数组顺序 | 查看下文 |
| output | struct | 是 | 输出结构 | 查看下文 |
- filter 参数结构:
| 名称 | 类型 | 是否必填 | 描述 | 范围 | 示例值 |
|---|---|---|---|---|---|
| filter_id | string | 否 | 滤镜ID | ||
| filters_lut_alpha | int | 否 | 程度值 | 0~100 | 默认值50 |
| filter_is_black | int | 否 |
- blush、eyesocket等数组中对象结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| id | string | 是 | 效果名称,默认值空 | "luozhuang" |
| color | string | 是 | 颜色值,rgba格式,默认值 0;0;0;0 | "" |
| alpha | int | 是 | 效果程度,默认值 0 | 50 |
- people_type 参数结构:
该字段用来定义图片中人物性别和年龄的对应关系,目前支持设置 5 种类型的人物性别。
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| age | list | 是 | 定义该属性的年龄范围 | [50, 100] |
| gender | int | 是 | 性别:1男 0女 | |
| key | string | 是 | 性别属性 | oldman |
| name | string | 否 | 性别属性名称 | 老 |
对于参数支持性别和年龄属性的,那么他的数据结构是一个 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 参数结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| format | string | 是 | 输出格式,支持jpg和png | jpg |
| preview_size | string | 是 | 原图分割尺寸,推荐3000 | 3000 |
| qualityKey | int | 是 | 输出图质量,范围1~13,数值越大对应的画质越高;默认值12,对应画质99 | 12 |
| resize_height | int | 是 | 输出图尺寸(高),0表示原图输出,默认0,保留字段暂不支持配置 | 0 |
| resize_width | int | 是 | 输出图尺寸(宽),0表示原图输出,默认0,保留字段暂不支持配置 | 0 |
| water_mark | int | 是 | 是否水印,0无水印 1有水印 | 0 |
| file_size_limit | array | 否 | 输出图片大小范围,以示例值来说最小不超过原图的0.8,最大不超过原图的1.3 | [0.8, 1.3] |
- all_params 参数结构:
| 客户端模块 | 客户端参数名 | 算法参数 | 类型 | 是否必填 | 范围 | 示例值 |
|---|---|---|---|---|---|---|
| 脸部优化 | 祛斑祛痘_脸部 | fleck_clean_flag | array | 是 | 0、1 | 默认值 0 |
| 脸部优化 | 祛唇纹 | lip_remove_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛法令纹 | wrinkle_nasolabial_removal_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛黑头/脂肪粒 | black_head_clean_flag | array | 是 | 0、1 | 默认值 0 |
| 脸部优化 | 祛黑眼圈 | remove_pouch | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛颈纹 | wrinkle_neck_removal_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛面颊纹 | wrinkle_cheek_removal_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛双下巴(旧版) | double_chin | array | 是 | 0、1 | 默认值 0 |
| 脸部优化 | 祛双下巴(新版) | double_chin_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛抬头纹 | wrinkle_forehead_removal_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛眼周纹 | wrinkle_periorbital_removal_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛油光 | shiny_clean_alpha | array | 是 | 0~100 | 默认值 0 |
| 脸部优化 | 祛痣_脸部 | nevus_removal_flag | array | 是 | 0、1 | 默认值 0 |
| 脸型调整 | 缩头 | ai_shrink_head | array | 是 | 0~100 | 默认值 0 |
| 脸型调整 | 额头 | face_forehead | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 中庭 | middle_half_of_face | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 下庭 | bottom_half_of_face | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 人中 | philtrum_warp | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 脸宽 | narrow_face | array | 是 | 大人-200~100,儿童-100~100 | 默认值 0 |
| 脸型调整 | 脸部轮廓平滑 | facial_contour | array | 是 | 0~100 | 默认值 0 |
| 脸型调整 | 颧骨_左 | cheekbone_left | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 颧骨_右 | cheekbone_right | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 太阳穴_左 | temple_left | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 太阳穴_右 | temple_right | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 下颌_左 | mandible_left | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 下颌_右 | mandible_right | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 下巴高度 | jaw_trans | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 下巴宽度 | face_trans | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 对称液化开关(仅适用于1-2人无遮挡的半身照) | run_symmetry_list | array | 是 | 0、1 | 默认值 0 |
| 脸型调整 | 五官对称 | face_symmetry | array | 是 | 0~100 | 默认值 0 |
| 脸型调整 | 上半身对称 | body_symmetry | array | 是 | 0~100 | 默认值 0 |
| 脸型调整 | 3D塑颜-上下 | threed_up_down | array | 是 | -100~100 | 默认值 0 |
| 脸型调整 | 3D塑颜-左右 | threed_left_right | array | 是 | -100~100 | 默认值 0 |
| 滤镜 | 滤镜 | filter | struct | 是 | 查看 | |
| 肤色调整 | 智能肤色(同肤色统一互斥) | skin_tone_flag | array | 是 | 0、1 | 默认值 0 |
| 肤色调整 | 肤色统一 | body_dullness_remove_alpha | array | 是 | 0~100 | 默认值 0 |
| 肤色调整 | 明度 | skin_tone_body_luma_alpha | array | 是 | 0~100 | 默认值 100 |
| 肤色调整 | 色彩 | skin_tone_body_hue_alpha | array | 是 | 0~100 | 默认值 100 |
| 肤色调整 | 肤色选择 | skin_color_path | array | 是 | 0~4 0:原肤 1:冷调 2:粉瓷 3:暖调 4:小麦 | 默认值 0 |
| 肤色调整 | 肤色选择透明度 | skin_color_hue_skin_alpha | array | 是 | 0~100 | 默认值 0 |
| 肤色调整 | 肤色偏好 | skin_color_hue_alpha | array | 是 | -100~100 | 默认值 0 |
| 肤色调整 | 皮肤红润 | skin_red_alpha | array | 是 | 0~100 | 默认值 0 |
| 肤色调整 | 皮肤美白 | skin_white_alpha | array | 是 | 0~100 | 默认值 0 |
| 肤色调整 | 皮肤透亮 | skin_hdr_alpha | array | 是 | 0~100 | 默认值 0 |
| 皮肤磨皮 | 高低频_脸部 | smooth_face_skin_alpha | array | 是 | 0~100 | 默认值 0 |
| 皮肤磨皮 | 高低频_身体 | smooth_not_face_skin_alpha | array | 是 | 0~100 | 默认值 0 |
| 皮肤磨皮 | 中性灰_脸部 | face_balance_alpha | array | 是 | 0~100 | 默认值 0 |
| 皮肤磨皮 | 皮肤纹理_脸部 | sharpen_alpha | array | 是 | 0~100 | 默认值 0 |
| 头发调整 | 头发蓬松 | fluffy_hair | array | 是 | 0~100 | 默认值 0 |
| 头发调整 | 发色加深 | black_hair | array | 是 | 0~100 | 默认值 0 |
| 五官塑造 | 鼻子_鼻尖 | nasal_tip | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 鼻子_鼻梁 | bridge_nose | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 鼻子_鼻翼 | shrink_nose | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 鼻子_大小 | scale_nose | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 鼻子_长短 | nose_longer | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 鼻子_山根 | nasal_root | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_丰上唇 | upperlip_enhance | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_丰下唇 | lowerlip_enhance | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_大小 | mouth_trans | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_高度 | mouth_high | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_宽度 | mouth_breadth | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_上下 | high_mouth | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 嘴巴_微笑 | mouth_smile | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_上下 | eye_up_down_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_上下 | eye_up_down_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_大小 | eye_trans_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_大小 | eye_trans_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_倾斜 | eye_tilt_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_倾斜 | eye_tilt_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_眼高 | eye_height_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_眼高 | eye_height_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_眼睑 | eye_lid_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_眼睑 | eye_lid_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_眼距 | eye_distance_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_眼距 | eye_distance_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_眼宽 | eye_width_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_眼宽 | eye_width_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_左_开眼角 | inner_eye_corner_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眼睛_右_开眼角 | inner_eye_corner_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_左_倾斜 | eyebrow_tilt_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_右_倾斜 | eyebrow_tilt_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_左_上下 | eyebrow_height_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_右_上下 | eyebrow_height_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_左_间距 | eyebrow_distance_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_右_间距 | eyebrow_distance_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_左_眉峰 | eyebrow_ridge_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_右_眉峰 | eyebrow_ridge_right | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_左_粗细 | eyebrow_size_left | array | 是 | -100~100 | 默认值 0 |
| 五官塑造 | 眉毛_右_粗细 | eyebrow_size_right | array | 是 | -100~100 | 默认值 0 |
请求实例:
{
"parameter": {
"repost_url": "https://httpbin.org/",
"all_params": {
"fleck_clean_flag": [
1,
1,
1,
1,
1
],
"lip_remove_alpha": [
30,
30,
30,
30,
30
],
"wrinkle_nasolabial_removal_alpha": [
30,
30,
30,
30,
30
],
"black_head_clean_flag": [
1,
1,
1,
1,
1
],
"remove_pouch": [
30,
30,
30,
30,
30
],
"wrinkle_neck_removal_alpha": [
30,
30,
30,
30,
30
],
"wrinkle_cheek_removal_alpha": [
30,
30,
30,
30,
30
],
"double_chin": [
1,
1,
1,
1,
1
],
"double_chin_alpha": [
100,
30,
100,
100,
100
],
"wrinkle_forehead_removal_alpha": [
30,
30,
30,
30,
30
],
"wrinkle_periorbital_removal_alpha": [
30,
30,
30,
30,
30
],
"shiny_clean_alpha": [
30,
30,
30,
30,
30
],
"nevus_removal_flag": [
1,
1,
1,
1,
1
],
"ai_shrink_head": [
30,
30,
30,
30,
30
],
"face_forehead": [
30,
30,
30,
30,
30
],
"middle_half_of_face": [
20,
20,
20,
20,
20
],
"bottom_half_of_face": [
20,
20,
20,
20,
20
],
"philtrum_warp": [
20,
20,
20,
20,
20
],
"narrow_face": [
30,
30,
30,
30,
30
],
"facial_contour": [
20,
20,
20,
20,
20
],
"cheekbone_left": [
20,
20,
20,
20,
20
],
"cheekbone_right": [
20,
20,
20,
20,
20
],
"temple_left": [
20,
20,
20,
20,
20
],
"temple_right": [
20,
20,
20,
20,
20
],
"mandible_left": [
20,
20,
20,
20,
20
],
"mandible_right": [
20,
20,
20,
20,
20
],
"jaw_trans": [
30,
30,
30,
30,
30
],
"face_trans": [
30,
30,
30,
30,
30
],
"run_symmetry_list": [
0,
1,
0,
0,
0
],
"face_symmetry": [
0,
100,
0,
0,
0
],
"body_symmetry": [
0,
50,
0,
0,
0
],
"threed_up_down": [
20,
20,
20,
20,
20
],
"threed_left_right": [
20,
20,
20,
20,
20
],
"filter": {
"filter_id": "Fa0000ItjzwJwznN",
"filters_lut_alpha": 80,
"filter_is_black": 0
},
"skin_tone_flag": [
0,
0,
0,
0,
0
],
"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
],
"smooth_face_skin_alpha": [
30,
30,
30,
30,
30
],
"smooth_not_face_skin_alpha": [
20,
20,
20,
20,
20
],
"face_balance_alpha": [
30,
30,
30,
30,
30
],
"sharpen_alpha": [
30,
30,
30,
30,
30
],
"fluffy_hair": [
30,
30,
30,
30,
30
],
"black_hair": [
30,
30,
30,
30,
30
],
"nasal_tip": [
30,
30,
30,
30,
30
],
"bridge_nose": [
30,
30,
30,
30,
30
],
"shrink_nose": [
30,
30,
30,
30,
30
],
"scale_nose": [
30,
30,
30,
30,
30
],
"nose_longer": [
30,
30,
30,
30,
30
],
"nasal_root": [
30,
30,
30,
30,
30
],
"upperlip_enhance": [
30,
30,
30,
30,
30
],
"lowerlip_enhance": [
20,
20,
20,
20,
20
],
"mouth_trans": [
30,
30,
30,
30,
30
],
"mouth_high": [
30,
30,
30,
30,
30
],
"mouth_breadth": [
30,
30,
30,
30,
30
],
"high_mouth": [
30,
30,
30,
30,
30
],
"mouth_smile": [
20,
20,
20,
20,
20
],
"eye_up_down_left": [
20,
20,
20,
20,
20
],
"eye_up_down_right": [
20,
20,
20,
20,
20
],
"eye_trans_left": [
20,
20,
20,
20,
20
],
"eye_trans_right": [
20,
20,
20,
20,
20
],
"eye_tilt_left": [
30,
50,
30,
30,
30
],
"eye_tilt_right": [
30,
30,
30,
30,
30
],
"eye_height_left": [
30,
20,
30,
30,
30
],
"eye_height_right": [
30,
30,
30,
30,
30
],
"eye_lid_left": [
20,
20,
20,
20,
20
],
"eye_lid_right": [
20,
20,
20,
20,
20
],
"eye_distance_left": [
30,
40,
30,
30,
30
],
"eye_distance_right": [
30,
30,
30,
30,
30
],
"eye_width_left": [
30,
30,
30,
30,
30
],
"eye_width_right": [
30,
30,
30,
30,
30
],
"inner_eye_corner_left": [
20,
20,
20,
20,
20
],
"inner_eye_corner_right": [
20,
20,
20,
20,
20
],
"eyebrow_tilt_left": [
20,
20,
20,
20,
20
],
"eyebrow_tilt_right": [
20,
20,
20,
20,
20
],
"eyebrow_height_left": [
20,
20,
20,
20,
20
],
"eyebrow_height_right": [
20,
20,
20,
20,
20
],
"eyebrow_distance_left": [
20,
20,
20,
20,
20
],
"eyebrow_distance_right": [
20,
20,
20,
20,
20
],
"eyebrow_ridge_left": [
20,
20,
20,
20,
20
],
"eyebrow_ridge_right": [
20,
20,
20,
20,
20
],
"eyebrow_size_left": [
20,
20,
20,
20,
20
],
"eyebrow_size_right": [
20,
20,
20,
20,
20
]
},
"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参数):
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | 查看 |
| message | string | 否 | 提示信息 | success |
- data 字段结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| msg_id | string | 是 | 异步任务ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
| media_data | string | 是 | 处理好的效果图地址 | 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_id | string | 是 | 异步任务ID | 6aca960e-6669-4f39-805e-9bc69705b82d |
请求示例:
{
"msg_id": "6aca960e-6669-4f39-805e-9bc69705b82d"
}响应参数:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | 参考下文示例 |
| message | string | 否 | 提示信息 | success |
| request_id | string | 是 | 请求ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
data 字段结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| msg_id | string | 是 | 异步任务ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
| media_data | string | 是 | 处理好的效果图地址 | 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"
}错误码
| 错误码 | 错误信息 | 描述 |
|---|---|---|
| 0 | SUCCESS | 请求成功 |
| 29901 | NOT_RESULT | 图片还在处理中,结果还没出来 |
| 29902 | RECORD_NOT_FOUND | 异步任务 ID 已过期 |
| 90002 | GATEWAY_AUTHORIZED_ERROR | 接口未授权/密钥错误 |
| 11201 | UNKNOW ERROR | 用户图片地址下载失败 |
| 20001 | UNKNOW 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/beauty_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/beauty_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/beauty_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/beauty_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/beauty_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/beauty_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/beauty_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/beauty_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();
}
}
}