ささやき (sasayaki)
August 13, 2026 · View on GitHub
ANDROID WILL BECOME A LOCKED-DOWN PLATFORM
ささやき (sasayaki)
A tiny (2MB) Android dictation app. Point it at any OpenAI-compatible backend and type by speaking.
Sasayaki does the same job as WisprFlow, except it costs nothing and is more private, connecting to your own models.
IMPORTANT: This app was coded with AI. I am not an android developer, and I wouldn't be able to do this if it wasn't for AI. I try to enforce good practices, but any contributions or suggestions are very welcome. The app works pretty fine, is small, and gives me what I want.
Features
- A floating dot appears when the keyboard opens. Tap it to dictate, and it stops when you go quiet.
- While you speak it widens into a timer with pause, cancel and profile buttons.
- Tap the bubble while it is processing to drop the dictation.
- Profiles bundle a language, an ASR model, an LLM model and a writing style. Switch the active one from the bubble.
- Post-processing: a small model turns what you said into a clean written message.
- "Uh... Yeah, let's meet at 8.. No sorry, at 9!" → "Let's meet at 9."
- Per profile, set the punctuation and casing, how far the model may rewrite you, how much it should condense, and whether emoji are allowed.
- Sasayaki passes the app you are dictating into as context, so mail comes out in a different tone from a chat.
- Replacement rules fix the words your ASR keeps mangling. Plain text or regex, and each profile chooses which ones apply.
- Write your own post-processing prompts and switch them on per profile, alongside the built-in ones.
- History keeps past dictations, up to a limit you choose, and can be switched off. Word and time totals keep counting either way.
- The bubble comes back on its own after a reboot.
![]() |
![]() |
| Main dashboard | Floating bubble recording in-chat |
Install
Grab the latest APK from the releases page and install it. Obtainium can keep it updated for you:
You need an Android device and an ASR backend that speaks the OpenAI API. An LLM for post-processing is optional and worth it.
Backends
Nothing here needs hosting: the app is the whole product, and it will talk to any OpenAI-compatible API. Run your own if you care about privacy and owning your data. If you would rather not, ppq.ai and nano-gpt.com are reasonable choices when you trust them. If you want a fully private backend, check out tinfoil.
Speech to text
Plenty of options exist, from whisper.cpp to faster-whisper. I run speaches.
For the model itself, deepdml/faster-whisper-large-v3-turbo-ct2 beat everything else I tried across several European languages. On a GPU it is quick, and it holds up when you talk fast or even whisper.
Other options:
- The whisper family, from tiny up to medium. For English only, the
enmodels are smaller and sharper. Parakeetgives good results.moonshineis small and multilingual, though I know of no OpenAI-compatible API for it.Voxtral Mini
Setting your main languages in the app lowers the word error rate.
LLM post-processing
Optional. A 2B or 4B model on a consumer GPU adds little delay and cleans the text up well.
I fine-tuned the 2B version of Qwen3.5 (unsloth/Qwen3.5-2B) using the recipe in the fine-tuning directory. Generate a synthetic dataset in your language, then train with unsloth on about 5GB of VRAM.
To serve it, I use llama-swap over a llama.cpp backend. Plain llama.cpp, koboldcpp and LlamaFiles all work too.
The same providers are useful if you don't want to host your own (ppq.ai and nano-gpt.com). If you want private inference, check out tinfoil.
Pick a model that follows instructions. Some will answer a dictated question instead of transcribing it, so that "what is the capital of France" becomes "Paris" in your chat box. The eval suite below catches that.
Development
Build the release APK in Docker, which avoids installing an Android SDK or a matching JDK:
make build # writes sasayaki-release.apk
Run the prompt tests, which need no network and no credentials:
./gradlew testDebugUnitTest
Two further suites measure the post-processing prompts against real models. They skip themselves unless OPENAI_ENDPOINT and OPENAI_API_KEY are set, so they never run by accident:
PostProcessingBenchmarksends dictations in English, Spanish, French, Catalan and Italian, then checks whether self-corrections were applied, whether the text stayed in its original language, and how long each model took.StyleControlDifferentialTestverifies that moving a style control changes the output, which is how I found two settings that did nothing at all.
Both write a report under app/build/reports/benchmark/.
License
GPLv3
Why ささやき?
It means whisper in Japanese. I like how it sounds and looks. I am also learning Japanese, so I thought it's fun to use a Japanese word I learned for this tiny app.


