Mobile Android Lite SDK

更新时间:
复制 MD 格式

This topic describes how to use the real-time multi-modal interactive Mobile Android Lite SDK provided by the Alibaba Cloud Model Studio Large Language Model (LLM) service. It covers SDK download and installation, key interfaces, and code examples.

The MultiModalDialog SDK, provided by the Alibaba Cloud Tongyi team, supports end-to-end multi-modal real-time audio and video interaction. You can use the SDK to integrate with the Qwen Large Language Model (LLM) and various backend agents to enable capabilities such as voice conversation, weather, music, and news. It also supports LLM conversation capabilities for video and images.

Multi-modal Real-time Interactive Service Architecture

Multimodal Real-time Interaction Service Architecture Diagram

Prerequisites

  • Enable an Alibaba Cloud Model Studio real-time multimodal interaction application to get your workspace ID, app ID, and API key.

SDK Integration

Interactive Data Link Description

The multi-modal conversation Android Lite SDK only supports the WebSocket data link for server-side interaction and AudioOnly audio mode for conversations.

  • For audio interaction, use a WebSocket connection because it offers faster connection speeds and lower performance requirements.

    • WebSocket Data Link Audio Format Description.

      • Uplink supports PCM and Opus audio formats for speech recognition.

      • Downlink supports PCM and MP3 audio streams.

Interactive Mode Description

The SDK supports three interactive modes: Push2Talk, Tap2Talk, and Duplex (full-duplex).

  • Push2Talk: Press and hold to speak. Release to end recording.

  • Tap2Talk: Tap to start speaking. The system automatically detects when the user finishes speaking.

  • Duplex: This mode provides full-duplex interaction. After the connection starts, you can speak at any time and interrupt speech.

    Note: Full-duplex interaction requires the client to integrate an Acoustic Echo Cancellation (AEC) algorithm. The Lite SDK does not provide this algorithm module. You must integrate the Acoustic Echo Cancellation algorithm module yourself or use the full-featured Mobile Android SDK for Alibaba Cloud Model Studio multi-modal conversations.

Invocation Description

The SDK and its invocation demo are described below.

  • You can download the SDK and demo dashscope-lite-android-1.0.2.zip and configure the necessary environment and dependencies.

  • Then, import the example code from the compressed package and integrate the SDK by following the invocation process.

SDK Reference

You can import dependency libraries.

  • app/src/main/libs

    • dashscope-multimodal-dialog-lite-1.*.aar // Alibaba Cloud multi-modal interactive Lite SDK

  • Other dependencies imported by the demo application are listed below.

    For more information, see app/build.gradle.

    implementation 'com.alibaba:fastjson:1.1.76.android'
    implementation 'org.java-websocket:Java-WebSocket:1.5.7'

Key Parameters

Parameter Name

Required

Value

Description

url

Yes

String

The server-side address for the request.

api_key

Yes

String

Alibaba Cloud Model Studio service registration API Key. Create an API key on the Model Studio platform. For security on the mobile client, you can also integrate a short-term token on the server-side and issue it to the client.

workspace_id

Yes

String

The workspace ID in the Model Studio console.

app_id

Yes

String

The application ID you created in the console.

Demo Overview

  • EntranceActivity: This is the entry page. You can modify information such as `url`, `api_key`, and `app_id`.

    • On this page, you can select conversation modes such as Tap2Talk or Push2Talk.

  • MultimodalDialogActivity: This is the conversation interaction implementation class.

    • The demo page references `TYAudioRecorder` as the audio input. You must replace it with your own implementation.

    • The demo page uses `AudioPlayer` as the audio playback output. You can choose to use your own implementation class.

    • In audio interaction mode, the demo supports the Visual Question Answering (VQA) (image-to-text) feature. Say "take a photo to identify xxx" to trigger the service to issue a photo-taking intent.

      • You can take a photo locally and upload it to OSS (or generate a public link using other content services) to trigger recognition and conversation for a single image.

      • You can also directly upload the image's Base64 encoding to request the service or the conversation result of the image.

Interface Design

