Getting started

更新时间:
复制 MD 格式

Important
  • This document applies only to the "Chinese mainland (Beijing)" region. You must use an API key from this region.

  • To use the portrait photo generation API, you must first request a trial and wait for approval. Otherwise, API calls will return an error status code.

Wanxiang

Note

Supported realm/task: AIGC

Portrait Photo 2.0 supports two modes: the LoRA training mode for character likeness and the TrainFree mode.

1) LoRA training mode for character likeness: In this mode, you use a pre-trained character likeness LoRA. You can then use the portrait photo generation model to create high-fidelity photos of the character. This mode supports various preset styles, such as ID photos, business portraits, retro, and summer sports. It also lets you upload custom style templates to generate personalized portrait photos.

2) TrainFree mode [Recommended]: In this mode, you upload a set of user photos (including at least one full-face, single-person photo) and a custom style template. The portrait photo generation model then instantly creates portrait photos without any training. This mode only supports generating photos using custom style templates.

LoRA training mode for character likeness:

  • Flowchart for the LoRA training mode:

image

The following images show examples of the API's features:

  • Input image

640.png

  • Generated result (Business portrait)

image.png

  • Preset style template

image.png

  • Custom template:

  • Input image

image.png

  • Custom template

image.jpeg

  • Generated result

image.jpeg

TrainFree mode for character likeness:

  • Flowchart for the TrainFree mode:

image

The TrainFree mode uses powerful, built-in pre-trained foundation models for portrait photos. This allows the diffusion model to generate images instantly without training. A series of post-processing steps are also applied to ensure the final photo balances similarity, realism, and aesthetic quality. This method quickly produces highly personalized, high-quality, and diverse portrait photos.

The following images show examples of the API's features:

  • Input image

image.jpeg

  • Custom template

image.jpeg

  • Generated result

image.jpeg

Getting started

Prerequisites

Function introduction

Workflow

  1. Activate Alibaba Cloud Model Studio and obtain an API key. For more information, see Obtain an API key and API host.

  2. Click Request a trial to request access to the FaceChain portrait photo generation feature, and wait for approval.

  3. (Optional) Call the face detection API to check the quality of user-uploaded images. You can use this as a preliminary check in your product to prompt users to replace low-quality images. For more information, see Face Detection API details.

  4. Package the image files, then upload and manage them. For more information, see Alibaba Cloud Model Studio File Management API.

  5. Call the character likeness training API to train a character likeness model and obtain the model ID. For more information, see Character Likeness Training API details.

  6. Using the trained custom model ID, call the portrait photo generation API. Select a target style template, send the request, and retrieve the generated photos. For more information, see Portrait Photo Generation API details.

Sample code

Note

The following code shows how to use the native FaceChain API to train a character likeness model and use it to generate portrait photos. Before you run the code:

  • Replace YOUR_DASHSCOPE_API_KEY in the example with your API key.

  • Install the required dependencies.

  • Follow the instructions in the code comments to replace the file paths.

If you do not have suitable photos, you can download our samples: sample1, sample2, and sample3.

Dependencies and code

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>the-latest-version2</version>
</dependency>

