A language course that measures your pronunciation for real. Glosso listens to each take, recognizes the sounds you actually made, compares them with the expected ones and tells you exactly which sound to fix. Android first, with an iOS app in progress. Languages: English (British and American), French, German and Russian.
The same phonetic engine runs on the phone (offline, ONNX Runtime) and on the server, so a take gets the same score in both places.
Glosso is free for everyone, with no paid tier. Support is a voluntary donation.
| Module | What it is |
|---|---|
:engine |
Kotlin Multiplatform phonetic engine: G2P, wav2vec2 phoneme recognition (ONNX), speech gate, phonetic comparison and feedback. The only place a score is computed. |
:server |
Ktor API (/v1/score, content, assets, product config, accounts). Reuses :engine. |
:shared |
The app itself in Compose Multiplatform (screens, view models, stores, API client), shared by Android and iOS. |
:androidApp |
Android shell: activity, on-device scorer, download service. Two flavors: playstore and fdroid (no Google libraries). |
iosApp/ |
Xcode project that runs the shared app on iOS. |
deploy/ |
Dockerfile, Compose stack, Caddy and monitoring config for self-hosting the server. |
tools/ |
Asset download, scoring bench, score parity, content pipeline and license tooling. |
How one take is scored:
- Reference IPA from the text through the language's G2P (
engine/.../g2p/). - Recognition:
Wav2Vec2PhonemeRecognizerreturns the heard phones with confidence and timings. - Gate:
SpeechGatedecides whether the audio can be judged at all. Unjudgeable audio is reported as "not evaluated", never as a low score. - Comparison:
PhoneticComparatoraligns expected and heard phones into perfect, close and missed, using per-language similarity and error rules. - Feedback:
FeedbackAssemblerbuilds the result both the app and the server return.
Everything language-specific hangs off LanguagePack (engine/.../model/LanguagePack.kt).
Adding a language is data plus a pack; see docs/ADD_LANGUAGE.md.
Requirements: JDK 21, the Android SDK (for the app), Python 3 (license check that runs on every app build) and Xcode (iOS only).
# Model, vocab and CMUdict (~350 MB) into data/assets
tools/fetch-assets.sh
# Tests
./gradlew :engine:jvmTest
./gradlew :server:test
./gradlew :shared:testAndroidHostTest # shared UI, Robolectric
./gradlew :androidApp:testFdroidDebugUnitTest :androidApp:testPlaystoreDebugUnitTest
# Run the server locally on :8080 (serves data/assets)
./gradlew :server:run
# Build the Android app against the local server (from the emulator)
./gradlew :androidApp:assembleFdroidDebug -PglossoApiBase=http://10.0.2.2:8080
# Release builds of each flavor (unsigned without a keystore)
./gradlew :androidApp:assembleFdroidRelease # F-Droid: no Google libraries
./gradlew :androidApp:bundlePlaystoreRelease # Google PlayThe app has two flavors. fdroid contains no non-free library: no Google Play
services and no Sign in with Google (so "Change phone" is hidden), and usage
statistics start off. playstore is the Google Play build with Sign in with
Google. See docs/FDROID.md.
Without -PglossoApiBase the app talks to the public Glosso API by default. Build inputs are Gradle
properties documented in androidApp/build.gradle.kts. The server runs with only the assets on
disk; PostgreSQL, Redis and the TTS providers are optional and each feature turns itself off
when its dependency is missing. The full list of environment variables is in
deploy/.env.example, and docs/DEPLOYMENT.md describes a production setup.
Engine tests that need the model or real audio skip themselves when the assets are not set.
tools/engine-bench/run.sh is the scoring bench that runs them; see
docs/ENGINE-BENCHMARK.md.
The server is in this repository (:server, AGPL) and anyone can run it: deploy/ has the
Dockerfile, a Compose stack and the reverse proxy, and docs/DEPLOYMENT.md walks through a
production setup. To point the app at it, open Settings > Advanced > Server, enter its address
(https://...) and tap "Check and use". The app checks that the address answers like a Glosso
server (/health and /v1/config) before switching; from then on lessons, cloud scoring,
downloads, usage statistics and sign-in all go to that server. "Use the default server" switches
back. Switching drops what came from the previous server (cached content and config, unsent
statistics); downloaded lessons are kept only when the new server serves exactly the same content
fingerprint. The learner's progress stays on the phone. Plain http:// is
accepted only by debug builds and only for a local address (localhost, 10.0.2.2, private
LAN ranges).
Most design docs are in Spanish. Some code comments mention research scripts and internal notes that are not part of the public repository.
docs/ADD_LANGUAGE.md- adding a languagedocs/ENGINE-BENCHMARK.md,docs/SCORING-DECISION-LAYER.md,docs/PHONEME_PROFILE.md- scoringdocs/MULTI-ACCENT.md- scoring against whole accent systemsdocs/CONTENT-ENGINE.md,docs/CONTENT_POOL.md,docs/TTS-LAYER.md,docs/TTS-CACHE.md- content and audio generationdocs/PRODUCT-CONFIG-CONTRACT.md,docs/GOOGLE-SIGNIN.md- product config and accountsdocs/BILLING.md- why there is no paid tierdocs/IOS-DEV.md,docs/IOS-ENGINE.md- iOSdocs/FDROID.md- the F-Droid flavor and the rules it followsdocs/PRIVACY.md,docs/LICENSING.md- privacy and third-party licensing
See CONTRIBUTING.md.
Glosso is free software under the GNU Affero General Public License v3.0 or later
(LICENSE). If you run a modified version of the server for others, you must offer
them its source. NOTICE lists the third-party components and their licenses, and an
additional permission for linking with the Google Play libraries the playstore build uses.
The Glosso name and logo are not covered by the license: forks must use their own.