"it works when the internet doesn't."
Shongjog is an offline-first, Bangla, voice-first emergency companion for Bangladesh, covering 12 hazard types and 13 first-aid topics. Gemma 4 runs entirely on-device via LiteRT-LM over a verified Bangla RAG corpus, so grounded guidance is available in airplane mode. Online it enriches that core with 13 live endpoints; with no internet at all it forms a Bluetooth / Wi-Fi Direct mesh carrying text, media and full-duplex voice calls between nearby phones.
Targets Android arm64-v8a only — local model inference requires it.
- Download · Features · Quick Start
- Firebase Setup (required to build)
- Building · Testing · Architecture
- Configuration · Documentation · Contributing
Grab the latest APK from Releases.
- Requires an arm64-v8a Android device (nearly all phones from the last several years), minSdk 26.
- Not on the Play Store — allow "Install from unknown sources" for your browser or file manager.
- On first launch the app downloads Gemma 4 E2B (2.47 GB; keep ~3 GB free). Everything else — quick cards, triage wizard, shelter map, offline directory — works immediately.
| Module | Path | Offline |
|---|---|---|
| Chat — grounded Bangla Q&A over the RAG corpus | Gemma 4 on-device | ✅ |
| AI Family Disaster Planner | Gemma 4 on-device | ✅ |
| AI Emergency Kit Generator | Gemma 4 on-device | ✅ |
| AI Risk Assessment | Gemma 4 on-device | ✅ |
| AI Situation Summary | Gemma 4 on-device | ✅ |
| AI Shelter Brief | Gemma 4 on-device | ✅ |
| AI Safety Re-Ranking (weighs live hazard proximity) | Gemma 4 on-device | ✅ |
| AI Damage Scanner (photo → damage type + severity) | Gemini vision | ☁ |
Every on-device module falls back to a deterministic result rather than an error.
- Offline RAG — 23 verified Bangla chunks across 10 topics, each tagged to a named source (WHO, BDRCS, CDC, MoDMR, IFRC, UNICEF, BMD). Keyword retrieval primary; brute-force cosine over bundled 768-dim L2-normalized fp32 vectors as a second path.
- Voice-first — Bangla STT with locale resolution and failure classification; Bangla TTS (bn-BD, bn-IN fallback), opt-in auto-read.
- Bilingual — Bangla-first with a complete English locale (834 strings) behind a toggle.
- Shelter map — 263 bundled shelter locations, GPS ranking, cached tiles, OSRM turn-by-turn routing, Nominatim/Overpass search. No Google Maps dependency.
- Mesh comms — text, images, video, voice notes and full-duplex 8 kHz voice calls over
nearby_connections(P2P_CLUSTER) with a GMS-free Wi-Fi Direct fallback. Multi-hop SOS relay: LRU dedup over 256 ids, 5-hop cap, 1-hour TTL. - Triage wizard — pure-Dart decision tree to 8 terminal first-aid routes. No model, cannot hallucinate.
- Live hazard feeds — GDACS, NASA EONET, USGS, Open-Meteo weather / marine surge / air quality. All key-less, all fail soft.
- Safety net — 25 quick cards, slide-to-confirm 999 dialer, SOS SMS with GPS, 22-entry offline directory.
- Coordinator panel — Firestore-backed live safe/danger counts, danger list, campaign approval, broadcasts.
git clone https://github.com/Ahnaf181419/shongjog.git
cd shongjog
flutter pub get
# → add android/app/google-services.json (see below) before building
flutter run -d <arm64-device-id> --release| SDK | Flutter 3.x · Dart ^3.12.0 |
| Android | compileSdk 36 · targetSdk 36 · minSdk 26 · Kotlin JVM 17 · AGP 9.x |
| Hardware | Physical arm64-v8a device required for inference |
| Storage | ~3 GB free for the model download |
x86_64 emulators run the UI only. The APK ships arm64 libs exclusively, so every LiteRT-LM call fails on an emulator and the app degrades to corpus answers. Any model-bearing work needs real hardware.
A fresh clone will not compile without this step. android/app/build.gradle.kts applies the com.google.gms.google-services plugin, which needs android/app/google-services.json at build time. That file is gitignored — it is per-developer and never committed.
- Create a Firebase project, add an Android app with applicationId
dev.frostflux.shongjog. - Download
google-services.jsonintoandroid/app/. - Enable Anonymous sign-in (Authentication → Sign-in method).
- Create a Firestore database.
- Paste
firestore.rulesinto Firestore → Rules and publish.
Step 5 is not optional. The rules enforce ownership binding and restrict access to safety reports (which carry name, phone and live GPS). The repo file is the source of truth, but rules deploy from the console — committing them changes nothing until they are pasted.
Firebase powers the coordinator panel and cloud-key delivery only. All init is wrapped in try/catch: with no network, or no Firebase project at all, the app still boots and the entire offline path works.
# Verified release build — this is the supported path
bash scripts/build_release.sh # macOS/Linux
pwsh scripts/build_release.ps1 # WindowsThe script builds, then inspects the resulting APK through 10 gates: LiteRT-LM libs present for arm64, arm64-only ABI, R8 stripped no MediaPipe/protobuf classes, Firebase wired, notification plugin packaged, no API key compiled into libapp.so, POST_NOTIFICATIONS declared, <queries> present for the speech recogniser, TTS, camera and file pickers, and the notification icon surviving resource shrinking.
Those gates exist because each one is a bug that shipped once. A missing <queries> block silently broke four features at once — Android 11 package visibility hides those services without raising an error.
flutter run # UI-only work on an emulator
flutter run -d <device> --release # inference on real hardware
flutter build appbundle --release # Play Store bundleThe release build is currently debug-signed — it sideloads fine but is not Play-uploadable. Add
android/key.propertiesand a release signing config before publishing.
flutter analyze # must report "No issues found!"
flutter test # 878 pass, 1 intentional skip
flutter test test/unit/ # unit only
flutter test test/widget/ # widget only100 test files. Coverage includes WCAG contrast ratios, 1.5× text scaling, Bangla numeral conversion, STT locale resolution, admin layout under stress, mesh path-traversal resistance, mesh link stability, Firestore access control, and the tier-fallback chain.
lib/
├── app/ MaterialApp, routing, theme, MainShell, startup gate
├── core/ singletons — modelManager, connectivity, auth, notifications
├── rag/ PURE DART — retrievers, prompt builder, rumour checker
├── knowledge/ KB loader (corpus.json + vectors.bin)
└── features/ chat · voice · mesh_comm · shelter · triage · safe_beacon
planner · damage_scanner · admin · hazards · weather …
Dependency rule: core/, rag/ and knowledge/ are pure Dart with zero Flutter or plugin imports — fully unit-testable without a device. Adapters wrap plugins and hand plain types inward.
- Engine registration —
FlutterGemma.initialize(inferenceEngines: [LiteRtLmEngine()])must run before any model call.flutter_gemma1.x registers no engine on its own. - Model format —
.litertlmonly. The repo's lone.taskis a web/WASM build the Android runtime cannot open. - Singleton access — go through
modelManager(implementsLocalLlm). Never callFlutterGemma.getActiveModel()from UI code. - Context window —
maxTokensis exactly1024;.litertlmrefuses to allocate tensors below it. Reply cap ismaxOutputTokens: 256. - Session lifecycle — one session per query, closed in a
finally. Native sessions hold a KV cache; leaking them exhausts memory in a handful of questions. - Tier order — on-device Gemma runs first, even when online. Cloud is a fallback, never the primary path.
shelter-shaped query → pure-Dart haversine ranker (microseconds, no model)
↓
TIER 1 Gemma 4 E2B on-device (90s ceiling, falls through on failure)
TIER 2 gemini-3.1-flash-lite → -preview → gemma-4-26b-a4b-it (online only)
TIER 3 verified corpus chunk, verbatim
TIER 4 "call 999"
Tiers 1, 3 and 4 need no network.
The published APK ships with no key compiled in — a --dart-define key is a plaintext literal in libapp.so that one grep recovers from any public download, and Dart obfuscation renames symbols, not string constants. Instead the app fetches a key at launch from Firestore config/cloud_ai (readable by signed-in clients, writable by none) and caches it in Android Keystore via flutter_secure_storage.
Set geminiApiKeys (array) or geminiApiKey (string) on that document. Blanking it revokes the key on every installed device at next launch, with no new release. A build gate fails the release if a key is ever found in the binary.
For local development only, .env / --dart-define=GEMINI_API_KEY=… still works as a last-resort fallback.
| Setting | Source |
|---|---|
| Theme (System/Light/Dark) | lib/core/theme_controller.dart |
| Language (বাংলা / English) | lib/core/locale_controller.dart |
| Model variant | auto by RAM tier — ≤4 GB low, ≤8 GB mid → E2B; >8 GB high → E4B. Overridable in Settings. |
| Mesh media → gallery | opt-in, default off |
| Path | Purpose |
|---|---|
firestore.rules |
Access control — paste into the console to take effect |
scripts/build_release.sh |
Build + 10-gate APK verification |
android/app/proguard-rules.pro |
Load-bearing R8 -keep rules for MediaPipe/Protobuf/ODML |
android/app/src/main/AndroidManifest.xml |
19 permissions + <queries> for speech, TTS, camera, pickers |
assets/kb/corpus.json |
23 verified Bangla chunks, 10 topics |
assets/kb/vectors.bin |
768-dim L2-normalized fp32 vectors |
assets/shelter/cyclone_shelters.geojson |
263 shelter locations |
assets/emergency/directory.json |
22-entry emergency directory |
lib/l10n/app_bn.arb, app_en.arb |
834 EN / 888 BN strings |
training/, eval/ |
LoRA SFT dataset (179 examples) + 50-query eval harness |
Full docs live in docs/ — start at docs/PROJECT-STATUS.md.
docs/architecture.md— technical architecturedocs/design.md— design system, tokens, accessibilitydocs/prd.md— product requirementsdocs/kaggle-writeup.md— hackathon submission writeup
See docs/CONTRIBUTING.md. Conventional commits; flutter analyze clean and the full suite green before pushing.
MIT — see LICENSE.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |



























