---
title: "AI Assistant (Multiple Documents, Compose)"
canonical_url: "https://www.nutrient.io/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin.md"
last_updated: "2026-05-15T19:10:04.916Z"
description: "AI-powered document chat across multiple documents using a Compose HorizontalPager. Requires the AI Assistant demo server running locally."
---

# AI Assistant (Multiple Documents, Compose)

AI-powered document chat across multiple documents using a Compose HorizontalPager. Requires the AI Assistant demo server running locally.

[Get Started](https://www.nutrient.io/sdk/android/getting-started.md)

[All Samples](https://www.nutrient.io/guides/android/samples.md)

[Download](https://www.nutrient.io/guides/android/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```kotlin

/*
 *   Copyright © 2025-2026 PSPDFKit GmbH. All rights reserved.
 *
 *   The PSPDFKit Sample applications are licensed with a modified BSD license.
 *   Please see License for details. This notice may not be removed from this file.
 */

package com.pspdfkit.catalog.examples.kotlin

import android.content.Context
import android.content.Intent
import android.graphics.RectF
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.pspdfkit.ai.createAiAssistant
import com.pspdfkit.ai.showAiAssistant
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.catalog.SdkExample.Companion.WELCOME_DOC
import com.pspdfkit.catalog.examples.kotlin.AiAssistantComposeActivity.Companion.PREFERENCES_NAME
import com.pspdfkit.catalog.examples.kotlin.AiAssistantComposeActivity.Companion.PREF_AI_IP_ADDRESS
import com.pspdfkit.catalog.ui.theming.CatalogTheme
import com.pspdfkit.catalog.utils.JwtGenerator
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.configuration.page.PageScrollDirection
import com.pspdfkit.document.providers.AssetDataProvider
import com.pspdfkit.document.providers.getDataProviderFromDocumentSource
import com.pspdfkit.jetpack.compose.interactors.DefaultListeners
import com.pspdfkit.jetpack.compose.interactors.DocumentState
import com.pspdfkit.jetpack.compose.interactors.getDefaultDocumentManager
import com.pspdfkit.jetpack.compose.interactors.rememberDocumentState
import com.pspdfkit.jetpack.compose.views.DocumentView
import com.pspdfkit.ui.DocumentDescriptor
import io.nutrient.domain.ai.AiAssistant
import io.nutrient.domain.ai.AiAssistantProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

/**
 * An example that demonstrates how to implement AI Assistant with multiple documents for the DocumentView in a Compose way.
 */
class AiAssistantMultiDocComposeExample(context: Context) :
    SdkExample(
        context,
        R.string.jetpackAiAssistantMultiDocExampleTitle,
        R.string.jetpackAiAssistantMultiDocExampleDescription,
    ) {
    override val launchRequirements = setOf(SdkExample.LaunchRequirement.AI_ASSISTANT_SERVER)

    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        val intent = Intent(context, AiAssistantMultiDocComposeActivity::class.java)
        context.startActivity(intent)
    }
}

class AiAssistantMultiDocComposeActivity :
    AppCompatActivity(),
    AiAssistantProvider {
    val assetFiles = listOf(WELCOME_DOC, "Scientific-paper.pdf", "Teacher.pdf", "The-Cosmic-Context-for-Life.pdf")
    val documentDescriptors = assetFiles.map { DocumentDescriptor.fromDataProviders(listOf(AssetDataProvider(it)), listOf(), listOf()) }
    private lateinit var activityConfiguration: PdfActivityConfiguration
    private val sessionId = AiAssistantMultiDocComposeActivity::class.java.simpleName
    private var ipAddressValue: String? = null
    var documentStateMap = mutableMapOf<Int, DocumentState>()

    private val _currentDocumentIndex = MutableStateFlow(0)
    val currentDocumentIndex: StateFlow<Int> = _currentDocumentIndex.asStateFlow()

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)

        val preferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE)
        ipAddressValue = preferences.getString(PREF_AI_IP_ADDRESS, "")?: ""

        setContent {
            var toolbarVisibility by remember { mutableStateOf(true) }
            activityConfiguration =
                PdfActivityConfiguration.Builder(LocalContext.current).setAiAssistantEnabled(true).defaultToolbarEnabled(false).scrollDirection(PageScrollDirection.VERTICAL).theme(R.style.PSPDFCatalog_AIAssistantDialog).themeDark(R.style.PSPDFCatalog_AIAssistantDialog_Dark).build()

            CatalogTheme {
                val currentIndex by currentDocumentIndex.collectAsState()

                Box(
                    modifier =
                    Modifier.fillMaxSize().navigationBarsPadding(),
                ) {
                    val pagerState = rememberPagerState(currentIndex) { documentDescriptors.size }
                    LaunchedEffect(currentIndex) {
                        pagerState.animateScrollToPage(currentIndex)
                    }
                    HorizontalPager(
                        state = pagerState,
                        userScrollEnabled = false,
                        beyondViewportPageCount = documentDescriptors.size,
                        modifier =
                        Modifier.fillMaxSize(),
                    ) { page ->
                        if (page < documentDescriptors.size) {
                            key(page) {
                                val dataProvider =
                                    remember(page) {
                                        documentDescriptors[page].documentSource.getDataProviderFromDocumentSource()
                                    }
                                // Create or retrieve the DocumentState for the current page.
                                val documentState =
                                    documentStateMap[page]?: rememberDocumentState(dataProvider, activityConfiguration).also {
                                            documentStateMap.put(page, it)
                                        }
                                Box(modifier = Modifier.fillMaxSize()) {
                                    DocumentView(
                                        modifier = Modifier.fillMaxSize(),
                                        documentState = documentState,
                                        documentManager =
                                        getDefaultDocumentManager(
                                            uiListener =
                                            DefaultListeners.uiListeners(
                                                onImmersiveModeEnabled = { toolbarVisibility =!it },
                                            ),
                                        ),
                                    )
                                }
                            }
                        }
                    }

                    CustomToolbar(
                        onClick = {
                            showAiAssistant(this@AiAssistantMultiDocComposeActivity)
                        },
                        toolbarVisibility = toolbarVisibility,
                        documentDescriptors = documentDescriptors,
                        currentIndex,
                    ) {
                        _currentDocumentIndex.value = it
                    }
                }
            }
        }
    }

    var assistant: AiAssistant? = null

    override fun getAiAssistant(): AiAssistant = assistant?: run {
        createAiAssistant(
            context = this@AiAssistantMultiDocComposeActivity,
            documentsDescriptors = documentDescriptors,
            serverUrl = "http://$ipAddressValue:4000",
            sessionId = sessionId,
            jwtToken = { documentIds ->
                JwtGenerator.generateJwtToken(
                    this@AiAssistantMultiDocComposeActivity,
                    claims =
                    mapOf(
                        "document_ids" to documentIds,
                        "session_ids" to listOf(sessionId),
                        "request_limit" to
                            mapOf(
                                "requests" to 160,
                                "time_period_s" to 1000 * 60 * 10,
                            ),
                    ),
                )
            },
        ).also {
            assistant = it
        }
    }

    override fun navigateTo(documentRect: List<RectF>, pageIndex: Int, documentIndex: Int) {
        _currentDocumentIndex.value = documentIndex
        documentStateMap[documentIndex]?.documentConnection?.highlight(pageIndex, documentRect)
    }
}

