Updated on 2025-08-19 GMT+08:00

Third-Party LLM Callback API for Intelligent Interaction

Functions

The MetaStudio intelligent interaction service allows developers to customize the virtual human brain, that is, a third-party large language model (LLM). When a user talks with the virtual avatar, this API is called to return the answer in text.

Signature Calculation Methods

If a third-party LLM API uses the HMAC-SHA256 signature, the parameters secret and time_stamp need to be added to the URL.

Value format: secret=hmac_sha256(URI(llm_url) + timestamp, appKey)&time_stamp=hex(timestamp)

Fields:

  • llm_url: API URL of the third-party LLM called by MetaStudio
  • appKey: APPKEY information provided by the third-party LLM integrated with MetaStudio

Code example:

URI uri = URI.create(llm_url);
long currentTimeMillis = System.currentTimeMillis();
String input = uri.toString() + currentTimeMillis;
String secret = Hmacsha256.doFinal(input, appKey);
String timeStamp = Long.toHexString(currentTimeMillis);

Specifically:

String appKey = "huawei_metaStudio";
URI uri = URI.create("https://metastudio-llm/digital-human/chat");
long currentTimeMillis = 1744612873350L;
String input = uri.toString() + currentTimeMillis; // input = https://metastudio-llm/digital-human/chat1744612873350
String secret = Hmacsha256.doFinal(input, appKey); // secret = a02fc32111795dc6f760e6bd15bb0cbc9a35921dc5dc86e57eea56ae644d793e
String timeStamp = Long.toHexString(currentTimeMillis); // timeStamp = 1963307d486
// The final request is https://metastudio-llm/digital-human/chat?secret=a02fc32111795dc6f760e6bd15bb0cbc9a35921dc5dc86e57eea56ae644d793e&time_stamp=1963307d486.

URI

POST llm_url

Table 1 Query parameters

Parameter

Mandatory

Type

Description

secret

Yes

String

Signature information.

Value format: secret=hmac_sha256(URI(llm_url) + timestamp, appKey)

Fields:

  • llm_url: API URL of the third-party LLM called by MetaStudio
  • appKey: APPKEY information provided by the third-party LLM integrated with MetaStudio

time_stamp

Yes

String

Timestamp. The value is in hexadecimal format, in millisecond.

Request Parameters

Table 2 Request body parameters

Parameter

Mandatory

Type

Description

messages

Yes

Array of Message objects

Multiple rounds of Q&A.

app_id

Yes

String

Application ID of a third-party LLM.

user

Yes

String

Unique ID of a user.

session_id

Yes

String

Unique ID of the current dialog. The ID is used to make the dialog context coherent.

is_stream

No

Boolean

Whether to use streaming responses for answers. The default value is false.

Table 3 Message

Parameter

Mandatory

Type

Description

content

Yes

String

Dialog content.

The value contains 1 to 4,096 characters.

Response Parameters

Status code: 200

Table 4 Header parameters in a non-streaming response

Parameter

Type

Description

Content-Type

String

Value: application/json;charset=UTF-8

Table 5 Header parameters in a streaming response

Parameter

Type

Description

Content-Type

String

Value: text/event-stream;charset=UTF-8

See Table 6 when is_stream is set to false.

Table 6 Body parameters in a non-streaming response

Parameter

Type

Description

id

String

Unique ID of each response.

created

Integer

Time when a response is generated.

choices

Array of ChatChoice objects

List of generated text.

Table 7 ChatChoice

Parameter

Mandatory

Type

Description

message

Yes

Table 8 objects

Generated text content.

index

Yes

Integer

Index value of generated text in the list. The counting starts from 0.

Table 8 MessageItem

Parameter

Mandatory

Type

Description

content

Yes

String

Dialog content.

The value contains 1 to 4,096 characters.

See Table 6 when is_stream is set to true.

Table 9 Body parameters in a streaming response

Parameter

Type

Description

data

String

If the value of is_stream is true, messages generated by a third-party LLM are returned to MetaStudio as Server-Sent Events (SSE) streams. That is, the generated messages are sent incrementally one by one. Each data field contains a part of the generated content. After all data is returned, the response ends.

A streaming response must end with data:[DONE].

Status code: 400

Table 10 Response body parameters

Parameter

Type

Description

error_code

String

Error code.

error_msg

String

Error description.

Request Examples

A Q&A request can be sent in either of the following ways:

  • Single-round non-streaming Q&A request
    Code example:
    POST https://xxx.xxx.xxx/xxx/xxx?secret=xxxxxxxxxxxxxxxxx&time_stamp=18d0cf1d921
    
    {
        "messages": [{
            "content": "Please introduce the Yangtze River."
        }],
        "app_id": "5ca7fxxxxxxe40a0a01bcxxxxxx88307",
        "user": "f6befxxxxxx24a6dbaaxxxxxxc576475",
        "session_id": "b1cb4bxxxxxx4de793129f76xxxxxx68",
        "is_stream": false
    }
  • Multi-round streaming Q&A request
    Code example:
    POST https://xxx.xxx.xxx/xxx/xxx?secret=xxxxxxxxxxxxxxxxx&time_stamp=18d0cf1d921
    
    {
        "messages": [{
            "content": "Please introduce the Yangtze River." //Question of the first round
        }, {
            "content": "The Yangtze River is a major river in China and one of the longest rivers in the world. Originating at the Tanggula Mountains, the Yangtze River runs more than 6,300 km through 11 provinces in China before flowing into the East China Sea." //Answer of the first round
        }, {
            "content": "Please list five provinces along the Yangtze River." //Question of the second round
        }, {
            "content": "The following are the five provinces along the Yangtze River:\n\n1. Qinghai\n2. Sichuan\n3. Yunnan\n4. Hunan\n5. Jiangxi" //Answer of the second round
        }, {
            "content": "What fish are there in the Yangtze River?" //Question of the third round
        }],
        "app_id": "5ca7fxxxxxxe40a0a01bcxxxxxx88307",
        "user": "f6befxxxxxx24a6dbaaxxxxxxc576475",
        "session_id": "b1cb4bxxxxxx4de793129f76xxxxxx68",
        "is_stream": true
    }

