@capgo/capacitor-llm 7.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Package.swift ADDED
@@ -0,0 +1,32 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapgoLLM",
6
+ platforms: [.iOS(.v14)],
7
+ products: [
8
+ .library(
9
+ name: "CapgoLLM",
10
+ targets: ["LLMPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
14
+ // Note: SwiftTasksVision is for MediaPipe Vision, not GenAI
15
+ // We would need a similar package for MediaPipeTasksGenAI
16
+ // Keeping this as a placeholder for when GenAI SPM support is available
17
+ // .package(url: "https://github.com/paescebu/SwiftTasksVision.git", from: "0.10.21")
18
+ ],
19
+ targets: [
20
+ .target(
21
+ name: "LLMPlugin",
22
+ dependencies: [
23
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
24
+ .product(name: "Cordova", package: "capacitor-swift-pm")
25
+ ],
26
+ path: "ios/Sources/LLMPlugin"),
27
+ .testTarget(
28
+ name: "LLMPluginTests",
29
+ dependencies: ["LLMPlugin"],
30
+ path: "ios/Tests/LLMPluginTests")
31
+ ]
32
+ )
package/README.md ADDED
@@ -0,0 +1,600 @@
1
+ # @capgo/capacitor-llm
2
+
3
+ <a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
4
+
5
+ <div align="center">
6
+ <h2><a href="https://capgo.app/?ref=plugin"> ➡️ Get Instant updates for your App with Capgo 🚀</a></h2>
7
+ <h2><a href="https://capgo.app/consulting/?ref=plugin"> Fix your annoying bug now, Hire a Capacitor expert 💪</a></h2>
8
+ </div>
9
+
10
+ Adds support for LLM locally runned for Capacitor
11
+
12
+ It uses Apple Intelligence (default) or MediaPipe custom models on iOS, and MediaPipe's tasks-genai on Android
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @capgo/capacitor-llm
18
+ npx cap sync
19
+ ```
20
+
21
+ ### iOS Additional Setup for Custom Models
22
+
23
+ If you want to use custom models on iOS (not just Apple Intelligence), you need to install MediaPipe dependencies.
24
+
25
+ **Using CocoaPods:**
26
+ The MediaPipe dependencies are already configured in the podspec. Make sure to run `pod install` after adding the plugin.
27
+
28
+ **Note about Static Framework Warning:**
29
+ When running `pod install`, you may see a warning about transitive dependencies with statically linked binaries. To fix this, update your Podfile:
30
+
31
+ ```ruby
32
+ # Change this:
33
+ use_frameworks!
34
+
35
+ # To this:
36
+ use_frameworks! :linkage => :static
37
+
38
+ # And add this to your post_install hook:
39
+ post_install do |installer|
40
+ assertDeploymentTarget(installer)
41
+
42
+ # Fix for static framework dependencies
43
+ installer.pods_project.targets.each do |target|
44
+ target.build_configurations.each do |config|
45
+ config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
46
+ end
47
+
48
+ # Specifically for MediaPipe pods
49
+ if target.name.include?('MediaPipeTasksGenAI')
50
+ target.build_configurations.each do |config|
51
+ config.build_settings['ENABLE_BITCODE'] = 'NO'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ ```
57
+
58
+ **Using Swift Package Manager:**
59
+ MediaPipe GenAI is currently only available via CocoaPods. SPM support may be added in the future via community packages like SwiftTasksVision.
60
+
61
+ ## Adding a Model to Your App
62
+
63
+ ### iOS
64
+
65
+ On iOS, you have two options:
66
+
67
+ 1. **Apple Intelligence (Default)**: Uses the built-in system model (requires iOS 26.0+) - Recommended
68
+ 2. **Custom Models**: Use your own models via MediaPipe (requires CocoaPods) - Note: Some model formats may have compatibility issues
69
+
70
+ #### Using Apple Intelligence (Default)
71
+
72
+ No additional setup needed. The plugin will automatically use Apple Intelligence on supported devices (iOS 26.0+).
73
+
74
+ #### Using Custom Models on iOS via MediaPipe
75
+
76
+ **⚠️ IMPORTANT**: While MediaPipe documentation states Gemma-2 2B works on all platforms, iOS implementation has compatibility issues with `.task` format models, often resulting in `(prefill_input_names.size() % 2)==(0)` errors.
77
+
78
+ ## Model Compatibility Guide
79
+
80
+ ### Android (Working ✅)
81
+ - **Model**: Gemma-3 models (270M, 1B, etc.)
82
+ - **Format**: `.task` + `.litertlm` files
83
+ - **Where to download**:
84
+ - [Kaggle Gemma models](https://www.kaggle.com/models/google/gemma) - "LiteRT (formerly TFLite)" tab
85
+ - Example: `gemma-3-270m-it-int8.task` + `gemma-3-270m-it-int8.litertlm`
86
+
87
+ ### iOS (Limited Support ⚠️)
88
+ - **Recommended**: Use Apple Intelligence (built-in, no download needed)
89
+ - **Alternative (Experimental)**:
90
+ - **Model**: Gemma-2 2B (documented as compatible but may still fail)
91
+ - **Format**: `.task` files (`.bin` format preferred but not available)
92
+ - **Where to download**:
93
+ - [Hugging Face MediaPipe models](https://huggingface.co/collections/google/mediapipe-668392ead2d6768e82fb3b87)
94
+ - Look for `Gemma2-2B-IT_*_ekv*.task` files
95
+ - Example: `Gemma2-2B-IT_multi-prefill-seq_q8_ekv1280.task`
96
+ - **Note**: Even with Gemma-2 2B, you may still encounter errors. Apple Intelligence is more reliable.
97
+
98
+ ### Web
99
+ - **Model**: Gemma-3 models
100
+ - **Format**: `.task` files
101
+ - **Where to download**: Same as Android
102
+
103
+ ## Download Instructions
104
+
105
+ 1. **For Android**:
106
+ - Go to [Kaggle Gemma models](https://www.kaggle.com/models/google/gemma)
107
+ - Click "LiteRT (formerly TFLite)" tab
108
+ - Download both `.task` and `.litertlm` files
109
+ - Place in `android/app/src/main/assets/`
110
+
111
+ 2. **For iOS** (if not using Apple Intelligence):
112
+ - Visit [Hugging Face MediaPipe collection](https://huggingface.co/collections/google/mediapipe-668392ead2d6768e82fb3b87)
113
+ - Find Gemma-2 2B models
114
+ - Download `.task` files (and `.litertlm` if available)
115
+ - Add to Xcode project in "Copy Bundle Resources"
116
+ - Note: Success is not guaranteed due to format compatibility issues
117
+
118
+ 3. **Set the model path**:
119
+
120
+ ```typescript
121
+ import { CapgoLLM } from '@capgo/capacitor-llm';
122
+
123
+ // iOS - Use Apple Intelligence (default)
124
+ await CapgoLLM.setModel({ path: 'Apple Intelligence' });
125
+
126
+ // iOS - Use MediaPipe model (experimental)
127
+ await CapgoLLM.setModel({
128
+ path: 'Gemma2-2B-IT_multi-prefill-seq_q8_ekv1280',
129
+ modelType: 'task',
130
+ maxTokens: 1280
131
+ });
132
+
133
+ // Now you can create chats and send messages
134
+ const chat = await CapgoLLM.createChat();
135
+ ```
136
+
137
+ ### Android
138
+
139
+ For Android, you need to include a compatible LLM model in your app. The plugin uses MediaPipe's tasks-genai, which supports various model formats.
140
+
141
+ When Gemini mini will be out of close alpha we might add it as default like we do Apple inteligence default
142
+ https://developer.android.com/ai/gemini-nano/experimental
143
+
144
+ **Important:** Your app's `minSdkVersion` must be set to 24 or higher. Update your `android/variables.gradle` file:
145
+ ```gradle
146
+ ext {
147
+ minSdkVersion = 24
148
+ // ... other settings
149
+ }
150
+ ```
151
+
152
+ 1. **Download a compatible model**:
153
+
154
+ **For Android: Gemma 3 Models** (Working ✅)
155
+ - **Recommended**: Gemma 3 270M - Smallest, most efficient (~240-400MB)
156
+ - Text-only model optimized for on-device inference
157
+ - Download from [Kaggle](https://www.kaggle.com/models/google/gemma) → "LiteRT (formerly TFLite)" tab
158
+ - Get both `.task` and `.litertlm` files
159
+
160
+ **For iOS: Limited Options** (⚠️)
161
+ - **Option 1** (Recommended): Use Apple Intelligence - no download needed
162
+ - **Option 2** (Experimental): Try Gemma-2 2B from [Hugging Face](https://huggingface.co/collections/google/mediapipe-668392ead2d6768e82fb3b87)
163
+ - Download `Gemma2-2B-IT_*.task` files
164
+ - May still encounter compatibility errors
165
+
166
+ **Available Model Sizes** (from [Google AI](https://ai.google.dev/gemma/docs/core#sizes)):
167
+ - `gemma-3-270m` - Most portable, text-only (~240-400MB) - Android only
168
+ - `gemma-3-1b` - Larger text-only (~892MB-1.5GB) - Android only
169
+ - `gemma-2-2b` - Cross-platform compatible (~1-2GB) - iOS experimental
170
+ - Larger models available but not recommended for mobile
171
+
172
+ For automated download, see the script in the example app section below.
173
+
174
+ 2. **Add the model to your app**:
175
+
176
+ **Option A - Bundle in APK (for smaller models)**:
177
+ - Place the model files in your app's `android/app/src/main/assets/` directory
178
+ - The `/android_asset/` prefix is used to reference files from the assets folder
179
+ - Note: This approach may increase APK size significantly
180
+
181
+ **Option B - Download at runtime (recommended for production)**:
182
+ - Host the model files on a server
183
+ - Download them to your app's files directory at runtime
184
+ - This keeps your APK size small
185
+
186
+ 3. **Set the model path**:
187
+
188
+ ```typescript
189
+ import { CapgoLLM } from '@capgo/capacitor-llm';
190
+
191
+ // If model is in assets folder (recommended) - point to the .task file
192
+ await CapgoLLM.setModelPath({ path: '/android_asset/gemma-3-270m-it-int8.task' });
193
+
194
+ // If model is in app's files directory
195
+ await CapgoLLM.setModelPath({ path: '/data/data/com.yourapp/files/gemma-3-270m-it-int8.task' });
196
+
197
+ // Example: Download model at runtime (recommended for production)
198
+ async function downloadModel() {
199
+ // Add progress listener
200
+ await CapgoLLM.addListener('downloadProgress', (event) => {
201
+ console.log(`Download progress: ${event.progress}%`);
202
+ });
203
+
204
+ // Download the model
205
+ const result = await CapgoLLM.downloadModel({
206
+ url: 'https://your-server.com/models/gemma-3-270m-it-int8.task',
207
+ companionUrl: 'https://your-server.com/models/gemma-3-270m-it-int8.litertlm', // Android only
208
+ filename: 'gemma-3-270m-it-int8.task' // Optional, defaults to filename from URL
209
+ });
210
+
211
+ console.log('Model downloaded to:', result.path);
212
+ if (result.companionPath) {
213
+ console.log('Companion file downloaded to:', result.companionPath);
214
+ }
215
+
216
+ // Now set the model path
217
+ await CapgoLLM.setModelPath({ path: result.path });
218
+ }
219
+
220
+ // Now you can create chats and send messages
221
+ const chat = await CapgoLLM.createChat();
222
+ ```
223
+
224
+ ## Usage Example
225
+
226
+ ```typescript
227
+ import { CapgoLLM } from '@capgo/capacitor-llm';
228
+
229
+ // Check if LLM is ready
230
+ const { readiness } = await CapgoLLM.getReadiness();
231
+ console.log('LLM readiness:', readiness);
232
+
233
+ // Set a custom model (optional - uses system default if not called)
234
+ // iOS: Use a GGUF model from bundle or path
235
+ // Android: Use a MediaPipe model from assets or files
236
+ await CapgoLLM.setModelPath({
237
+ path: Platform.isIOS ? 'gemma-3-270m.gguf' : '/android_asset/gemma-3-270m-it-int8.task'
238
+ });
239
+
240
+ // Create a chat session
241
+ const { id: chatId } = await CapgoLLM.createChat();
242
+
243
+ // Listen for AI responses
244
+ CapgoLLM.addListener('textFromAi', (event) => {
245
+ console.log('AI:', event.text);
246
+ });
247
+
248
+ // Listen for completion
249
+ CapgoLLM.addListener('aiFinished', (event) => {
250
+ console.log('AI finished responding to chat:', event.chatId);
251
+ });
252
+
253
+ // Send a message
254
+ await CapgoLLM.sendMessage({
255
+ chatId,
256
+ message: 'Hello! How are you today?'
257
+ });
258
+ ```
259
+
260
+ ## API
261
+
262
+ <docgen-index>
263
+
264
+ * [`createChat()`](#createchat)
265
+ * [`sendMessage(...)`](#sendmessage)
266
+ * [`getReadiness()`](#getreadiness)
267
+ * [`setModel(...)`](#setmodel)
268
+ * [`downloadModel(...)`](#downloadmodel)
269
+ * [`addListener('textFromAi', ...)`](#addlistenertextfromai-)
270
+ * [`addListener('aiFinished', ...)`](#addlisteneraifinished-)
271
+ * [`addListener('downloadProgress', ...)`](#addlistenerdownloadprogress-)
272
+ * [`addListener('readinessChange', ...)`](#addlistenerreadinesschange-)
273
+ * [Interfaces](#interfaces)
274
+
275
+ </docgen-index>
276
+
277
+ <docgen-api>
278
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
279
+
280
+ LLM Plugin interface for interacting with on-device language models
281
+
282
+ ### createChat()
283
+
284
+ ```typescript
285
+ createChat() => Promise<{ id: string; instructions?: string; }>
286
+ ```
287
+
288
+ Creates a new chat session
289
+
290
+ **Returns:** <code>Promise&lt;{ id: string; instructions?: string; }&gt;</code>
291
+
292
+ --------------------
293
+
294
+
295
+ ### sendMessage(...)
296
+
297
+ ```typescript
298
+ sendMessage(options: { chatId: string; message: string; }) => Promise<void>
299
+ ```
300
+
301
+ Sends a message to the AI in a specific chat session
302
+
303
+ | Param | Type | Description |
304
+ | ------------- | ------------------------------------------------- | --------------------------------- |
305
+ | **`options`** | <code>{ chatId: string; message: string; }</code> | - The chat id and message to send |
306
+
307
+ --------------------
308
+
309
+
310
+ ### getReadiness()
311
+
312
+ ```typescript
313
+ getReadiness() => Promise<{ readiness: string; }>
314
+ ```
315
+
316
+ Gets the readiness status of the LLM
317
+
318
+ **Returns:** <code>Promise&lt;{ readiness: string; }&gt;</code>
319
+
320
+ --------------------
321
+
322
+
323
+ ### setModel(...)
324
+
325
+ ```typescript
326
+ setModel(options: ModelOptions) => Promise<void>
327
+ ```
328
+
329
+ Sets the model configuration
330
+ - iOS: Use "Apple Intelligence" as path for system model, or provide path to MediaPipe model
331
+ - Android: Path to a MediaPipe model file (in assets or files directory)
332
+
333
+ | Param | Type | Description |
334
+ | ------------- | ----------------------------------------------------- | ------------------------- |
335
+ | **`options`** | <code><a href="#modeloptions">ModelOptions</a></code> | - The model configuration |
336
+
337
+ --------------------
338
+
339
+
340
+ ### downloadModel(...)
341
+
342
+ ```typescript
343
+ downloadModel(options: DownloadModelOptions) => Promise<DownloadModelResult>
344
+ ```
345
+
346
+ Downloads a model from a URL and saves it to the appropriate location
347
+ - iOS: Downloads to the app's documents directory
348
+ - Android: Downloads to the app's files directory
349
+
350
+ | Param | Type | Description |
351
+ | ------------- | --------------------------------------------------------------------- | ---------------------------- |
352
+ | **`options`** | <code><a href="#downloadmodeloptions">DownloadModelOptions</a></code> | - The download configuration |
353
+
354
+ **Returns:** <code>Promise&lt;<a href="#downloadmodelresult">DownloadModelResult</a>&gt;</code>
355
+
356
+ --------------------
357
+
358
+
359
+ ### addListener('textFromAi', ...)
360
+
361
+ ```typescript
362
+ addListener(eventName: 'textFromAi', listenerFunc: (event: TextFromAiEvent) => void) => Promise<{ remove: () => Promise<void>; }>
363
+ ```
364
+
365
+ Adds a listener for text received from AI
366
+
367
+ | Param | Type | Description |
368
+ | ------------------ | ------------------------------------------------------------------------------- | ----------------------------------- |
369
+ | **`eventName`** | <code>'textFromAi'</code> | - Event name 'textFromAi' |
370
+ | **`listenerFunc`** | <code>(event: <a href="#textfromaievent">TextFromAiEvent</a>) =&gt; void</code> | - Callback function for text events |
371
+
372
+ **Returns:** <code>Promise&lt;{ remove: () =&gt; Promise&lt;void&gt;; }&gt;</code>
373
+
374
+ --------------------
375
+
376
+
377
+ ### addListener('aiFinished', ...)
378
+
379
+ ```typescript
380
+ addListener(eventName: 'aiFinished', listenerFunc: (event: AiFinishedEvent) => void) => Promise<{ remove: () => Promise<void>; }>
381
+ ```
382
+
383
+ Adds a listener for AI completion events
384
+
385
+ | Param | Type | Description |
386
+ | ------------------ | ------------------------------------------------------------------------------- | ------------------------------------- |
387
+ | **`eventName`** | <code>'aiFinished'</code> | - Event name 'aiFinished' |
388
+ | **`listenerFunc`** | <code>(event: <a href="#aifinishedevent">AiFinishedEvent</a>) =&gt; void</code> | - Callback function for finish events |
389
+
390
+ **Returns:** <code>Promise&lt;{ remove: () =&gt; Promise&lt;void&gt;; }&gt;</code>
391
+
392
+ --------------------
393
+
394
+
395
+ ### addListener('downloadProgress', ...)
396
+
397
+ ```typescript
398
+ addListener(eventName: 'downloadProgress', listenerFunc: (event: DownloadProgressEvent) => void) => Promise<{ remove: () => Promise<void>; }>
399
+ ```
400
+
401
+ Adds a listener for model download progress events
402
+
403
+ | Param | Type | Description |
404
+ | ------------------ | ------------------------------------------------------------------------------------------- | --------------------------------------- |
405
+ | **`eventName`** | <code>'downloadProgress'</code> | - Event name 'downloadProgress' |
406
+ | **`listenerFunc`** | <code>(event: <a href="#downloadprogressevent">DownloadProgressEvent</a>) =&gt; void</code> | - Callback function for progress events |
407
+
408
+ **Returns:** <code>Promise&lt;{ remove: () =&gt; Promise&lt;void&gt;; }&gt;</code>
409
+
410
+ --------------------
411
+
412
+
413
+ ### addListener('readinessChange', ...)
414
+
415
+ ```typescript
416
+ addListener(eventName: 'readinessChange', listenerFunc: (event: ReadinessChangeEvent) => void) => Promise<{ remove: () => Promise<void>; }>
417
+ ```
418
+
419
+ Adds a listener for readiness status changes
420
+
421
+ | Param | Type | Description |
422
+ | ------------------ | ----------------------------------------------------------------------------------------- | ---------------------------------------- |
423
+ | **`eventName`** | <code>'readinessChange'</code> | - Event name 'readinessChange' |
424
+ | **`listenerFunc`** | <code>(event: <a href="#readinesschangeevent">ReadinessChangeEvent</a>) =&gt; void</code> | - Callback function for readiness events |
425
+
426
+ **Returns:** <code>Promise&lt;{ remove: () =&gt; Promise&lt;void&gt;; }&gt;</code>
427
+
428
+ --------------------
429
+
430
+
431
+ ### Interfaces
432
+
433
+
434
+ #### ModelOptions
435
+
436
+ Model configuration options
437
+
438
+ | Prop | Type | Description |
439
+ | ----------------- | ------------------- | ---------------------------------------------------------------------------------------------------------- |
440
+ | **`path`** | <code>string</code> | Model path or "Apple Intelligence" for iOS system model |
441
+ | **`modelType`** | <code>string</code> | Model file type/extension (e.g., "task", "bin", "litertlm"). If not provided, will be extracted from path. |
442
+ | **`maxTokens`** | <code>number</code> | Maximum number of tokens the model handles |
443
+ | **`topk`** | <code>number</code> | Number of tokens the model considers at each step |
444
+ | **`temperature`** | <code>number</code> | Amount of randomness in generation (0.0-1.0) |
445
+ | **`randomSeed`** | <code>number</code> | Random seed for generation |
446
+
447
+
448
+ #### DownloadModelResult
449
+
450
+ Result of model download
451
+
452
+ | Prop | Type | Description |
453
+ | ------------------- | ------------------- | ------------------------------------------------------- |
454
+ | **`path`** | <code>string</code> | Path where the model was saved |
455
+ | **`companionPath`** | <code>string</code> | Path where the companion file was saved (if applicable) |
456
+
457
+
458
+ #### DownloadModelOptions
459
+
460
+ Options for downloading a model
461
+
462
+ | Prop | Type | Description |
463
+ | ------------------ | ------------------- | ------------------------------------------------------------- |
464
+ | **`url`** | <code>string</code> | URL of the model file to download |
465
+ | **`companionUrl`** | <code>string</code> | Optional: URL of companion file (e.g., .litertlm for Android) |
466
+ | **`filename`** | <code>string</code> | Optional: Custom filename (defaults to filename from URL) |
467
+
468
+
469
+ #### TextFromAiEvent
470
+
471
+ Event data for text received from AI
472
+
473
+ | Prop | Type | Description |
474
+ | ------------- | -------------------- | -------------------------------------------------------------------------- |
475
+ | **`text`** | <code>string</code> | The text content from AI - this is an incremental chunk, not the full text |
476
+ | **`chatId`** | <code>string</code> | The chat session ID |
477
+ | **`isChunk`** | <code>boolean</code> | Whether this is a complete chunk (true) or partial streaming data (false) |
478
+
479
+
480
+ #### AiFinishedEvent
481
+
482
+ Event data for AI completion
483
+
484
+ | Prop | Type | Description |
485
+ | ------------ | ------------------- | --------------------------------- |
486
+ | **`chatId`** | <code>string</code> | The chat session ID that finished |
487
+
488
+
489
+ #### DownloadProgressEvent
490
+
491
+ Event data for download progress
492
+
493
+ | Prop | Type | Description |
494
+ | --------------------- | ------------------- | ---------------------------------------- |
495
+ | **`progress`** | <code>number</code> | Percentage of download completed (0-100) |
496
+ | **`totalBytes`** | <code>number</code> | Total bytes to download |
497
+ | **`downloadedBytes`** | <code>number</code> | Bytes downloaded so far |
498
+
499
+
500
+ #### ReadinessChangeEvent
501
+
502
+ Event data for readiness status changes
503
+
504
+ | Prop | Type | Description |
505
+ | --------------- | ------------------- | -------------------- |
506
+ | **`readiness`** | <code>string</code> | The readiness status |
507
+
508
+ </docgen-api>
509
+
510
+ ## Example App Model Setup
511
+
512
+ The example app demonstrates how to use custom models with the Capacitor LLM plugin.
513
+
514
+ ### Downloading Models
515
+
516
+ Since AI models require license acceptance, you need to download them manually:
517
+
518
+ ### Model Setup by Platform
519
+
520
+ #### Android Setup (Gemma 3 270M) ✅
521
+
522
+ 1. **Create Kaggle account and accept license:**
523
+ - Create a [Kaggle account](https://www.kaggle.com)
524
+ - Visit [Gemma 3 models](https://www.kaggle.com/models/google/gemma-3) and accept terms
525
+
526
+ 2. **Download the model:**
527
+ - Click "LiteRT (formerly TFLite)" tab
528
+ - Download `gemma-3-270m-it-int8` (get BOTH files):
529
+ - `gemma-3-270m-it-int8.task`
530
+ - `gemma-3-270m-it-int8.litertlm`
531
+
532
+ 3. **Place in Android app:**
533
+ - Copy BOTH files to: `example-app/android/app/src/main/assets/`
534
+ - In code, reference with `/android_asset/` prefix
535
+
536
+ #### iOS Setup ⚠️
537
+
538
+ **Option 1 (Recommended)**: Use Apple Intelligence
539
+ - No model download needed
540
+ - Works out of the box on iOS 26.0+
541
+
542
+ **Option 2 (Experimental)**: Try Gemma-2 2B
543
+ 1. Visit [Hugging Face MediaPipe models](https://huggingface.co/collections/google/mediapipe-668392ead2d6768e82fb3b87)
544
+ 2. Download Gemma-2 2B files (e.g., `Gemma2-2B-IT_multi-prefill-seq_q8_ekv1280.task`)
545
+ 3. Add to Xcode project in "Copy Bundle Resources"
546
+ 4. Note: May still encounter errors - Apple Intelligence is more reliable
547
+ ### Update your code to use the model:
548
+ ```typescript
549
+ // Android - Gemma 3 270M
550
+ await CapgoLLM.setModel({
551
+ path: '/android_asset/gemma-3-270m-it-int8.task',
552
+ maxTokens: 2048,
553
+ topk: 40,
554
+ temperature: 0.8
555
+ });
556
+
557
+ // iOS Option 1 - Apple Intelligence (Recommended)
558
+ await CapgoLLM.setModel({
559
+ path: 'Apple Intelligence'
560
+ });
561
+
562
+ // iOS Option 2 - Gemma-2 2B (Experimental)
563
+ await CapgoLLM.setModel({
564
+ path: 'Gemma2-2B-IT_multi-prefill-seq_q8_ekv1280',
565
+ modelType: 'task',
566
+ maxTokens: 1280,
567
+ topk: 40,
568
+ temperature: 0.8
569
+ });
570
+ ```
571
+
572
+ ### Model Selection Guide
573
+
574
+ **For Android**: Gemma 3 270M is recommended because:
575
+ - Smallest size (~240-400MB)
576
+ - Text-only (perfect for chat)
577
+ - Optimized for mobile devices
578
+ - Works reliably with MediaPipe
579
+
580
+ **For iOS**: Apple Intelligence is recommended because:
581
+ - No download required
582
+ - Native iOS integration
583
+ - Better performance
584
+ - No compatibility issues
585
+
586
+ ## Known Issues
587
+
588
+ - **iOS MediaPipe Compatibility**: MediaPipe iOS SDK has issues with `.task` format models
589
+ - Symptom: `(prefill_input_names.size() % 2)==(0)` errors
590
+ - Solution: Use Apple Intelligence (built-in) instead of custom models
591
+ - Alternative: Try Gemma-2 2B models (experimental, may still fail)
592
+
593
+ - **Platform Requirements**:
594
+ - iOS: Apple Intelligence requires iOS 26.0+
595
+ - Android: Minimum SDK 24
596
+
597
+ - **Performance Considerations**:
598
+ - Model files are large (300MB-2GB)
599
+ - Initial download takes time
600
+ - Some devices may have memory limitations
@@ -0,0 +1,59 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.7.2'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace "ee.forgr.capgo_llm"
22
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ }
49
+
50
+
51
+ dependencies {
52
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
53
+ implementation project(':capacitor-android')
54
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
+ implementation 'com.google.mediapipe:tasks-genai:0.10.24'
56
+ testImplementation "junit:junit:$junitVersion"
57
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
58
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
59
+ }