MultimodalDialog Conversation Entry Class
  1. MultiModalDialog

    You can initialize the conversation class by passing in necessary global parameters.

    /**
     * Initializes     
     * @param context: Context
     * @param url: Server address
     * @param workspaceId: Workspace ID
     * @param appId: Application ID
     * @param dialogMode: Conversation mode
     * */
        fun MultiModalDialog(
            context: Context,
            url: String?,
            workspaceId: String?,
            appId: String?,
            dialogMode: DialogMode?
        )
  2. createConversation

    You can create a session.

    /**
     * After successful initialization, start the conversation flow.
     * @param params Initialization parameters
     * @param chatCallback Main callback. All messages, except those during initialization, are passed to the upper layer through this callback.
     */
     fun createConversation(@NonNull MultiModalRequestParam params,chatCallback: IConversationCallback)
  3. start

    You can start a conversation.

    /**
     * Connects and starts a conversation.
     * @param apiKey: Model Studio service API key. A short-term API key is recommended.
     * @param dialogId: Conversation ID (optional). Pass a value to inherit previous conversation history.
     */
     fun start(String apiKey, String dialogId)
  4. stop

    You can end a conversation.

    /**
     * Disconnects and ends a conversation.
     */
    fun stop()
  5. destroy

    /**
     * Destroys the instance.
     */
    fun destroy()
  6. interrupt

    You can interrupt interaction.

    /**
     * Interrupts AI speech.
     */
    fun interrupt()
  7. startSpeech

    You can notify the server to start uploading audio. Note that you can only call this method when in the Listening state and only in Push2Talk mode.

    /**
     * Notifies the server to start uploading audio. Note that you can only call this method when in the Listening state.
     * Call this method only in Push2Talk mode.
     */
    fun startSpeech()
  8. sendAudioData

    You can notify the server to upload audio.

    /**
     * Notifies the server to upload audio.
     * @param audioData Audio frame data
     */
    fun sendAudioData(byte[] data)
  9. stopSpeech

    You can notify the server to stop uploading audio. Call this method only in Push2Talk mode.

    /**
     * Notifies the server to stop uploading audio. Call this method only in Push2Talk mode.
     * Push2Talk user finishes speaking.
     */
    fun stopSpeech()
  10. requestToRespond

    You can request the server to answer a specific question or play Text-to-Speech (TTS).

    /**
     * Requests the server to answer a specific question or play Text-to-Speech (TTS).
     * @param type: "transcript" means converting text directly to speech; "prompt" means sending text to the Large Language Model (LLM) for a response.
     * @param text: Corresponding text
     * @param params: Additional parameters
     */
    fun requestToRespond(type: String, text: String, params: MultiModalRequestParam)
  11. Other Interfaces.

    /**
     * Sends speech response ended.
     */
    fun sendResponseEnded()
        
    /**
     * Sends speech response started.
     */
    fun sendResponseStarted()
        
Key Parameter Enumerations
Parameter

Value

Description

DialogMode

TAP2TALK

Manually start, automatically end.

PUSH2TALK

Manually start, manually end.

DUPLEX

Full-duplex interaction.

MultiModalRequestParam Client-Cloud Interaction Parameter Details

Primary Parameter

Secondary Parameter

Tertiary Parameter

Quaternary Parameter

Type

Required

Description

input

workspace_id

string

Yes

The user's workspace ID.

app_id

string

Yes

The application ID created by the customer in the console. Determine which conversation system to use based on the value pattern.

dialog_id

string

No

Conversation ID. If provided, continue the existing conversation.

parameters

upstream

type

string

Yes

Uplink type:

AudioOnly for voice calls only

AudioAndVideo for video upload

mode

string

No

The mode used by the client. Options:

  • push2talk

  • tap2talk

  • duplex

Default is tap2talk

audio_format

string

No

Audio format. Supports PCM and Opus. Default is PCM.

downstream

voice

string

No

The timbre of the synthesized speech.

sample_rate

int

No

The sample rate of the synthesized speech (unit: Hz). Default sample rate is 24000 Hz.

intermediate_text

string

No

Controls which intermediate texts are returned to the user:

transcript returns the user's speech recognition result.

dialog returns intermediate responses.

You can set multiple, comma-separated values. The default value is transcript.

