Automatic Speech Recognition
LiteRT
litertlm
gemma-4
asr
translation
text-generation
speech-to-text
speech-recognition
multilingual
100-languages
int8
ios
mobile
Instructions to use aoiandroid/bluegemma-ios with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use aoiandroid/bluegemma-ios with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| // | |
| // LlmManager.swift | |
| // TranslateBlue / BlueGemma iOS Voice Session | |
| // | |
| // Created for TranslateBlue Issue #38: iOS Metal GPU Accelerated LLM Engine | |
| // Optimized for Google Gemma 4 E2B-it (LiteRT-LM / MediaPipe Tasks GenAI) | |
| // | |
| import Foundation | |
| import SwiftUI | |
| import MediaPipeTasksGenAI | |
| public class LlmManager: ObservableObject { | |
| public var responseText: String = "" | |
| public var isGenerating: Bool = false | |
| public var isInitialized: Bool = false | |
| public var errorMessage: String? = nil | |
| private var llmInference: LlmInference? | |
| private let modelFileName = "gemma-4-E2B-it-ios" | |
| private let modelExtension = "task" | |
| public init() { | |
| setupEngine() | |
| setupMemoryLifecycleObservers() | |
| } | |
| deinit { | |
| NotificationCenter.default.removeObserver(self) | |
| } | |
| /// Initializes the LiteRT-LM Metal GPU Accelerated Engine with dynamic KV cache quantization. | |
| public func setupEngine() { | |
| guard let modelPath = Bundle.main.path(forResource: modelFileName, ofType: modelExtension) ?? | |
| Bundle.main.path(forResource: "Bluegemma", ofType: "litertlm") else { | |
| let err = "[ERROR] Model file '\(modelFileName).\(modelExtension)' not found in app bundle or document path." | |
| print(err) | |
| self.errorMessage = err | |
| return | |
| } | |
| let options = LlmInference.Options() | |
| options.modelPath = modelPath | |
| options.maxTokens = 512 | |
| options.temperature = 0.7 | |
| options.topK = 40 | |
| // ========================================== | |
| // METAL GPU & ANE MEMORY OPTIMIZATION (iOS) | |
| // ========================================== | |
| // Enable dynamic KV cache quantization to prevent OS Jetsam memory termination | |
| options.kvCacheConfig.enableQuantization = true | |
| do { | |
| self.llmInference = try LlmInference(options: options) | |
| self.isInitialized = true | |
| self.errorMessage = nil | |
| print("[OK] LiteRT-LM Engine initialized with Metal GPU hardware acceleration successfully.") | |
| } catch { | |
| let err = "[FATAL] Failed to initialize LiteRT-LM Metal Engine: \(error.localizedDescription)" | |
| print(err) | |
| self.errorMessage = err | |
| self.isInitialized = false | |
| } | |
| } | |
| /// Asynchronously streams direct translation responses to SwiftUI views. | |
| public func generateTranslationStream(targetLanguage: String, sourceText: String) async { | |
| guard let engine = llmInference else { | |
| self.responseText = "Error: Model engine not loaded." | |
| return | |
| } | |
| self.isGenerating = true | |
| self.responseText = "" | |
| let systemPrompt = "You are a direct professional translator. Output ONLY the translated text in \(targetLanguage). Do not write any intro, greeting, explanation, or options." | |
| let formattedPrompt = "<start_of_turn>system\n\(systemPrompt)<end_of_turn>\n<start_of_turn>user\nTranslate the following sentence into \(targetLanguage): \(sourceText)<end_of_turn>\n<start_of_turn>model\n" | |
| do { | |
| // Execute background inference off the main thread with userInitiated priority | |
| try await Task.detached(priority: .userInitiated) { | |
| autoreleasepool { | |
| try? engine.generateAsync(prompt: formattedPrompt) { [weak self] partialResult, error in | |
| guard let self = self else { return } | |
| if let error = error { | |
| DispatchQueue.main.async { | |
| self.responseText = "Inference Error: \(error.localizedDescription)" | |
| self.isGenerating = false | |
| } | |
| return | |
| } | |
| if let newText = partialResult { | |
| DispatchQueue.main.async { | |
| self.responseText += newText | |
| } | |
| } | |
| } | |
| } | |
| }.value | |
| DispatchQueue.main.async { | |
| self.isGenerating = false | |
| } | |
| } catch { | |
| self.responseText = "Execution Error: \(error.localizedDescription)" | |
| self.isGenerating = false | |
| } | |
| } | |
| /// Registers background/foreground lifecycle notifications to prevent OS Jetsam memory kills. | |
| private func setupMemoryLifecycleObservers() { | |
| #if os(iOS) | |
| NotificationCenter.default.addObserver( | |
| self, | |
| selector: #selector(appDidEnterBackground), | |
| name: UIApplication.didEnterBackgroundNotification, | |
| object: nil | |
| ) | |
| NotificationCenter.default.addObserver( | |
| self, | |
| selector: #selector(appWillEnterForeground), | |
| name: UIApplication.willEnterForegroundNotification, | |
| object: nil | |
| ) | |
| #endif | |
| } | |
| @objc private func appDidEnterBackground() { | |
| print("[INFO] App entered background. Releasing LLM Metal VRAM to prevent OS Jetsam kill...") | |
| releaseMemory() | |
| } | |
| @objc private func appWillEnterForeground() { | |
| print("[INFO] App returned to foreground. Reloading LLM Metal Engine...") | |
| if !isInitialized { | |
| setupEngine() | |
| } | |
| } | |
| /// Instantly releases model reference to free system RAM/VRAM. | |
| public func releaseMemory() { | |
| self.llmInference = nil | |
| self.isInitialized = false | |
| print("[INFO] Model released from RAM/VRAM.") | |
| } | |
| } | |