百变发型

描述

根据指定发型编号,对输入人像图片进行发型替换,并返回处理后的图片 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,并按照开放平台接口签名生成请求签名。AuthorizationX-Sdk-Date 由签名 SDK 生成。

请求参数

是否必选参数名类型参数说明
必选taskstring固定 /v1/hairtransfer/495184
必选task_typestring固定 formula
必选init_imagesobject[]输入人像图片列表
必选paramsstring算法参数的 JSON 字符串,内部包含 parameter 对象
可选sync_timeoutint同步等待时长,单位:秒。示例值 30-1 表示不等待,立即返回。未获得最终结果时,使用返回的任务 ID 查询结果

init_images 图片参数,结构说明如下

是否必选参数名类型参数说明
必选urlstring输入人像图片 URL
可选profileobject图片属性信息

profile 图片属性,结构说明如下

是否必选参数名类型参数说明
必选media_profilesobject图片属性;传入 profile 时填写
可选versionstring版本号,默认 v1

media_profiles 媒体属性,结构说明如下

是否必选参数名类型参数说明
可选media_data_typestring媒体数据类型,默认 url,表示使用图片 URL

params 为 JSON 字符串,解码后的结构如下

{
  "parameter": {
    "rsp_media_type": "url",
    "hair_type": "1"
  }
}
是否必选参数名类型参数说明
必选parameterobject发型处理参数对象

parameter 算法参数,结构说明如下

是否必选参数名类型参数说明
可选rsp_media_typestring返回媒体类型,url 表示返回图片 URL
可选hair_typestring发型编号。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_idstring请求 ID
trace_idstring链路追踪 ID
codeint请求状态码,0 表示请求成功;任务是否完成以 data.status 为准
error_codeint业务错误码,0 表示无业务错误
messagestring返回信息
dataobject任务状态和处理结果

data 字段说明

字段类型参数说明
statusint任务状态,10 表示成功,2 表示失败;任务未完成时通过任务查询接口获取后续结果
resultobject任务处理结果
progressnumber任务进度,范围 0–11 表示完成
predict_elapsednumber预计处理耗时,单位:毫秒
create_timeint64任务创建时间戳,单位:毫秒
task_idstring任务 ID,用于查询任务
custom_task_idstring自定义任务 ID
trace_idstring链路追踪 ID
client_infostring客户端信息
init_imagesobject[]/null输入图片信息

result 字段说明

字段类型参数说明
idstring任务 ID
urlsstring[]结果图片 URL 列表
imagesstring[]结果图片 URL 列表,与 urls 含义一致
parametersobject结果参数信息
dataobject算法返回的详细结果
msgstring返回信息
msg_idstring消息 ID
mtlab_resobject算法返回状态
media_info_listobject[]结果图片属性列表

result.data 字段说明

字段类型参数说明
durationobject各阶段耗时信息
error_codeint算法错误码,0 表示成功
error_msgstring算法返回信息
extraobject图片转换附加信息
media_info_listobject[]结果图片属性列表
msg_idstring消息 ID
parameterobject算法结果参数

result.data.duration 字段说明

字段类型参数说明
alg_process_timenumber算法处理耗时,单位:毫秒
created_timestampnumber任务创建时间戳,单位:秒
pull_timestampnumber资源拉取时间戳,单位:秒
repost_timenumber重试耗时
upload_timenumber上传耗时,单位:毫秒
waiting_timenumber排队等待耗时,单位:毫秒

result.data.extra 字段说明

字段类型参数说明
trans_metaobject转换元数据
trans_meta.rsp_metaobject[]结果图片元数据列表

rsp_meta 数组项说明

字段类型参数说明
heightnumber图片高度,单位:像素
widthnumber图片宽度,单位:像素
media_typestring媒体类型,例如 image
sizenumber文件大小,单位:KB

media_info_list 数组项说明,适用于结果中的媒体列表

字段类型参数说明
media_datastring结果图片 URL
media_extraobject/null图片附加信息
media_profilesobject结果图片属性

media_profiles 字段说明

字段类型参数说明
media_data_sizenumber[]图片尺寸,顺序为 [高度, 宽度]
media_data_typestring媒体数据类型,url 表示 URL

result.parameters 和 result.data.parameter 字段说明

字段类型参数说明
rsp_media_typestring返回媒体类型
versionstring算法版本号

result.mtlab_res 字段说明

字段类型参数说明
ErrorCodeint算法错误码
ErrorMsgstring算法错误信息
error_codeint兼容错误码字段
error_msgstring兼容错误信息字段
media_info_listobject[]/null媒体信息列表
msg_idstring消息 ID
parameterobject/null算法参数信息

失败返回值说明

字段类型参数说明
error_codeint错误码
messagestring错误信息
datastring/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 状态代码错误信息说明
20001PROCESS_ERROR处理失败

通用的错误代码与信息

详见 API 错误码

调用示例

签名 SDK 接入文档:GoJavaPythonJavaScriptPHP

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.json

Python

下载 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();
    }
}