audio_format

string

No

Audio format. Supports PCM and MP3. Default is PCM.

client_info

user_id

string

Yes

The end user ID, used for user-related processing.

device

uuid

string

No

The globally unique ID of the client. Generate it yourself and pass it to the SDK.

network

ip

string

No

The public network IP address of the caller.

location

latitude

string

No

Caller Dimensions

longitude

string

No

The longitude information of the caller.

city_name

string

No.

Caller's city

biz_params

user_defined_params

object

No

Other parameters to pass through to the agent.

user_defined_tokens

object

No

Authentication information required by the agent to pass through.

tool_prompts

object

No

The prompt required by the agent to pass through.

user_query_params

object

No

Custom parameters for user requests to pass through.

user_prompt_params

object

No

Custom parameters for user prompts to pass through.

IConversationCallback (Callback Interface)
/**
  * Authentication passed, WebSocket connection established.
  */
fun onConnected()

/**
  * Conversation established, start conversation flow.
  */
fun onStarted(dialogId: String)

/**
   * State switch.
   * Includes DIALOG_IDLE, DIALOG_LISTENING, DIALOG_RESPONDING, DIALOG_THINKING.
   */
fun onConvStateChangedCallback(state: State.DialogState)

/**
   * Timeout exceeding the user's valid input timeout. Upon receiving this event, restart or end the conversation.
   * @param timeout Timeout duration
   */
fun onSpeechTimeout(timeout: Long)

/**
   * Exception information during the conversation.
   * @param errorInfo Exception information
   */
fun onErrorReceived(errorCode: Int, errorMessage: String)

/**
   * Callback for synthesized TTS audio.
   * @param bytes Audio data
   */
fun onSynthesizedSpeech(bytes: ByteArray)

/**
   * Conversation ended.
   */
fun onStopped()

/**
   * User started speaking detected.
   */
fun onSpeechStarted()

/**
   * User finished speaking detected.
   */
fun onSpeechEnded()

/**
   * Interrupt request accepted.
   */
fun onRequestAccepted()

/**
   * Cloud starts sending TTS response.
   */
fun onRespondingStarted()

/**
   * Cloud finishes sending TTS response.
   */
fun onRespondingEnded(output: Map<String, Any>)

/**
   * Speech recognition content.
   */
fun onSpeechContent(output: Map<String, Any>)

/**
   * Conversation response content.
   */
fun onRespondingContent(output: Map<String, Any>)

/**
   * WebSocket connection closed.
   */
fun onClosed(closeCode: Int, reason: String)

Important Callback Method Descriptions
  • onSpeechContent(output: Map<String, Any>)

    This provides speech recognition content.

    SpeechContent - Response

    Primary Parameter

    Secondary Parameter

    Tertiary Parameter

    Type

    Required

    Description

    output

    event

    string

    Yes

    Event name: SpeechContent

    dialog_id

    string

    Yes

    Conversation ID

    text

    string

    Yes

    The text recognized from the user's speech, streamed as full output.

    finished

    bool

    Yes

    Indicates whether the output has finished.

    {
        "header": {
            "request_id": "9B32878******************3D053",
            "service_id": "368208df",
            "status_code": 200,
            "status_name": "Success",
            "status_message": "Success.",
            "attributes":{
              "user_id":"1234557879x"
            }
        },
        "payload": {
            "output":{
              "event": "SpeechContent",
              "dialog_id": "b39398c9dd8147********35cdea81f7",
              "text": "one two three",
              "finished": false
            },
            "usage":{
              "invoke":10,
              "model_x":10
            }
        }
    }
  • onRespondingContent(output: Map<String, Any>)

    This provides text returned by the Large Language Model (LLM).

    Primary Parameter

    Secondary Parameter

    Tertiary Parameter

    Type

    Required

    Description

    output

    finished

    bool

    Yes

    Indicates whether the output has finished.

    dialog_id

    string

    Yes

    Conversation ID

    event

    string

    Yes

    Message type

    text

    string

    No

    The text result returned by the LLM.

    spoken

    string

    No

    The text of the content to be played, returned by the LLM. This may differ from the `text` field.

    extra_info

    object

    No

    Other extension information. Currently supports:

    commands: command string

    agent_info: agent information

    tool_calls: information returned by the plugin

    dialog_debug: conversation debug information

    timestamps: timestamps of each node in the data link

    Example:

    {
        "header": {
            "event": "result-generated",
            "task_id": "9B32878******************3D053"
        },
        "payload": {
            "output": {
                "event": "RequestAccepted",
                "dialog_id": "b39398c9dd8147********35cdea81f7",
                "text": "You entered the number sequence \"12345\". If you have questions about these numbers or need me to use them for a task, provide more details and I will do my best to help.",
                "spoken": "You entered the number sequence \"12345\". If you have questions about these numbers or need me to use them for a task, provide more details and I will do my best to help.",
                "finished": true,
                "extra_info": {
                    "commands": "[{\"name\":\"VOLUME_SET\",\"params\":[{\"name\":\"series\",\"normValue\":\"70\",\"value\":\"70\"}]}]",
                    "tool_result": [
                        {
                            "id": "",
                            "type": "function",
                            "function": {
                                "name": "function_name",
                                "arguments": "{\"id\": \"123\", \"name\": \"test\"}",
                                "outputs": "Function call result",
                                "status": {
                                    "code": 200,
                                    "message": "Success."
                                }
                            }
                        }
                    ]
                }
            },
            "usage": {
                "invoke": 10,
                "model_x": 10
            }
        }
    }
    
    