package com.alibaba.dashscope.demo;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class FacechainDemo {
    private static final String API_KEY = "YOUR_DASHSCOPE_API_KEY";

    private static final String REQUEST_FORMAT = "{\n"
        + "    \"model\": \"facechain-generation\",\n"
        + "    \"input\": {\n"
        + "        \"description\": \"sample\"\n"
        + "    },\n"
        + "    \"parameters\": {\n"
        + "        \"style\": \"f_business_male\",\n"
        + "        \"size\": \"768*1024\",\n"
        + "        \"n\": 4\n"
        + "    },\n"
        + "    \"resources\": [\n"
        + "        {\n"
        + "            \"resource_id\": \"%s\",\n"
        + "            \"resource_type\": \"facelora\"\n"
        + "        }\n"
        + "    ]\n"
        + "}";

    public static void main(String[] args) throws Exception {
        List<String> sourceFileLocalPaths = new ArrayList<>();
        // This example shows how to package two local photos into a local ZIP file.
        sourceFileLocalPaths.add("Replace this with the local path of your image file, for example, /home/admin/sample/sample1.jpeg");
        sourceFileLocalPaths.add("Replace this with the local path of your image file, for example, /home/admin/sample/sample2.jpeg");
        String targetZipFileLocalPath = "Replace this with the desired local path for the output ZIP package, for example, /home/admin/sample/sample.zip";
        // Package the files.
        zipFiles(sourceFileLocalPaths, targetZipFileLocalPath);
        // Upload the file to the DashScope platform.
        JSONObject uploadResponse = uploadFile(targetZipFileLocalPath);
        // Get the file_id generated after the file is uploaded.
        String fileId = uploadResponse.getJSONObject("data").getJSONArray("uploaded_files").getJSONObject(0).getString(
            "file_id");
        // Start the training job.
        JSONObject finetuneRequest = new JSONObject();
        // Static field.
        finetuneRequest.put("model", "facechain-finetune");
        JSONArray fileIds = new JSONArray();
        fileIds.add(fileId);
        finetuneRequest.put("training_file_ids", fileIds);
        JSONObject createFinetuneResponse = sendPostRequest("https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/fine-tunes",
            finetuneRequest.toJSONString());
        // Get the job ID of the created training job.
        String jobId = createFinetuneResponse.getJSONObject("output").getString("job_id");
        // Poll the job status until it succeeds.
        String queryJobUrl = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/fine-tunes/" + jobId;
        String finetunedOutput = null;
        do {
            JSONObject jobQueryResponse = sendGetRequest(queryJobUrl);
            String jobStatus = jobQueryResponse.getJSONObject("output").getString("status");
            if ("SUCCEEDED".equals(jobStatus)) {
                finetunedOutput = jobQueryResponse.getJSONObject("output").getString("finetuned_output");
            } else if ("FAILED".equals(jobStatus)) {
                throw new Exception("the job is failed");
            } else {
                System.out.println("the job " + jobId + " is now " + jobStatus);
                Thread.sleep(10 * 1000);
            }
        } while (Objects.isNull(finetunedOutput));
        // finetuned_output is the resourceId.
        System.out.println("Got the FaceChain resourceId: " + finetunedOutput);
        // Use the finetuned_output from training as a resource to call the inference service. Because inference takes a long time, this step creates an asynchronous task.
        String genPotraitRequestString = String.format(REQUEST_FORMAT, finetunedOutput);
        String genPotraitUrl = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/album/gen_potrait";
        JSONObject genPotraitTaskResponse = sendPostRequest(genPotraitUrl, genPotraitRequestString);
        // Get the ID of the inference task.
        String taskId = genPotraitTaskResponse.getJSONObject("output").getString("task_id");
        // Poll for the inference result.
        String taskQueryUrl = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/tasks/" + taskId;
        JSONArray resultImageUrls = null;
        do {
            JSONObject taskQueryResponse = sendGetRequest(taskQueryUrl);
            String jobStatus = taskQueryResponse.getJSONObject("output").getString("task_status");
            if ("SUCCEEDED".equals(jobStatus)) {
                resultImageUrls = taskQueryResponse.getJSONObject("output").getJSONArray("results");
            } else if ("FAILED".equals(jobStatus)) {
                throw new Exception("the task is failed");
            } else {
                System.out.println("the task " + taskId + " is now " + jobStatus);
                Thread.sleep(10 * 1000);
            }
        } while (Objects.isNull(resultImageUrls));
        // Get the synthesized result.
        System.out.println("The image URLs are: " + resultImageUrls.toJSONString());
    }

    private static void zipFiles(List<String> sourceFileLocalPaths, String targetZipFileLocalPath) {
        try {
            FileOutputStream fos = new FileOutputStream(targetZipFileLocalPath);
            ZipOutputStream zos = new ZipOutputStream(fos);
            byte[] buffer = new byte[1024];

            for (String sourceFile : sourceFileLocalPaths) {
                File file = new File(sourceFile);
                FileInputStream fis = new FileInputStream(file);
                zos.putNextEntry(new ZipEntry(file.getName()));

                int length;
                while ((length = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, length);
                }

                fis.close();
                zos.closeEntry();
            }

            zos.close();
            System.out.println("Files compressed successfully!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static JSONObject uploadFile(String fileToUpload) {
        StringBuilder responseBuilder = new StringBuilder();
        try {
            URL url = new URL("https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/files");
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            // Set the request header.
            conn.setRequestProperty("Authorization", API_KEY);
            conn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=---------------------------1234567890");
            // Create a file stream.
            File file = new File(fileToUpload);
            FileInputStream fis = new FileInputStream(file);
            // Get the output stream.
            OutputStream os = conn.getOutputStream();
            // Write the request body.
            os.write(("-----------------------------1234567890\r\n" +
                "Content-Disposition: form-data; name=\"files\"; filename=\"" + file.getName() + "\"\r\n" +
                "Content-Type: application/octet-stream\r\n" +
                "\r\n").getBytes());

            // Write the file content.
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }

            // Write the end flag for the request.
            os.write(("\r\n-----------------------------1234567890--\r\n").getBytes());

            // Close the streams.
            fis.close();
            os.flush();
            os.close();

            // Get the response code.
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                System.out.println("File upload succeeded");
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            } else {
                System.out.println("File upload failed with response code: " + responseCode);
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            }
            System.out.println("File upload finished. Response: " + responseBuilder.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSONObject.parseObject(responseBuilder.toString());
    }

    public static JSONObject sendPostRequest(String url, String jsonBody) {
        StringBuilder responseBuilder = new StringBuilder();
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)requestUrl.openConnection();
            conn.setRequestMethod("POST");

            // Set the request header.
            conn.setRequestProperty("Authorization", API_KEY);
            conn.setRequestProperty("X-DashScope-Async", "enable"); // This header is effective only when calling the portrait photo API.
            conn.setRequestProperty("Content-Type", "application/json");

            // Set the request body.
            conn.setDoOutput(true);
            DataOutputStream os = new DataOutputStream(conn.getOutputStream());
            os.writeBytes(jsonBody);
            os.flush();
            os.close();

            // Get the response code.
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            } else {
                System.out.println("HTTP POST request failed with response code: " + responseCode);
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("POST request response is: " + responseBuilder.toString());
        return JSONObject.parseObject(responseBuilder.toString());
    }

    public static JSONObject sendGetRequest(String url) {
        StringBuilder responseBuilder = new StringBuilder();
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)requestUrl.openConnection();
            conn.setRequestMethod("GET");
            // Set the request header.
            conn.setRequestProperty("Authorization", API_KEY);
            conn.setRequestProperty("Content-Type", "application/json");
            // Get the response code.
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            } else {
                System.out.println("HTTP GET request failed with response code: " + responseCode);
                // Read the response body.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    responseBuilder.append(line);
                }
                br.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("GET request response is: " + responseBuilder.toString());
        return JSONObject.parseObject(responseBuilder.toString());
    }
}

Learn more

For details about how to call the FaceChain portrait photo generation APIs, see Face Detection API details, Character Likeness Training API details, and Portrait Photo Generation API details.