百变发型
描述
根据指定发型编号,对输入人像图片进行发型替换,并返回处理后的图片 URL。
版本
1.0
图片要求
通过图片 URL 传入人像图片,示例使用一张图片。media_data_type 设置为 url。
调用 URL
正式环境:https://openapi.meitu.com
任务提交接口:https://openapi.meitu.com/api/v1/sdk/sync/push
任务名称(task):/v1/hairtransfer/495184
任务类型(task_type):formula调用方法
POST
Content-Type: application/json
X-Aigcp-Way: handler
权限
使用前需申请 Access Key 和 Secret Key,并按照开放平台接口签名生成请求签名。Authorization 和 X-Sdk-Date 由签名 SDK 生成。
请求参数
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | task | string | 固定 /v1/hairtransfer/495184 |
| 必选 | task_type | string | 固定 formula |
| 必选 | init_images | object[] | 输入人像图片列表 |
| 必选 | params | string | 算法参数的 JSON 字符串,内部包含 parameter 对象 |
| 可选 | sync_timeout | int | 同步等待时长,单位:秒。示例值 30;-1 表示不等待,立即返回。未获得最终结果时,使用返回的任务 ID 查询结果 |
init_images 图片参数,结构说明如下
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | url | string | 输入人像图片 URL |
| 可选 | profile | object | 图片属性信息 |
profile 图片属性,结构说明如下
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | media_profiles | object | 图片属性;传入 profile 时填写 |
| 可选 | version | string | 版本号,默认 v1 |
media_profiles 媒体属性,结构说明如下
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 可选 | media_data_type | string | 媒体数据类型,默认 url,表示使用图片 URL |
params 为 JSON 字符串,解码后的结构如下
{
"parameter": {
"rsp_media_type": "url",
"hair_type": "1"
}
}| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | parameter | object | 发型处理参数对象 |
parameter 算法参数,结构说明如下
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 可选 | rsp_media_type | string | 返回媒体类型,url 表示返回图片 URL |
| 可选 | hair_type | string | 发型编号。0 表示保持原发型;其他编号参见参考发型标识。按字符串传入,例如 "1"、"1_II" |
输入值示例
以下示例使用发型编号 "1"。替换图片 URL 后,将请求体保存为 request.json。
{
"task": "/v1/hairtransfer/495184",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/portrait.jpg",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"hair_type\":\"1\"}}",
"sync_timeout": 30
}返回值说明
成功返回值说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
request_id | string | 请求 ID |
trace_id | string | 链路追踪 ID |
code | int | 请求状态码,0 表示请求成功;任务是否完成以 data.status 为准 |
error_code | int | 业务错误码,0 表示无业务错误 |
message | string | 返回信息 |
data | object | 任务状态和处理结果 |
data 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
status | int | 任务状态,10 表示成功,2 表示失败;任务未完成时通过任务查询接口获取后续结果 |
result | object | 任务处理结果 |
progress | number | 任务进度,范围 0–1,1 表示完成 |
predict_elapsed | number | 预计处理耗时,单位:毫秒 |
create_time | int64 | 任务创建时间戳,单位:毫秒 |
task_id | string | 任务 ID,用于查询任务 |
custom_task_id | string | 自定义任务 ID |
trace_id | string | 链路追踪 ID |
client_info | string | 客户端信息 |
init_images | object[]/null | 输入图片信息 |
result 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
id | string | 任务 ID |
urls | string[] | 结果图片 URL 列表 |
images | string[] | 结果图片 URL 列表,与 urls 含义一致 |
parameters | object | 结果参数信息 |
data | object | 算法返回的详细结果 |
msg | string | 返回信息 |
msg_id | string | 消息 ID |
mtlab_res | object | 算法返回状态 |
media_info_list | object[] | 结果图片属性列表 |
result.data 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
duration | object | 各阶段耗时信息 |
error_code | int | 算法错误码,0 表示成功 |
error_msg | string | 算法返回信息 |
extra | object | 图片转换附加信息 |
media_info_list | object[] | 结果图片属性列表 |
msg_id | string | 消息 ID |
parameter | object | 算法结果参数 |
result.data.duration 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
alg_process_time | number | 算法处理耗时,单位:毫秒 |
created_timestamp | number | 任务创建时间戳,单位:秒 |
pull_timestamp | number | 资源拉取时间戳,单位:秒 |
repost_time | number | 重试耗时 |
upload_time | number | 上传耗时,单位:毫秒 |
waiting_time | number | 排队等待耗时,单位:毫秒 |
result.data.extra 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
trans_meta | object | 转换元数据 |
trans_meta.rsp_meta | object[] | 结果图片元数据列表 |
rsp_meta 数组项说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
height | number | 图片高度,单位:像素 |
width | number | 图片宽度,单位:像素 |
media_type | string | 媒体类型,例如 image |
size | number | 文件大小,单位:KB |
media_info_list 数组项说明,适用于结果中的媒体列表
| 字段 | 类型 | 参数说明 |
|---|---|---|
media_data | string | 结果图片 URL |
media_extra | object/null | 图片附加信息 |
media_profiles | object | 结果图片属性 |
media_profiles 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
media_data_size | number[] | 图片尺寸,顺序为 [高度, 宽度] |
media_data_type | string | 媒体数据类型,url 表示 URL |
result.parameters 和 result.data.parameter 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
rsp_media_type | string | 返回媒体类型 |
version | string | 算法版本号 |
result.mtlab_res 字段说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
ErrorCode | int | 算法错误码 |
ErrorMsg | string | 算法错误信息 |
error_code | int | 兼容错误码字段 |
error_msg | string | 兼容错误信息字段 |
media_info_list | object[]/null | 媒体信息列表 |
msg_id | string | 消息 ID |
parameter | object/null | 算法参数信息 |
失败返回值说明
| 字段 | 类型 | 参数说明 |
|---|---|---|
error_code | int | 错误码 |
message | string | 错误信息 |
data | string/null | 错误附加信息,可为 null |
返回值示例
请求成功返回示例
Response Status: 200
Content-Type: application/json; charset=utf-8
以下示例展示任务信息和结果图片地址,其余结果详情字段省略。
{
"request_id": "req_example",
"trace_id": "trace_example",
"code": 0,
"error_code": 0,
"message": "success",
"data": {
"status": 10,
"result": {
"id": "task_example",
"urls": [
"https://example.com/result_1.jpeg",
"https://example.com/result_2.jpeg"
],
"parameters": {
"rsp_media_type": "url",
"version": "1.0.32"
}
},
"progress": 1,
"predict_elapsed": 10000,
"create_time": 1776137629570,
"task_id": "task_example",
"custom_task_id": "",
"trace_id": "trace_example",
"client_info": "",
"init_images": null
}
}请求失败返回示例
Response Status: 400
Content-Type: application/json; charset=utf-8
{
"error_code": 20001,
"message": "PROCESS_ERROR",
"data": null
}任务查询
当 sync_timeout=-1,或提交请求尚未返回最终结果时,使用返回的 data.task_id 调用任务查询接口。
GET https://openapi.meitu.com/api/v1/sdk/status?task_id=YOUR_TASK_ID
查询请求也需使用 AK/SK 签名。查询状态为 0(已创建)或 1(处理中)时,可继续查询;10 表示成功,2 表示失败,-1 表示未找到任务。任务在 24 小时后过期,不支持查询已过期任务。
当前 API 特有的错误代码与信息
| ErrorCode 状态代码 | 错误信息 | 说明 |
|---|---|---|
| 20001 | PROCESS_ERROR | 处理失败 |
通用的错误代码与信息
详见 API 错误码。
调用示例
签名 SDK 接入文档:Go、Java、Python、JavaScript、PHP。
cURL
SDK_DATE 为签名使用的 UTC 时间,SIGNATURE 为生成的认证字符串(不含 Bearer 前缀)。两者必须对应本次请求的 request.json 和下列请求头;生成方式参见开放平台接口签名。
curl --request POST \
--url 'https://openapi.meitu.com/api/v1/sdk/sync/push' \
--header 'Host: openapi.meitu.com' \
--header 'Content-Type: application/json' \
--header 'X-Aigcp-Way: handler' \
--header "X-Sdk-Date: ${SDK_DATE}" \
--header "Authorization: Bearer ${SIGNATURE}" \
--data-binary @request.jsonPython
下载 Python SDK 1.0.2,将 sign_sdk 目录放入项目,并安装 requests。替换示例中的 AK、SK 和图片 URL 后执行。
import json
import requests
from sign_sdk import sign
access_key = "your_access_key"
secret_key = "your_secret_key"
url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
params = {
"parameter": {
"rsp_media_type": "url",
"hair_type": "1",
}
}
payload = {
"task": "/v1/hairtransfer/495184",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/portrait.jpg",
"profile": {
"media_profiles": {"media_data_type": "url"},
"version": "v1",
},
}
],
"params": json.dumps(params, separators=(",", ":")),
"sync_timeout": 30,
}
body = json.dumps(payload, separators=(",", ":"))
headers = {
"Host": "openapi.meitu.com",
"Content-Type": "application/json",
"X-Aigcp-Way": "handler",
}
signer = sign.Signer(access_key, secret_key)
request = signer.sign(url, "POST", headers, body)
with requests.Session() as session:
response = session.send(request, timeout=(10, 60))
print("Status:", response.status_code)
print("Response:", response.text)Go
下载 Go SDK 1.0.3,使用 Go 1.20 或更高版本。将以下代码保存为解压目录中的 demo.go,替换 AK、SK 和图片 URL 后执行 go run .。
package main
import (
"fmt"
"io"
"net/http"
"time"
"github.com/mtlab/api/signer"
)
func main() {
accessKey := "your_access_key"
secretKey := "your_secret_key"
endpoint := "https://openapi.meitu.com/api/v1/sdk/sync/push"
body := `{
"task": "/v1/hairtransfer/495184",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/portrait.jpg",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"hair_type\":\"1\"}}",
"sync_timeout": 30
}`
headers := make(http.Header)
headers.Set("Host", "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
headers.Set("X-Aigcp-Way", "handler")
sign := signer.NewSigner(accessKey, secretKey)
request, err := sign.Sign(endpoint, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Sign request failed:", err)
return
}
client := &http.Client{Timeout: 60 * time.Second}
response, err := client.Do(request)
if err != nil {
fmt.Println("Send request failed:", err)
return
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
fmt.Println("Read response failed:", err)
return
}
fmt.Println("Status:", response.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
下载 PHP SDK 1.0.9,将 signer.php 与示例放在同一目录,并启用 cURL 扩展。
<?php
require_once __DIR__ . '/signer.php';
$accessKey = 'your_access_key';
$secretKey = 'your_secret_key';
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$params = json_encode([
'parameter' => [
'rsp_media_type' => 'url',
'hair_type' => '1',
],
]);
$body = json_encode([
'task' => '/v1/hairtransfer/495184',
'task_type' => 'formula',
'init_images' => [
[
'url' => 'https://example.com/portrait.jpg',
'profile' => [
'media_profiles' => ['media_data_type' => 'url'],
'version' => 'v1',
],
],
],
'params' => $params,
'sync_timeout' => 30,
]);
$headers = [
'Host' => 'openapi.meitu.com',
'Content-Type' => 'application/json',
'X-Aigcp-Way' => 'handler',
];
$signer = new Signer($accessKey, $secretKey);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt_array($curl, [
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
CURLOPT_HEADER => false,
]);
$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
下载 Java SDK 1.0.3,使用 JDK 8 或更高版本。将包内 src/main/java/com/meitu/openai/common/Signer.java 加入项目,将以下示例保存为 Main.java。
import com.meitu.openai.common.Signer;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
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 {
String accessKey = "your_access_key";
String secretKey = "your_secret_key";
String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
String body = "{\n"
+ " \"task\": \"/v1/hairtransfer/495184\",\n"
+ " \"task_type\": \"formula\",\n"
+ " \"init_images\": [\n"
+ " {\n"
+ " \"url\": \"https://example.com/portrait.jpg\",\n"
+ " \"profile\": {\n"
+ " \"media_profiles\": {\n"
+ " \"media_data_type\": \"url\"\n"
+ " },\n"
+ " \"version\": \"v1\"\n"
+ " }\n"
+ " }\n"
+ " ],\n"
+ " \"params\": \"{\\\"parameter\\\":{\\\"rsp_media_type\\\":\\\"url\\\",\\\"hair_type\\\":\\\"1\\\"}}\",\n"
+ " \"sync_timeout\": 30\n"
+ "}";
Map<String, String> headers = new HashMap<>();
headers.put("Host", "openapi.meitu.com");
headers.put("Content-Type", "application/json");
headers.put("X-Aigcp-Way", "handler");
Signer signer = new Signer(accessKey, secretKey);
Map<String, String> signedHeaders = signer.sign(url, "POST", headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(10_000);
connection.setReadTimeout(60_000);
connection.setDoOutput(true);
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(bodyBytes.length);
try (OutputStream output = connection.getOutputStream()) {
output.write(bodyBytes);
}
int status = connection.getResponseCode();
InputStream input = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
System.out.println("Status: " + status);
if (input != null) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(input, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
connection.disconnect();
}
}