/**
 * A custom toolbar component for document viewer with animated visibility.
 *
 * @param onClick Callback for AI Assistant button click
 * @param toolbarVisibility Whether the toolbar should be visible
 * @param documentDescriptors List of [DocumentDescriptor] to display titles in the toolbar
 * @param currentIndex The index of the currently selected document
 * @param onPagerIndexChange Callback to change the pager index when a tab is clicked
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomToolbar(
    onClick: () -> Unit,
    toolbarVisibility: Boolean,
    documentDescriptors: List<DocumentDescriptor>,
    currentIndex: Int,
    onPagerIndexChange: suspend (Int) -> Unit = {},
) {
    val localDensity = LocalDensity.current
    val context = LocalContext.current
    val coroutineScope = rememberCoroutineScope()

    // Animate toolbar appearance/disappearance with slide, expand and fade effects
    AnimatedVisibility(
        visible = toolbarVisibility,
        enter =
        slideInVertically { with(localDensity) { -40.dp.roundToPx() } } +
            expandVertically(expandFrom = Alignment.Top) +
            fadeIn(initialAlpha = 0.3f),
        exit = slideOutVertically() + shrinkVertically() + fadeOut(),
    ) {
        Column {
            TopAppBar(
                title = {
                    Column {
                        Text(
                            text = documentDescriptors[currentIndex].getTitle(context),
                            color = Color.White,
                            style =
                            TextStyle(
                                fontSize = 16.sp,
                                fontWeight = FontWeight.Medium,
                            ),
                        )
                    }
                },
                actions = {
                    IconButton(
                        onClick = onClick,
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.ic_ai_assistant),
                            contentDescription = "AI Assistant",
                            tint = Color.White,
                        )
                    }
                },
                colors =
                TopAppBarDefaults.topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary,
                    titleContentColor = MaterialTheme.colorScheme.onPrimary,
                ),
            )
            PrimaryTabRow(
                selectedTabIndex = currentIndex,
                modifier = Modifier.fillMaxWidth(),
            ) {
                documentDescriptors.forEachIndexed { index, descriptor ->
                    Tab(
                        selected = currentIndex == index,
                        onClick = {
                            coroutineScope.launch {
                                onPagerIndexChange.invoke(index)
                            }
                        },
                        text = {
                            Text(
                                text = descriptor.getTitle(context),
                                maxLines = 1,
                                overflow = TextOverflow.Ellipsis,
                            )
                        },
                    )
                }
            }
        }
    }
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Application Policy](/guides/android/samples/application-policy-kotlin.md)
- [Custom Form Highlight Color](/guides/android/samples/custom-form-highlight-color-java.md)
- [Custom Page Templates](/guides/android/samples/custom-page-templates-java.md)
- [Digital Signature (Basic)](/guides/android/samples/digital-signature-basic-kotlin.md)
- [Disabled Annotation Property](/guides/android/samples/disabled-annotation-property-java.md)
- [Image Document](/guides/android/samples/image-document-kotlin.md)
- [Compose Image Document](/guides/android/samples/compose-image-document-kotlin.md)
- [Inline Multimedia](/guides/android/samples/inline-multimedia-kotlin.md)
- [JavaScript Form Filling](/guides/android/samples/javascript-form-filling-kotlin.md)
- [Overlay Visibility](/guides/android/samples/overlay-visibility-kotlin.md)
- [PdfFragment](/guides/android/samples/pdffragment-kotlin.md)
- [Reader View](/guides/android/samples/reader-view-kotlin.md)
- [Playground](/guides/android/samples/playground-kotlin.md)
- [JavaScript Calculator](/guides/android/samples/javascript-calculator-kotlin.md)
- [Text Field Suggestions](/guides/android/samples/text-field-suggestions-kotlin.md)
- [Thumbnail Bar Modes](/guides/android/samples/thumbnail-bar-modes-kotlin.md)
- [Signature Storage Database](/guides/android/samples/signature-storage-database-kotlin.md)
- [Selection Customization](/guides/android/samples/selection-customization-java.md)
- [Password Protected PDF](/guides/android/samples/password-protected-pdf-kotlin.md)
- [Scientific Paper](/guides/android/samples/scientific-paper-kotlin.md)
- [Try Instant](/guides/android/samples/try-instant-kotlin.md)
- [Merge Documents](/guides/android/samples/merge-documents-kotlin.md)
- [Annotation Rendering](/guides/android/samples/annotation-rendering-kotlin.md)
- [Custom Data Provider](/guides/android/samples/custom-data-provider-kotlin.md)
- [Annotations with Transparency](/guides/android/samples/annotations-with-transparency-kotlin.md)
- [Annotation Flags](/guides/android/samples/annotation-flags-kotlin.md)
- [AI Assistant (Multiple Documents, ViewPager)](/guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md)
- [Custom Sharing Menu](/guides/android/samples/custom-sharing-menu-java.md)
- [Add LTV to Existing Signature](/guides/android/samples/add-ltv-to-existing-signature-kotlin.md)
- [Custom Toolbar Grouping](/guides/android/samples/custom-toolbar-grouping-java.md)
- [Custom Layout](/guides/android/samples/custom-layout-kotlin.md)
- [Custom ActionBar Actions](/guides/android/samples/custom-actionbar-actions-kotlin.md)
- [Custom Activity Toolbars](/guides/android/samples/custom-activity-toolbars-java.md)
- [Custom Note Hinter](/guides/android/samples/custom-note-hinter-kotlin.md)
- [Custom Main Toolbar](/guides/android/samples/custom-main-toolbar-kotlin.md)
- [Annotation Configuration](/guides/android/samples/annotation-configuration-kotlin.md)
- [Annotation Selection Styling](/guides/android/samples/annotation-selection-styling-kotlin.md)
- [Custom Search UI (Compose)](/guides/android/samples/custom-search-ui-compose-kotlin.md)
- [Document Switcher](/guides/android/samples/document-switcher-java.md)
- [File Annotation Creation](/guides/android/samples/file-annotation-creation-kotlin.md)
- [Dynamic Pages on Scroll](/guides/android/samples/dynamic-pages-on-scroll-kotlin.md)
- [Custom Activity Form Editing](/guides/android/samples/custom-activity-form-editing-java.md)
- [Custom Stamp Annotations](/guides/android/samples/custom-stamp-annotations-java.md)
- [Custom Outline Provider](/guides/android/samples/custom-outline-provider-kotlin.md)
- [Compose Navigation](/guides/android/samples/compose-navigation-kotlin.md)
- [Fragment Runtime Configuration](/guides/android/samples/fragment-runtime-configuration-kotlin.md)
- [Annotation Overlay](/guides/android/samples/annotation-overlay-java.md)
- [Instant Document JSON](/guides/android/samples/instant-document-json-kotlin.md)
- [DocumentView Composable](/guides/android/samples/documentview-composable-kotlin.md)
- [Form Creation](/guides/android/samples/form-creation-kotlin.md)
- [Document Download](/guides/android/samples/document-download-kotlin.md)
- [JavaScript Actions](/guides/android/samples/javascript-actions-kotlin.md)
- [Instant JSON Attachment](/guides/android/samples/instant-json-attachment-kotlin.md)
- [Digital Signature (Manual)](/guides/android/samples/digital-signature-manual-kotlin.md)
- [Digital Signature (Third-Party)](/guides/android/samples/digital-signature-third-party-kotlin.md)
- [Inline Search](/guides/android/samples/inline-search-java.md)
- [Form Filling](/guides/android/samples/form-filling-kotlin.md)
- [Form Click Intercept (Compose)](/guides/android/samples/form-click-intercept-compose-kotlin.md)
- [Document Sharing](/guides/android/samples/document-sharing-java.md)
- [Custom Download Dialog](/guides/android/samples/custom-download-dialog-java.md)
- [Download Progress](/guides/android/samples/download-progress-kotlin.md)
- [Popup Toolbar Customization](/guides/android/samples/popup-toolbar-customization-kotlin.md)
- [Custom Sharing Dialog](/guides/android/samples/custom-sharing-dialog-java.md)
- [PDF from Image](/guides/android/samples/pdf-from-image-kotlin.md)
- [Digital Signature (Two-Step)](/guides/android/samples/digital-signature-two-step-kotlin.md)
- [Remote URL](/guides/android/samples/remote-url-kotlin.md)
- [PdfUiFragment](/guides/android/samples/pdfuifragment-kotlin.md)
- [Runtime Configuration](/guides/android/samples/runtime-configuration-kotlin.md)
- [Sound Extraction](/guides/android/samples/sound-extraction-kotlin.md)
- [Document from Canvas](/guides/android/samples/document-from-canvas-kotlin.md)
- [Tabbed Documents](/guides/android/samples/tabbed-documents-kotlin.md)
- [Watermarks](/guides/android/samples/watermarks-kotlin.md)
- [Programmatic Zoom](/guides/android/samples/programmatic-zoom-kotlin.md)
- [Signature Parcelize](/guides/android/samples/signature-parcelize-kotlin.md)
- [OCR](/guides/android/samples/ocr-kotlin.md)
- [Vertical Scrollbar](/guides/android/samples/vertical-scrollbar-java.md)
- [Split View](/guides/android/samples/split-view-java.md)
- [XFDF Import/Export](/guides/android/samples/xfdf-import-export-kotlin.md)
- [UI View Modes](/guides/android/samples/ui-view-modes-kotlin.md)
- [LTV Signature](/guides/android/samples/ltv-signature-kotlin.md)
- [Bookmark Highlighting](/guides/android/samples/bookmark-highlighting-kotlin.md)
- [Custom Annotation Inspector](/guides/android/samples/custom-annotation-inspector-java.md)
- [Annotation Sidebar](/guides/android/samples/annotation-sidebar-kotlin.md)
- [AI Assistant (Single Document)](/guides/android/samples/ai-assistant-single-document-kotlin.md)
- [Document Comparison](/guides/android/samples/document-comparison-kotlin.md)
- [Document Processing](/guides/android/samples/document-processing-kotlin.md)
- [Custom Annotation Creation Toolbar](/guides/android/samples/custom-annotation-creation-toolbar-java.md)
- [Custom Electronic Signature](/guides/android/samples/custom-electronic-signature-java.md)
- [E-Learning](/guides/android/samples/e-learning-kotlin.md)
- [Electronic + Digital Signing](/guides/android/samples/electronic-digital-signing-kotlin.md)
- [Generate PDF Report](/guides/android/samples/generate-pdf-report-kotlin.md)
- [Multimedia Annotations](/guides/android/samples/multimedia-annotations-kotlin.md)
- [Forms with JavaScript](/guides/android/samples/forms-with-javascript-kotlin.md)
- [External Document](/guides/android/samples/external-document-kotlin.md)
- [Overlay Views](/guides/android/samples/overlay-views-kotlin.md)
- [Kiosk Grid](/guides/android/samples/kiosk-grid-kotlin.md)
- [Search Indexing](/guides/android/samples/search-indexing-kotlin.md)
- [Annotation Creation](/guides/android/samples/annotation-creation-kotlin.md)
- [Filterable Thumbnail Grid](/guides/android/samples/filterable-thumbnail-grid-kotlin.md)
- [Tabbed Documents (Persistent)](/guides/android/samples/tabbed-documents-persistent-kotlin.md)
- [Measurement Tools](/guides/android/samples/measurement-tools-kotlin.md)
- [HTML-to-PDF Conversion](/guides/android/samples/html-to-pdf-conversion-kotlin.md)
- [AES Encrypted File](/guides/android/samples/aes-encrypted-file-java.md)
- [Construction Floor Plan](/guides/android/samples/construction-floor-plan-kotlin.md)
- [Hide and Reveal Areas](/guides/android/samples/hide-and-reveal-areas-kotlin.md)
- [Multiple Documents (Compose Pager)](/guides/android/samples/multiple-documents-compose-pager-kotlin.md)
- [Screen Reader](/guides/android/samples/screen-reader-java.md)
- [Custom Search UI (Views)](/guides/android/samples/custom-search-ui-views-java.md)

