Compose Integration

The AI components work seamlessly with the Stream Chat Android SDK.

StreamingText

You can easily integrate the message streaming view into your Compose chat UI.

One option is to use it when rendering messages:

@Composable
fun MessageItem(message: Message) {
    val isGenerating = message.extraData["generating"] == true
    val isFromAI = message.extraData["ai_generated"] == true

    if (isFromAI) {
        StreamingText(
            text = message.text,
            animate = isGenerating
        )
    } else {
        Text(text = message.text)
    }
}

You can also add thinking indicators, for example at the bottom of the message list:

@Composable
fun ChatScreen(channelId: String) {
    val chatClient = ChatClient.instance()
    val channel = chatClient.channel(channelId)

    val context = LocalContext.current
    val factory = MessagesViewModelFactory(
        context = context,
        channelId = channelId,
    )
    val viewModel = viewModel(
        modelClass = MessageListViewModel::class.java,
        factory = factory,
    )

    var assistantState by remember { mutableStateOf<String?>(null) }

    // Listen to AI typing indicator events
    LaunchedEffect(channelId) {
        channel.subscribeFor<AIIndicatorUpdatedEvent> { event ->
            assistantState = event.aiState
        }
    }

    Column {
        // Message list
        MessageList(viewModel)

        // Typing indicator overlay
        if (assistantState != null) {
            AITypingIndicator(
                label = {
                    Text(
                        when (assistantState) {
                            "AI_STATE_THINKING" -> "Thinking"
                            "AI_STATE_CHECKING_SOURCES" -> "Checking sources"
                            "AI_STATE_GENERATING" -> "Generating response"
                            else -> ""
                        }
                    )
                }
            )
        }

        // Composer
        ChatComposer(
            onSendClick = { messageData ->
                channel.sendMessage(
                    Message(
                        text = messageData.text,
                        attachments = messageData.attachments.map { uri ->
                            // Convert URI to attachment
                        }
                    )
                ).enqueue()
            },
            onStopClick = {
                channel.sendEvent(EventType.AI_TYPING_INDICATOR_STOP).enqueue()
            },
            isStreaming = assistantState == "AI_STATE_GENERATING",
        )
    }
}

For a reference implementation showing how to integrate these components with Stream Chat’s client API, please check our sample app.

© Getstream.io, Inc. All Rights Reserved.