Error Handling

onErrorReceived - Response

This section lists error codes and their corresponding error messages.

Error Code

Error Name

Description

40000000

ClientError

Client-side error.

40000001

InvalidParameter

Invalid parameter, such as a missing parameter.

40000002

DirectiveNotSupported

Unsupported instruction, such as an incorrect instruction name.

40000003

MessageInvalid

Invalid instruction, such as an incorrect instruction format.

40000004

ConnectError

Connection error, such as client or digital human RTC exit.

40010000

AccessDenied

Access denied.

40010001

UNAUTHORIZED

Unauthorized.

40020000

DataInspectionFailed

Input or output triggers Green Net.

50000000

InternalError

Internal server-side error. Contact server-side personnel for troubleshooting.

50000001

UnknownError

Unknown internal server-side error. Contact server-side personnel for troubleshooting.

50010000

InternalAsrError

Internal ASR error.

50020000

InternalLLMError

Internal LLM error.

50030000

InternalSynthesizerError

Internal TTS error.

Invocation Timing

Half-duplex Interaction

image

More SDK Interface Usage Instructions

VQA Interaction

VQA enables multimodal interaction using images and voice by sending images during a conversation.

The core process involves a voice or text request for a photo-taking intent, which triggers the "visual_qa" photo-taking instruction.

After the client receives a photo-taking instruction through the callback function onRespondingContent, you can send an image link or Base64 data. The system supports images smaller than 180 KB.

  • You can handle the "visual_qa" command and upload the photo.

