main
Onde Chat
A simple Android chat app built with the Onde Inference SDK. It runs Qwen 2.5 1.5B entirely on your phone — no server, no API key, nothing leaves the device.
What it does
- Downloads the model on first launch (~941 MB, cached after that)
- Streams replies token by token as the model generates them
- Keeps a full conversation history across turns
- Works offline once the model is cached
Getting started
Open onde/sdk/kotlin/example/ as the project root in Android Studio (not the repo root — the settings.gradle.kts lives here). Gradle will pull everything from Maven Central on first sync.
You'll need a device or emulator running Android 8.0 (API 26) or higher. An x86_64 emulator works fine, though a real ARM phone will feel noticeably faster.
Hit Run. The first launch will download the model over your internet connection — after that the app is fully offline.
Project layout
example/
├── settings.gradle.kts standalone project root
├── build.gradle.kts deps and build config
└── src/main/
├── AndroidManifest.xml INTERNET permission lives here
└── kotlin/com/ondeinference/example/
├── MainActivity.kt one activity, sets up the theme and hands off to Compose
├── ChatViewModel.kt model loading, streaming, history — all the logic
└── ui/
├── ChatScreen.kt everything you see on screen
└── theme/Theme.kt Material3 colours, dynamic on Android 12+
How the streaming works
When you send a message, the app drops an empty assistant bubble into the list immediately, then fills it in character by character as tokens arrive from the Rust engine. The ViewModel holds a StringBuilder and swaps the tail of the message list on every chunk — so Compose only recomposes the one bubble that's changing, not the whole conversation.
onde.stream(text).collect { chunk ->
buffer.append(chunk.delta)
// update only the last bubble in the list
}
Swapping the model
The app loads the platform default (Qwen 2.5 1.5B) via loadDefaultModel(). To use a different model, call loadModel() with a config instead:
onde.loadModel(
config = OndeModels.qwen25_3b(), // ~1.93 GB — not great on phones
systemPrompt = "You are a creative writing assistant.",
sampling = OndeSampling.deterministic(),
)
Available sampling presets:
| Preset | Temp | Max tokens | Good for |
|---|---|---|---|
OndeSampling.mobile() |
0.7 | 128 | everyday chat |
OndeSampling.default() |
0.7 | 512 | longer responses |
OndeSampling.deterministic() |
0.0 | 512 | coding, facts |
Developing against a local SDK build
By default the app pulls onde-inference from Maven Central. If you want to test changes to the SDK itself, open the parent directory (onde/sdk/kotlin/) in Android Studio instead and swap the dependency in build.gradle.kts:
// instead of:
implementation("com.ondeinference:onde-inference:0.1.3")
// use:
implementation(project(":lib"))
Troubleshooting
Download never finishes — check your internet connection. HuggingFace Hub occasionally rate-limits anonymous downloads; setting an HF_TOKEN env variable before building can help.
App crashes immediately — make sure you're on API 26+. The SDK uses Os.setenv to configure the HuggingFace cache paths, which requires Android 8.0.
Inference is very slow — CPU inference on an emulator is slow by design. Try a physical ARM device for a much better experience.
Out of memory on load — the 1.5B model needs roughly 1–1.5 GB of free RAM. Close other apps and try again, or restart the device.