Response Examples

Status code: 200

A Q&A request and its response must be sent in the same way.

  • Response to a single-round non-streaming Q&A
    Code example:
    {
        "id": "2f8e891225d486190c8bea91207e9aa1",
        "created": 20230512084843,
        "choices": [{
            "index": 0,
            "message": {
                "content": "The Yangtze River is a major river in China and one of the longest rivers in the world. Originating at the Tanggula Mountains, the Yangtze River runs more than 6,300 km through 11 provinces in China before flowing into the East China Sea."
            }
        }]
    }
  • Response to a multi-round streaming Q&A
    Code example:
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646748, "choices": [{"message": {"content": "The Yangtze River"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646766, "choices": [{"message": {"content": "is"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646785, "choices": [{"message": {"content": "one of the"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646822, "choices": [{"message": {"content": "longest"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646841, "choices": [{"message": {"content": "rivers"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646878, "choices": [{"message": {"content": "in China,"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646915, "choices": [{"message": {"content": "running through"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646952, "choices": [{"message": {"content": "multiple"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394646989, "choices": [{"message": {"content": "provinces."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647008, "choices": [{"message": {"content": "The river"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647026, "choices": [{"message": {"content": "boasts"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647044, "choices": [{"message": {"content": "a"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647063, "choices": [{"message": {"content": "wide"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647081, "choices": [{"message": {"content": "range of"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647100, "choices": [{"message": {"content": "fish species."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647118, "choices": [{"message": {"content": "The following"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647136, "choices": [{"message": {"content": "are"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647154, "choices": [{"message": {"content": "some"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647173, "choices": [{"message": {"content": "typical"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647191, "choices": [{"message": {"content": "fish"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647209, "choices": [{"message": {"content": "species"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647246, "choices": [{"message": {"content": "of the Yangtze River:\n"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647265, "choices": [{"message": {"content": "\n"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647302, "choices": [{"message": {"content": "1."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647321, "choices": [{"message": {"content": "**"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647357, "choices": [{"message": {"content": "Chinese sturgeon"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647394, "choices": [{"message": {"content": "**: "}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647412, "choices": [{"message": {"content": "This is"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647431, "choices": [{"message": {"content": "an"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647449, "choices": [{"message": {"content": "old"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647468, "choices": [{"message": {"content": "species"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647523, "choices": [{"message": {"content": "of"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647560, "choices": [{"message": {"content": "the family Acipenseridae,"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647579, "choices": [{"message": {"content": "and"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647597, "choices": [{"message": {"content": "is"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647616, "choices": [{"message": {"content": "also"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647635, "choices": [{"message": {"content": "one"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647653, "choices": [{"message": {"content": "of"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647672, "choices": [{"message": {"content": "the"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647690, "choices": [{"message": {"content": "oldest"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647709, "choices": [{"message": {"content": "fish species"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647728, "choices": [{"message": {"content": "in the"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647747, "choices": [{"message": {"content": "world."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647765, "choices": [{"message": {"content": "\n"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647804, "choices": [{"message": {"content": "2."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647822, "choices": [{"message": {"content": "**"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647878, "choices": [{"message": {"content": "Silverfin"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647914, "choices": [{"message": {"content": "**: "}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647932, "choices": [{"message": {"content": "also"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394647951, "choices": [{"message": {"content": "known as"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648005, "choices": [{"message": {"content": "silver carp,"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648024, "choices": [{"message": {"content": "is"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648042, "choices": [{"message": {"content": "a"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648060, "choices": [{"message": {"content": "typical"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648079, "choices": [{"message": {"content": "freshwater"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648115, "choices": [{"message": {"content": "fish"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648133, "choices": [{"message": {"content": "species"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648152, "choices": [{"message": {"content": "."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648170, "choices": [{"message": {"content": "\n"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648206, "choices": [{"message": {"content": "3."}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648225, "choices": [{"message": {"content": "**"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648316, "choices": [{"message": {"content": "Bighead carp"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648362, "choices": [{"message": {"content": "**: "}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648380, "choices": [{"message": {"content": "featuring"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648398, "choices": [{"message": {"content": "a"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648471, "choices": [{"message": {"content": "big head,"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648489, "choices": [{"message": {"content": "is"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648508, "choices": [{"message": {"content": "an"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648527, "choices": [{"message": {"content": "important"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648545, "choices": [{"message": {"content": "edible"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648564, "choices": [{"message": {"content": "fish"}}]}
    
    data:{"id": "5b7eb95f59e54981b3aa58998c888c4b", "created": 1705394648582, "choices": [{"message": {"content": "species."}}]}
    
    data:[DONE]

Status code: 400
{
  "error_code" : "xxxxxxxx",
  "error_msg" : "Invalid parameter"
}

Status Codes

Status Code

Description

200

The information is returned when the request succeeded.

400

Incorrect input parameters of the request, including the error code and its description.

Error Codes

See Error Codes.