@Override
public void onRespondingContent(@NotNull final Map<String, ?> output) {
  Log.i(TAG,"onRespondingContent output:{"+output+"}");     
  if (output.containsKey("extra_info")) {
    JSONObject extraInfo = (JSONObject) output.get("extra_info");
    try {
        if (extraInfo.containsKey("commands") && extraInfo.getString("commands") != null && extraInfo.getString("commands").contains("visual_qa")) {
        // Contains VQA instruction, simple implementation here.
            uploadVQAImg();
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }
}

// Upload photo.
private void uploadVQAImg(){
    MultiModalRequestParam updateParams = null;
    JSONObject imageObject = new JSONObject();
    try{
        imageObject.put("type", "url");
        imageObject.put("value", vqaImgLink);
        List<JSONObject> images = new ArrayList<>();
        images.add(imageObject);
            updateParams= MultiModalRequestParam
                .builder()
                .images(images)
                    .build();
    }catch (JSONException e){
        e.printStackTrace();
    }
    Log.i(TAG, "uploadVQAImg: " + JSON.toJSONString(updateParams));
    multimodalDialog.requestToRespond("prompt", "",updateParams);
}

Request LiveAI Through WebSocket Data Link

LiveAI (video call) is the official agent provided by Alibaba Cloud Model Studio multimodal interaction. Using the Android Lite SDK, you can also invoke the video call feature by recording video frames yourself within the WebSocket data link.

Note: When invoking LiveAI via WebSocket, sending images only supports Base64 encoding. Each image must be smaller than 180 KB.

  • LiveAI Invocation Timing

Screenshot

  • Key Code Example

You can refer to the following invocation process to implement LiveAI invocation using the WebSocket protocol.

// 1. Set the interaction type to AudioAndVideo.
MultiModalRequestParam.UpStream.builder().mode(this.dialogMode.getValue()).type("AudioAndVideo").build();

// 2. Send a voicechat_video_channel request after establishing the connection.
private void sendVideoChatCommand(){
    try {
        MultiModalRequestParam updateParams = MultiModalRequestParam.builder().build();
        org.json.JSONObject videoObj = new org.json.JSONObject();
        videoObj.put("action", "connect");
        videoObj.put("type", "voicechat_video_channel");

        List<org.json.JSONObject> videos = new ArrayList<>();
        videos.add(videoObj);

        updateParams.setBizParams(MultiModalRequestParam.BizParams.builder()
                .videos(videos).build());

        multimodalDialog.requestToRespond("prompt", "", updateParams);

    } catch (org.json.JSONException e) {
        Log.e(TAG, "Failed to start video mode", e);
    }
}

// 3. Submit one video frame image data every 500 ms. Note that the image size must be less than 180 KB.
/**
 * Demonstrates implementing LiveAI in a WebSocket data link.
 * Starts a video frame stream, sending one image frame every 500 ms.
 */
private void startVideoFrameStreaming() {
    Thread videoStreamingThread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                while (isVideoChatting && !Thread.currentThread().isInterrupted()) {
                    Thread.sleep(500);

                    MultiModalRequestParam updateParams = null;
                    try {

                        updateParams = MultiModalRequestParam
                                .builder()
                                .images(MultimodalDialogActivity.this.getImageList())
                                .build();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    multimodalDialog.updateInfo(updateParams);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
        }
    });

    videoStreamingThread.setDaemon(true);
    videoStreamingThread.setName("LiveAI-VideoStreaming");
    videoStreamingThread.start();

}

/**
 * Builds images list request.
 * */
private List getImageList() {
    AssetManager assetManager = getAssets();
    org.json.JSONObject imageObject = new org.json.JSONObject();
    List<org.json.JSONObject> images = new ArrayList<>();
    try{

        imageObject.put("type", "base64");
        imageObject.put("value", getImageBase64(assetManager.open("jpeg-bridge.jpg")));

        images.add(imageObject);

    }catch (Exception e){
        e.printStackTrace();
    }
    return images;
}

private String getImageBase64(InputStream file) { // Images smaller than 200 KB.
    try {

        byte[] bytes = new byte[file.available()];
        file.read(bytes);
        return Base64.encodeToString(bytes, Base64.NO_WRAP); // Use the NO_WRAP parameter to avoid line breaks.
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

Text-to-Speech (TTS) Synthesis

The SDK supports requesting the server to synthesize audio directly from text.

You can send a requestToRespond request when the client is in the Listening state.

If the current state is not Listening, first call the interrupt interface to interrupt the current broadcast.

multimodalDialog.requestToRespond("transcript","Happiness is a skill. It is the inner peace you feel after letting go of excessive external desires.",null);

Custom Prompt Variables and Value Passing

  • You can configure custom variables in the [Prompt] project in the console.

As shown in the following example, a user_name field is defined to represent the user's nickname. The user_name variable is inserted into the prompt as a placeholder `${user_name}`.

image.png

  • You can set variables in the code.

For example, set "user_name" = "Rice".

// Set user_prompt_params in biz_params when building the request parameters.
HashMap<String, String> userPromptParams = new HashMap<>();
userPromptParams.put("user_name", "Alice");
        MultiModalRequestParam.BizParams bizParams = MultiModalRequestParam.BizParams
                .builder()
                .userPromptParams(userPromptParams)
                .build();
  • Request a response.

image.png