{"id":37023268,"url":"https://github.com/getstream/stream-chat-android-ai","last_synced_at":"2026-01-14T02:47:26.467Z","repository":{"id":327571114,"uuid":"1096398063","full_name":"GetStream/stream-chat-android-ai","owner":"GetStream","description":"Official Stream Chat UI components for AI-first Android apps with Jetpack Compose. Features streaming text, markdown, and chat state management.","archived":false,"fork":false,"pushed_at":"2025-12-16T10:04:21.000Z","size":2638,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2025-12-18T07:37:53.125Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GetStream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-14T11:15:22.000Z","updated_at":"2025-12-16T17:33:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/GetStream/stream-chat-android-ai","commit_stats":null,"previous_names":["getstream/stream-chat-android-ai"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/GetStream/stream-chat-android-ai","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-chat-android-ai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-chat-android-ai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-chat-android-ai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-chat-android-ai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GetStream","download_url":"https://codeload.github.com/GetStream/stream-chat-android-ai/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GetStream%2Fstream-chat-android-ai/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T02:47:25.868Z","updated_at":"2026-01-14T02:47:26.441Z","avatar_url":"https://github.com/GetStream.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Integrating Stream Chat with AI](/assets/repo_cover.png)\n\n# AI components for [Stream Android Chat SDK](https://getstream.io/tutorials/android-chat/)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/GetStream/stream-chat-android-ai/actions/workflows/ci.yml\"\u003e\n    \u003cimg alt=\"CI\" src=\"https://github.com/GetStream/stream-chat-android-ai/actions/workflows/ci.yml/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://developer.android.com/about/versions/marshmallow\"\u003e\n    \u003cimg alt=\"API-23\" src=\"https://img.shields.io/badge/API-23%2B-brightgreen.svg?style=flat\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/GetStream/stream-chat-android-ai/releases\"\u003e\n    \u003cimg alt=\"release\" src=\"https://img.shields.io/github/v/release/GetStream/stream-chat-android-ai?color=lightblue\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://central.sonatype.com/repository/maven-snapshots/io/getstream/stream-chat-android-ai-compose/\"\u003e\n    \u003cimg alt=\"snapshot\" src=\"https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Fio%2Fgetstream%2Fstream-chat-android-ai-compose%2Fmaven-metadata.xml\u0026strategy=latestProperty\u0026label=snapshot\u0026color=lightblue\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![stream-chat-android-ai-compose](https://img.shields.io/badge/stream--chat--android--ai--compose-.01%20MB-lightgreen)\n\n\u003c/div\u003e\n\nThis official repository for Stream Chat's UI components is designed specifically for AI-first\napplications written in Jetpack Compose. When paired with our real-time [Chat API](https://getstream.io/chat/), it makes\nintegrating with and rendering responses from LLM providers such as ChatGPT, Gemini, Anthropic or\nany custom backend easier by providing rich out-of-the-box components able to render Markdown,\ncode blocks, tables, thinking indicators, images, etc.\n\nTo start, this library includes the following components which assist with this task:\n\n**StreamingText** - a composable that progressively reveals text content word-by-word with smooth\nanimation, perfect for displaying AI-generated responses in real-time, similar to ChatGPT.\n\n**AITypingIndicator** - a component that displays animated typing indicators with optional\nlabels, able to show different states of the LLM (thinking, checking external sources, etc).\n\n**ChatComposer** - a complete chat input component with text input, attachment support, voice input,\nand send/stop buttons. It manages message composition state and provides a polished UI with\nautomatic keyboard handling.\n\n**SpeechToTextButton** - a composable button that provides speech-to-text functionality with\nwaveform visualization, automatic permission handling, and customizable UI components.\n\nThis repository also includes a sample app that demonstrates how to use these components in a\nAI chat application.\n\nOur team plans to keep iterating and adding more components over time. If there's a component\nyou use every day in your apps and would like to see added, please open an issue and we will try\nto add it 😎.\n\n## 📦 Installation\n\nAdd the dependency to your `build.gradle.kts`:\n\n```kotlin\ndependencies {\n    implementation(\"io.getstream:stream-chat-android-ai-compose:$version\")\n}\n```\n\nThe library provides UI components that work independently. For state management and backend\nintegration, refer to the sample app which demonstrates how to integrate these components with\nStream Chat SDK and AI providers.\n\n### Snapshot Releases\n\nTo use snapshot releases, you need to add the Sonatype snapshot repository to your `settings.gradle.kts`:\n\n```kotlin\ndependencyResolutionManagement {\n    repositories {\n        google()\n        mavenCentral()\n        maven { url = uri(\"https://central.sonatype.com/repository/maven-snapshots\") }\n    }\n}\n```\n\nFind the latest snapshot version in the badge above, or check the [Maven Central snapshot repository](https://central.sonatype.com/repository/maven-snapshots/io/getstream/stream-chat-android-ai-compose/) for available versions.\n\n## 🚀 Usage\n\n### AITypingIndicator\n\n`AITypingIndicator` is a composable that displays an animated typing indicator with an optional\nlabel. By default, it shows three animated dots that sequentially highlight.\n\n**Basic Usage:**\n\n```kotlin\nimport io.getstream.chat.android.ai.compose.ui.component.AITypingIndicator\n\n@Composable\nfun MyScreen() {\n    AITypingIndicator(\n        label = { Text(\"Thinking\") }\n    )\n}\n```\n\n**Customization:**\n\n```kotlin\nAITypingIndicator(\n    modifier = Modifier.padding(16.dp),\n    label = { Text(\"Processing...\") },\n    indicator = { \n        // Custom indicator composable\n        CircularProgressIndicator()\n    }\n)\n```\n\n**Parameters:**\n- `modifier`: Modifier to be applied to the root Row container\n- `label`: Optional composable label to display before the indicator (defaults to empty)\n- `indicator`: Composable indicator to display (defaults to `AnimatedDots`)\n\n### StreamingText\n\n`StreamingText` progressively reveals text content word-by-word with smooth animation, perfect\nfor displaying AI-generated responses. By default it renders the streamed text using the same\nmarkdown formatter as the sample app, so you can drop it directly into chat bubbles without any\nextra setup.\n\n**Basic Usage:**\n\n```kotlin\nimport io.getstream.chat.android.ai.compose.ui.component.StreamingText\n\n@Composable\nfun AssistantMessage(\n    text: String,\n    isGenerating: Boolean\n) {\n    StreamingText(\n        text = text,\n        animate = isGenerating,\n    )\n}\n```\n\n**Customization:**\n\n```kotlin\nStreamingText(\n    text = fullText,\n    animate = true,\n    chunkDelayMs = 50, // Adjust animation speed\n) { displayedText -\u003e\n    Text(\n        text = displayedText,\n        style = MaterialTheme.typography.bodyLarge\n    )\n}\n```\n\n**Behavior:**\n- When `animate` is `true`: Progressively reveals text word-by-word\n- When `animate` is `false`: Displays full text immediately\n- Automatically handles continuation (if new text starts with previous text, continues from\n  current position)\n- Resets animation for completely new text\n\n**Parameters:**\n- `text`: The full text content to display\n- `animate`: Whether to animate the text reveal (default: `true`)\n- `chunkDelayMs`: Delay in milliseconds between each chunk reveal (default: `30`)\n- `content`: Optional composable that receives the animated text as `displayedText`. Defaults to\n  the library's markdown renderer used across the sample app.\n\n### ChatComposer\n\n`ChatComposer` is a complete chat input component that provides text input, attachment support,\nvoice input, and send/stop buttons.\n\n**Basic Usage (with internal state management):**\n\n```kotlin\nimport io.getstream.chat.android.ai.compose.ui.component.ChatComposer\nimport io.getstream.chat.android.ai.compose.ui.component.MessageData\n\n@Composable\nfun ChatScreen(isGenerating: Boolean) {\n    ChatComposer(\n        onSendClick = { messageData: MessageData -\u003e\n            // Handle message send\n            // messageData.text contains the text\n            // messageData.attachments contains Set\u003cUri\u003e of selected images\n        },\n        onStopClick = {\n            // Handle stop streaming\n        },\n        isGenerating = isGenerating,\n    )\n}\n```\n\n**Features:**\n- Text input with placeholder (\"Ask Assistant\")\n- Image attachment support (up to 3 images via photo picker)\n- Voice input button with speech-to-text integration\n- Send button (shown when text is entered)\n- Stop button (shown during AI generation)\n- Attachment preview with remove functionality\n\n**MessageData Structure:**\n\n```kotlin\ndata class MessageData(\n    val text: String = \"\",\n    val attachments: Set\u003cUri\u003e = emptySet(),\n)\n```\n\n### SpeechToTextButton\n\n`SpeechToTextButton` provides speech-to-text functionality with animated waveform visualization\nand automatic permission handling. Clicking the button toggles recording on and off. When not recording,\nit displays a microphone icon button. When recording, it transforms into a circular button with animated\nbars that respond to voice input levels.\n\n**Basic Usage:**\n\n```kotlin\nimport io.getstream.chat.android.ai.compose.ui.component.SpeechToTextButton\nimport io.getstream.chat.android.ai.compose.ui.component.rememberSpeechToTextButtonState\n\n@Composable\nfun MyComposer() {\n    var text by remember { mutableStateOf(\"\") }\n\n    val speechState = rememberSpeechToTextButtonState(\n        onFinalResult = { recognizedText -\u003e\n            // Called with the final result when recording stops\n            text = recognizedText\n        }\n    )\n\n    SpeechToTextButton(\n        state = speechState\n    )\n}\n```\n\n**Usage with Real-time Streaming:**\n\n```kotlin\n@Composable\nfun MyComposer() {\n    var text by remember { mutableStateOf(\"\") }\n\n    val speechState = rememberSpeechToTextButtonState(\n        onPartialResult = { partialText -\u003e\n            // Called with partial results as user speaks (real-time streaming)\n            // This updates continuously as speech is detected\n            text = partialText\n        },\n        onFinalResult = { finalText -\u003e\n            // Called with the final result when recording stops\n            // This is the complete, finalized transcription\n            text = finalText\n        }\n    )\n\n    SpeechToTextButton(\n        state = speechState\n    )\n}\n```\n\n**Advanced Usage with State Tracking:**\n\n```kotlin\nimport io.getstream.chat.android.ai.compose.ui.component.SpeechToTextButton\nimport io.getstream.chat.android.ai.compose.ui.component.rememberSpeechToTextButtonState\n\n@Composable\nfun MyComposer() {\n    var text by remember { mutableStateOf(\"\") }\n\n    // Remember the text that existed before starting speech recognition\n    var textBeforeSpeech by remember { mutableStateOf(\"\") }\n\n    val speechState = rememberSpeechToTextButtonState(\n        onPartialResult = { partialText -\u003e\n            // Update with partial results in real-time\n            text = if (textBeforeSpeech.isBlank()) {\n                partialText\n            } else {\n                \"$textBeforeSpeech $partialText\"\n            }\n        },\n        onFinalResult = { finalText -\u003e\n            // Append final recognized text after the text which is already in the composer\n            text = if (textBeforeSpeech.isBlank()) {\n                finalText\n            } else {\n                \"$textBeforeSpeech $finalText\"\n            }\n        }\n    )\n\n    // Capture text when recording starts\n    LaunchedEffect(speechState.isRecording()) {\n        if (speechState.isRecording()) {\n            textBeforeSpeech = text\n        }\n    }\n\n    SpeechToTextButton(\n        state = speechState\n    )\n\n    // Check if currently recording\n    if (speechState.isRecording()) {\n        Text(\"Recording...\")\n    }\n}\n```\n\n**Customization:**\n\n```kotlin\nval speechState = rememberSpeechToTextButtonState(\n    onPartialResult = { partialText -\u003e\n        // Handle partial results (optional)\n    },\n    onFinalResult = { finalText -\u003e\n        // Handle final result\n    }\n)\n\nSpeechToTextButton(\n    state = speechState,\n    idleContent = { onClick -\u003e\n        // Custom content when not recording\n        IconButton(onClick = onClick) {\n            Icon(Icons.Default.Mic, \"Voice input\")\n        }\n    },\n    recordingContent = { onClick, rmsdB -\u003e\n        // Custom content when recording\n        // rmsdB is the current audio level (0-10) for visualization\n        IconButton(onClick = onClick) {\n            // Your custom recording visualization\n        }\n    }\n)\n```\n\n**Features:**\n- Click to toggle recording on/off\n- Automatic audio permission requests (RECORD_AUDIO)\n- Animated waveform visualization during recording that responds to audio levels\n- Real-time streaming of recognized text (partial results as speech is detected)\n- Final result callback when recording stops\n- Automatic UI transformation between idle and recording states\n- State tracking for recording status\n\n**Parameters:**\n- `modifier`: Modifier to be applied to the root container\n- `state`: Optional state holder for tracking recording status and receiving recognized text.\n  Defaults to a remembered state with an empty callback. To receive text, create a state using\n  `rememberSpeechToTextButtonState` with your callbacks and pass it here.\n- `idleContent`: The composable content to display when not recording. Receives an onClick callback\n  that toggles recording. Defaults to a microphone icon button.\n- `recordingContent`: The composable content to display when recording. Receives an onClick callback\n  that stops recording and the current audio level (rmsdB) for visualization. Defaults to animated bars.\n\n**rememberSpeechToTextButtonState Parameters:**\n- `onPartialResult`: Optional callback invoked when text chunks are recognized during recording.\n  Called with each partial result as speech is detected, enabling real-time text streaming.\n  Use this to update your UI in real-time as the user speaks.\n- `onFinalResult`: Required callback invoked when the final result is available after recording stops.\n  Called with the complete, finalized transcription. This is the definitive result of the speech recognition.\n\n**SpeechToTextButtonState API:**\n\n```kotlin\n// Check if currently recording\nval isRecording: Boolean = state.isRecording()\n```\n\n## 🛥 What is Stream?\n\nStream allows developers to rapidly deploy scalable feeds, chat messaging and video with an industry leading 99.999% uptime SLA guarantee.\n\nStream provides UI components and state handling that make it easy to build real-time chat and video calling for your app. Stream runs and maintains a global network of edge servers around the world, ensuring optimal latency and reliability regardless of where your users are located.\n\n## 📕 Tutorials\n\nTo learn more about integrating AI and chatbots into your application, we recommend checking out the full list of tutorials across all of our supported frontend SDKs and providers. Stream's Chat SDK is natively supported across:\n* [React](https://getstream.io/chat/react-chat/tutorial/)\n* [React Native](https://getstream.io/chat/react-native-chat/tutorial/)\n* [Angular](https://getstream.io/chat/angular/tutorial/)\n* [Jetpack Compose](https://getstream.io/tutorials/android-chat/)\n* [SwiftUI](https://getstream.io/tutorials/ios-chat/)\n* [Flutter](https://getstream.io/chat/flutter/tutorial/)\n* [Javascript/Bring your own](https://getstream.io/chat/docs/javascript/)\n\n## 👩‍💻 Free for Makers 👨‍💻\n\nStream is free for most side and hobby projects.\nTo qualify, your project/company needs to have \u003c 5 team members and \u003c $10k in monthly revenue.\nMakers get $100 in monthly credit for video for free.\nFor more details, check out the [Maker Account](https://getstream.io/maker-account).\n\n## 💼 We are hiring!\n\nWe've recently closed a [\\$38 million Series B funding round](https://techcrunch.com/2021/03/04/stream-raises-38m-as-its-chat-and-activity-feed-apis-power-communications-for-1b-users/) and we keep actively growing.\nOur APIs are used by more than a billion end-users, and you'll have a chance to make a huge impact on the product within a team of the strongest engineers all over the world.\nCheck out our current openings and apply via [Stream's website](https://getstream.io/team/#jobs).\n\n## License\n\n```\nCopyright (c) 2014-2025 Stream.io Inc. All rights reserved.\n\nLicensed under the Stream License;\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   https://github.com/GetStream/stream-chat-android-ai/blob/main/LICENSE\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetstream%2Fstream-chat-android-ai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetstream%2Fstream-chat-android-ai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetstream%2Fstream-chat-android-ai/lists"}