Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Sunflower

On-device translation, transcription, and speech Q&A for ten Ugandan languages (Luganda, Acholi, Ateso, Lugbara, Runyankole, Lusoga, Lumasaba, Swahili, Kinyarwanda, English). Runs a fine-tuned Gemma 4 E2B (Sunbird AI) — and optionally a Whisper-based ASR cascade — under [Cactus](https://github.com/cactus-compute/cactus)'s ARM-optimized engine. Android-first; offline.
On-device translation, transcription, and speech Q&A for ten Ugandan languages (Luganda, Acholi, Ateso, Lugbara, Runyankole, Lusoga, Lumasaba, Swahili, Kinyarwanda, English). Runs a fine-tuned Gemma 4 E2B (Sunbird AI) — and optionally a Whisper-based ASR cascade — under [Cactus](https://github.com/cactus-compute/cactus)'s ARM-optimized engine. Android & iOS; offline.

For the architecture, threading model, and Cactus FFI contract, see [design-spec.md](./design-spec.md).
For card-stack UI behaviour, see [card_spec.md](./card_spec.md).

## Run

Requirements: flagship Android device (Pixel 7+ / S22+), Flutter 3.11+, Android NDK r27.x, USB debugging.
Requirements: flagship Android (Pixel 7+ / S22+) or iOS device (iPhone 13+), Flutter 3.11+, macOS/Xcode (for iOS), Android NDK r27.x (for Android).

```bash
git clone git@github.com:SunbirdAI/sunflower-app.git
Expand All @@ -16,6 +16,13 @@ flutter pub get
flutter run
```

For iOS, ensure you have CocoaPods installed:

```bash
cd ios && pod install && cd ..
flutter run
```

The model isn't bundled (~4.7 GB INT4). On first launch the app shows "Get the model" — open the gear icon, tap Download. The tarball streams from HuggingFace into the app's private documents directory.

For dev pushes from Mac (faster than the in-app download):
Expand Down Expand Up @@ -104,6 +111,7 @@ scripts/
└── export_stitched.sh Whisper + Gemma dual-convert for the stitched bundle
test/ chips, conversation_state, classroom_prompt
android/app/src/main/jniLibs/arm64-v8a/libcactus.so
ios/cactus-ios.xcframework iOS native engine framework
```

## How to
Expand Down Expand Up @@ -185,7 +193,9 @@ cp flutter/cactus.dart /path/to/sunflower-app/lib/cactus.dart
# then re-convert the model with the same vX.Y and re-upload to HF
```

### Build a release APK
### Build a release

#### Android (APK)

```bash
flutter build apk --release
Expand All @@ -194,6 +204,15 @@ flutter build apk --release

The APK is signed with the Flutter debug key by default. Set up release signing in `android/app/build.gradle.kts` before distributing.

#### iOS (IPA)

```bash
flutter build ios --release
```

Open `ios/Runner.xcworkspace` in Xcode to configure signing and capabilities (Microphone access is already in `Info.plist`).


### Run tests

```bash
Expand Down
34 changes: 34 additions & 0 deletions ios/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*

# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
24 changes: 24 additions & 0 deletions ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>
2 changes: 2 additions & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
2 changes: 2 additions & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
38 changes: 38 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
platform :ios, '16.0'
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks! :linkage => :static
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
61 changes: 61 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
PODS:
- audioplayers_darwin (0.0.1):
- Flutter
- FlutterMacOS
- Flutter (1.0.0)
- flutter_foreground_task (0.0.1):
- Flutter
- flutter_onnxruntime (0.0.1):
- Flutter
- onnxruntime-objc (= 1.22.0)
- onnxruntime-c (1.22.0)
- onnxruntime-objc (1.22.0):
- onnxruntime-objc/Core (= 1.22.0)
- onnxruntime-objc/Core (1.22.0):
- onnxruntime-c (= 1.22.0)
- record_ios (1.2.0):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS

DEPENDENCIES:
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`)
- Flutter (from `Flutter`)
- flutter_foreground_task (from `.symlinks/plugins/flutter_foreground_task/ios`)
- flutter_onnxruntime (from `.symlinks/plugins/flutter_onnxruntime/ios`)
- record_ios (from `.symlinks/plugins/record_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)

SPEC REPOS:
trunk:
- onnxruntime-c
- onnxruntime-objc

EXTERNAL SOURCES:
audioplayers_darwin:
:path: ".symlinks/plugins/audioplayers_darwin/darwin"
Flutter:
:path: Flutter
flutter_foreground_task:
:path: ".symlinks/plugins/flutter_foreground_task/ios"
flutter_onnxruntime:
:path: ".symlinks/plugins/flutter_onnxruntime/ios"
record_ios:
:path: ".symlinks/plugins/record_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"

SPEC CHECKSUMS:
audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_foreground_task: a159d2c2173b33699ddb3e6c2a067045d7cebb89
flutter_onnxruntime: 515c2ab17b67fb027964ebbf2d02329771a482de
onnxruntime-c: 7f778680e96145956c0a31945f260321eed2611a
onnxruntime-objc: 83d28b87525bd971259a66e153ea32b5d023de19
record_ios: 412daca2350b228e698fffcd08f1f94ceb1e3844
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb

PODFILE CHECKSUM: 93e78d9efba2e1946f2eddcc1dd4ffef6df21e1a

COCOAPODS: 1.16.2
Loading