@capgo/capacitor-llm 8.1.0 → 8.1.1

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/README.md CHANGED
@@ -380,14 +380,15 @@ Get the native Capacitor plugin version.
380
380
  Model configuration options
381
381
  Only `path` is required. All other properties are optional overrides.
382
382
 
383
- | Prop | Type | Description |
384
- | ----------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
385
- | **`path`** | <code>string</code> | Model path, "Apple Intelligence" for the Apple system model on iOS, or "Gemini Nano" for the Android AICore system model when already available on the device. On iOS, custom `.litertlm` models require the plugin to be integrated through Swift Package Manager. Gemma 4 examples use `.litertlm` on mobile and `*-web.task` on web. |
386
- | **`modelType`** | <code>string</code> | Optional. Model file type/extension (for example `task`, `bin`, `litertlm`, or `gemini-nano`). If not provided, it is extracted from the path. Use `litertlm` on iOS only in SwiftPM integrations. |
387
- | **`maxTokens`** | <code>number</code> | Maximum number of tokens the model handles |
388
- | **`topk`** | <code>number</code> | Number of tokens the model considers at each step |
389
- | **`temperature`** | <code>number</code> | Amount of randomness in generation (0.0-1.0) |
390
- | **`randomSeed`** | <code>number</code> | Optional. Random seed for generation. |
383
+ | Prop | Type | Description | Since |
384
+ | ----------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
385
+ | **`path`** | <code>string</code> | Model path, "Apple Intelligence" for the Apple system model on iOS, or "Gemini Nano" for the Android AICore system model when already available on the device. On iOS, custom `.litertlm` models require the plugin to be integrated through Swift Package Manager. Gemma 4 examples use `.litertlm` on mobile and `*-web.task` on web. | |
386
+ | **`modelType`** | <code>string</code> | Optional. Model file type/extension (for example `task`, `bin`, `litertlm`, or `gemini-nano`). If not provided, it is extracted from the path. Use `litertlm` on iOS only in SwiftPM integrations. | |
387
+ | **`maxTokens`** | <code>number</code> | Maximum number of tokens the model handles | |
388
+ | **`topk`** | <code>number</code> | Number of tokens the model considers at each step | |
389
+ | **`temperature`** | <code>number</code> | Amount of randomness in generation (0.0-1.0) | |
390
+ | **`randomSeed`** | <code>number</code> | Optional. Random seed for generation. | |
391
+ | **`backend`** | <code>'gpu' \| 'cpu'</code> | Optional. LiteRT-LM engine backend for iOS (SwiftPM) and Android. Use `cpu` for stable long generations. When omitted, iOS prefers CPU then falls back to GPU; Android uses CPU. | 8.2.0 |
391
392
 
392
393
 
393
394
  #### DownloadModelResult
@@ -84,9 +84,10 @@ public class LLM {
84
84
  Integer topk,
85
85
  Float temperature,
86
86
  Integer randomSeed,
87
+ String backend,
87
88
  ModelLoadCallback callback
88
89
  ) {
89
- ModelLoadRequest request = nextLoadRequest(path, modelType, maxTokens, topk, temperature, randomSeed);
90
+ ModelLoadRequest request = nextLoadRequest(path, modelType, maxTokens, topk, temperature, randomSeed, backend);
90
91
  resetModelState();
91
92
 
92
93
  android.util.Log.d(
@@ -111,10 +112,11 @@ public class LLM {
111
112
  Integer maxTokens,
112
113
  Integer topk,
113
114
  Float temperature,
114
- Integer randomSeed
115
+ Integer randomSeed,
116
+ String backend
115
117
  ) {
116
118
  currentLoadId += 1;
117
- return new ModelLoadRequest(path, modelType, maxTokens, topk, temperature, randomSeed, currentLoadId);
119
+ return new ModelLoadRequest(path, modelType, maxTokens, topk, temperature, randomSeed, backend, currentLoadId);
118
120
  }
119
121
 
120
122
  private synchronized boolean isCurrentLoad(long loadId) {
@@ -210,11 +212,12 @@ public class LLM {
210
212
  }
211
213
 
212
214
  private Engine initializeLiteRtModel(String actualPath, ModelLoadRequest request) {
215
+ Backend primaryBackend = resolveLiteRtBackend(request.backend);
213
216
  EngineConfig config = new EngineConfig(
214
217
  actualPath,
215
- new Backend.CPU(),
216
- new Backend.CPU(),
217
- new Backend.CPU(),
218
+ primaryBackend,
219
+ primaryBackend,
220
+ primaryBackend,
218
221
  request.maxTokens,
219
222
  context.getCacheDir().getAbsolutePath()
220
223
  );
@@ -223,6 +226,14 @@ public class LLM {
223
226
  return loadedEngine;
224
227
  }
225
228
 
229
+ private Backend resolveLiteRtBackend(String backend) {
230
+ if (backend != null && "gpu".equalsIgnoreCase(backend.trim())) {
231
+ return new Backend.GPU();
232
+ }
233
+
234
+ return new Backend.CPU();
235
+ }
236
+
226
237
  private LlmInference initializeMediaPipeModel(String actualPath, ModelLoadRequest request) {
227
238
  LlmInferenceOptions options = LlmInferenceOptions.builder()
228
239
  .setModelPath(actualPath)
@@ -820,6 +831,7 @@ public class LLM {
820
831
  private final Integer topk;
821
832
  private final Float temperature;
822
833
  private final Integer randomSeed;
834
+ private final String backend;
823
835
  private final long loadId;
824
836
 
825
837
  private ModelLoadRequest(
@@ -829,6 +841,7 @@ public class LLM {
829
841
  Integer topk,
830
842
  Float temperature,
831
843
  Integer randomSeed,
844
+ String backend,
832
845
  long loadId
833
846
  ) {
834
847
  this.modelPath = modelPath;
@@ -837,6 +850,7 @@ public class LLM {
837
850
  this.topk = topk;
838
851
  this.temperature = temperature;
839
852
  this.randomSeed = randomSeed;
853
+ this.backend = backend;
840
854
  this.loadId = loadId;
841
855
  }
842
856
  }
@@ -9,7 +9,7 @@ import com.getcapacitor.annotation.CapacitorPlugin;
9
9
  @CapacitorPlugin(name = "CapgoLLM")
10
10
  public class LLMPlugin extends Plugin {
11
11
 
12
- private final String pluginVersion = "8.1.0";
12
+ private final String pluginVersion = "8.1.1";
13
13
 
14
14
  private LLM llm;
15
15
 
@@ -106,6 +106,7 @@ public class LLMPlugin extends Plugin {
106
106
  Float temperature = call.getFloat("temperature", 0.8f);
107
107
  Integer randomSeed = call.getInt("randomSeed", 0);
108
108
  String modelType = call.getString("modelType");
109
+ String backend = call.getString("backend");
109
110
 
110
111
  llm.setModel(
111
112
  path,
@@ -114,6 +115,7 @@ public class LLMPlugin extends Plugin {
114
115
  topk,
115
116
  temperature,
116
117
  randomSeed,
118
+ backend,
117
119
  new LLM.ModelLoadCallback() {
118
120
  @Override
119
121
  public void onSuccess() {
package/dist/docs.json CHANGED
@@ -374,6 +374,18 @@
374
374
  "docs": "Optional. Random seed for generation.",
375
375
  "complexTypes": [],
376
376
  "type": "number | undefined"
377
+ },
378
+ {
379
+ "name": "backend",
380
+ "tags": [
381
+ {
382
+ "text": "8.2.0",
383
+ "name": "since"
384
+ }
385
+ ],
386
+ "docs": "Optional. LiteRT-LM engine backend for iOS (SwiftPM) and Android.\nUse `cpu` for stable long generations. When omitted, iOS prefers CPU then falls back to GPU; Android uses CPU.",
387
+ "complexTypes": [],
388
+ "type": "'gpu' | 'cpu' | undefined"
377
389
  }
378
390
  ]
379
391
  },
@@ -188,4 +188,10 @@ export interface ModelOptions {
188
188
  temperature?: number;
189
189
  /** Optional. Random seed for generation. */
190
190
  randomSeed?: number;
191
+ /**
192
+ * Optional. LiteRT-LM engine backend for iOS (SwiftPM) and Android.
193
+ * Use `cpu` for stable long generations. When omitted, iOS prefers CPU then falls back to GPU; Android uses CPU.
194
+ * @since 8.2.0
195
+ */
196
+ backend?: 'gpu' | 'cpu';
191
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * LLM Plugin interface for interacting with on-device language models\n */\nexport interface LLMPlugin {\n /**\n * Creates a new chat session\n * @returns Promise with chat id and optional instructions\n */\n createChat(): Promise<{ id: string; instructions?: string }>;\n\n /**\n * Sends a message to the AI in a specific chat session\n * @param options - The chat id and message to send\n * @returns Promise that resolves when message is sent\n */\n sendMessage(options: { chatId: string; message: string }): Promise<void>;\n\n /**\n * Gets the readiness status of the LLM\n * @returns Promise with readiness status string\n */\n getReadiness(): Promise<{ readiness: string }>;\n\n /**\n * Sets the model configuration\n * - iOS: Use \"Apple Intelligence\" as path for the system model. Custom LiteRT-LM `.litertlm` models are supported on iOS only when this plugin is integrated through Swift Package Manager.\n * - Android: Use \"Gemini Nano\" for the AICore system model on supported devices where it is already available. Prefer LiteRT-LM `.litertlm` bundles for custom models; legacy MediaPipe `.task` models are still supported\n * - Web: Provide a web-ready model asset for `@mediapipe/tasks-genai` such as Gemma 4 `*-web.task`\n * @param options - The model configuration\n * @returns Promise that resolves when model is loaded\n */\n setModel(options: ModelOptions): Promise<void>;\n\n /**\n * Downloads a model from a URL and saves it to the appropriate location\n * - iOS: Downloads to the app's documents directory\n * - Android: Downloads to the app's files directory\n * @param options - The download configuration\n * @returns Promise with download result including the saved path\n */\n downloadModel(options: DownloadModelOptions): Promise<DownloadModelResult>;\n\n /**\n * Adds a listener for text received from AI\n * @param eventName - Event name 'textFromAi'\n * @param listenerFunc - Callback function for text events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'textFromAi',\n listenerFunc: (event: TextFromAiEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for AI completion events\n * @param eventName - Event name 'aiFinished'\n * @param listenerFunc - Callback function for finish events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'aiFinished',\n listenerFunc: (event: AiFinishedEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for generation failures that happen after streaming starts\n * @param eventName - Event name 'generationError'\n * @param listenerFunc - Callback function for generation errors\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'generationError',\n listenerFunc: (event: GenerationErrorEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for model download progress events\n * @param eventName - Event name 'downloadProgress'\n * @param listenerFunc - Callback function for progress events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'downloadProgress',\n listenerFunc: (event: DownloadProgressEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for readiness status changes\n * @param eventName - Event name 'readinessChange'\n * @param listenerFunc - Callback function for readiness events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'readinessChange',\n listenerFunc: (event: ReadinessChangeEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * @returns Promise that resolves with the plugin version\n * @throws Error if getting the version fails\n * @since 1.0.0\n * @example\n * ```typescript\n * const { version } = await CapgoLLM.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n\n/**\n * Event data for text received from AI\n */\nexport interface TextFromAiEvent {\n /** The text content from AI - this is an incremental chunk, not the full text */\n text: string;\n /** The chat session ID */\n chatId: string;\n /** Whether this is a complete chunk (true) or partial streaming data (false) */\n isChunk?: boolean;\n}\n\n/**\n * Event data for AI completion\n */\nexport interface AiFinishedEvent {\n /** The chat session ID that finished */\n chatId: string;\n}\n\n/**\n * Event data for generation failures\n * `chatId` is optional and may be omitted when the failure is not tied to a specific chat.\n */\nexport interface GenerationErrorEvent {\n /** Optional. The chat session ID that failed, when available. */\n chatId?: string;\n /** Error message describing the failure */\n error: string;\n}\n\n/**\n * Options for downloading a model\n * Only `url` is required. `companionUrl` and `filename` are optional.\n */\nexport interface DownloadModelOptions {\n /** URL of the model file to download */\n url: string;\n /** Optional: URL of a companion file for legacy model formats */\n companionUrl?: string;\n /** Optional: Custom filename (defaults to filename from URL) */\n filename?: string;\n}\n\n/**\n * Result of model download\n */\nexport interface DownloadModelResult {\n /** Path where the model was saved */\n path: string;\n /** Path where the companion file was saved (if applicable) */\n companionPath?: string;\n}\n\n/**\n * Event data for download progress\n */\nexport interface DownloadProgressEvent {\n /** Percentage of download completed (0-100) */\n progress: number;\n /** Total bytes to download */\n totalBytes?: number;\n /** Bytes downloaded so far */\n downloadedBytes?: number;\n}\n\n/**\n * Event data for readiness status changes\n */\nexport interface ReadinessChangeEvent {\n /** The readiness status */\n readiness: string;\n}\n\n/**\n * Model configuration options\n * Only `path` is required. All other properties are optional overrides.\n */\nexport interface ModelOptions {\n /** Model path, \"Apple Intelligence\" for the Apple system model on iOS, or \"Gemini Nano\" for the Android AICore system model when already available on the device. On iOS, custom `.litertlm` models require the plugin to be integrated through Swift Package Manager. Gemma 4 examples use `.litertlm` on mobile and `*-web.task` on web. */\n path: string;\n /** Optional. Model file type/extension (for example `task`, `bin`, `litertlm`, or `gemini-nano`). If not provided, it is extracted from the path. Use `litertlm` on iOS only in SwiftPM integrations. */\n modelType?: string;\n /** Maximum number of tokens the model handles */\n maxTokens?: number;\n /** Number of tokens the model considers at each step */\n topk?: number;\n /** Amount of randomness in generation (0.0-1.0) */\n temperature?: number;\n /** Optional. Random seed for generation. */\n randomSeed?: number;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * LLM Plugin interface for interacting with on-device language models\n */\nexport interface LLMPlugin {\n /**\n * Creates a new chat session\n * @returns Promise with chat id and optional instructions\n */\n createChat(): Promise<{ id: string; instructions?: string }>;\n\n /**\n * Sends a message to the AI in a specific chat session\n * @param options - The chat id and message to send\n * @returns Promise that resolves when message is sent\n */\n sendMessage(options: { chatId: string; message: string }): Promise<void>;\n\n /**\n * Gets the readiness status of the LLM\n * @returns Promise with readiness status string\n */\n getReadiness(): Promise<{ readiness: string }>;\n\n /**\n * Sets the model configuration\n * - iOS: Use \"Apple Intelligence\" as path for the system model. Custom LiteRT-LM `.litertlm` models are supported on iOS only when this plugin is integrated through Swift Package Manager.\n * - Android: Use \"Gemini Nano\" for the AICore system model on supported devices where it is already available. Prefer LiteRT-LM `.litertlm` bundles for custom models; legacy MediaPipe `.task` models are still supported\n * - Web: Provide a web-ready model asset for `@mediapipe/tasks-genai` such as Gemma 4 `*-web.task`\n * @param options - The model configuration\n * @returns Promise that resolves when model is loaded\n */\n setModel(options: ModelOptions): Promise<void>;\n\n /**\n * Downloads a model from a URL and saves it to the appropriate location\n * - iOS: Downloads to the app's documents directory\n * - Android: Downloads to the app's files directory\n * @param options - The download configuration\n * @returns Promise with download result including the saved path\n */\n downloadModel(options: DownloadModelOptions): Promise<DownloadModelResult>;\n\n /**\n * Adds a listener for text received from AI\n * @param eventName - Event name 'textFromAi'\n * @param listenerFunc - Callback function for text events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'textFromAi',\n listenerFunc: (event: TextFromAiEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for AI completion events\n * @param eventName - Event name 'aiFinished'\n * @param listenerFunc - Callback function for finish events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'aiFinished',\n listenerFunc: (event: AiFinishedEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for generation failures that happen after streaming starts\n * @param eventName - Event name 'generationError'\n * @param listenerFunc - Callback function for generation errors\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'generationError',\n listenerFunc: (event: GenerationErrorEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for model download progress events\n * @param eventName - Event name 'downloadProgress'\n * @param listenerFunc - Callback function for progress events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'downloadProgress',\n listenerFunc: (event: DownloadProgressEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Adds a listener for readiness status changes\n * @param eventName - Event name 'readinessChange'\n * @param listenerFunc - Callback function for readiness events\n * @returns Promise with remove function to unsubscribe\n */\n addListener(\n eventName: 'readinessChange',\n listenerFunc: (event: ReadinessChangeEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * @returns Promise that resolves with the plugin version\n * @throws Error if getting the version fails\n * @since 1.0.0\n * @example\n * ```typescript\n * const { version } = await CapgoLLM.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n\n/**\n * Event data for text received from AI\n */\nexport interface TextFromAiEvent {\n /** The text content from AI - this is an incremental chunk, not the full text */\n text: string;\n /** The chat session ID */\n chatId: string;\n /** Whether this is a complete chunk (true) or partial streaming data (false) */\n isChunk?: boolean;\n}\n\n/**\n * Event data for AI completion\n */\nexport interface AiFinishedEvent {\n /** The chat session ID that finished */\n chatId: string;\n}\n\n/**\n * Event data for generation failures\n * `chatId` is optional and may be omitted when the failure is not tied to a specific chat.\n */\nexport interface GenerationErrorEvent {\n /** Optional. The chat session ID that failed, when available. */\n chatId?: string;\n /** Error message describing the failure */\n error: string;\n}\n\n/**\n * Options for downloading a model\n * Only `url` is required. `companionUrl` and `filename` are optional.\n */\nexport interface DownloadModelOptions {\n /** URL of the model file to download */\n url: string;\n /** Optional: URL of a companion file for legacy model formats */\n companionUrl?: string;\n /** Optional: Custom filename (defaults to filename from URL) */\n filename?: string;\n}\n\n/**\n * Result of model download\n */\nexport interface DownloadModelResult {\n /** Path where the model was saved */\n path: string;\n /** Path where the companion file was saved (if applicable) */\n companionPath?: string;\n}\n\n/**\n * Event data for download progress\n */\nexport interface DownloadProgressEvent {\n /** Percentage of download completed (0-100) */\n progress: number;\n /** Total bytes to download */\n totalBytes?: number;\n /** Bytes downloaded so far */\n downloadedBytes?: number;\n}\n\n/**\n * Event data for readiness status changes\n */\nexport interface ReadinessChangeEvent {\n /** The readiness status */\n readiness: string;\n}\n\n/**\n * Model configuration options\n * Only `path` is required. All other properties are optional overrides.\n */\nexport interface ModelOptions {\n /** Model path, \"Apple Intelligence\" for the Apple system model on iOS, or \"Gemini Nano\" for the Android AICore system model when already available on the device. On iOS, custom `.litertlm` models require the plugin to be integrated through Swift Package Manager. Gemma 4 examples use `.litertlm` on mobile and `*-web.task` on web. */\n path: string;\n /** Optional. Model file type/extension (for example `task`, `bin`, `litertlm`, or `gemini-nano`). If not provided, it is extracted from the path. Use `litertlm` on iOS only in SwiftPM integrations. */\n modelType?: string;\n /** Maximum number of tokens the model handles */\n maxTokens?: number;\n /** Number of tokens the model considers at each step */\n topk?: number;\n /** Amount of randomness in generation (0.0-1.0) */\n temperature?: number;\n /** Optional. Random seed for generation. */\n randomSeed?: number;\n /**\n * Optional. LiteRT-LM engine backend for iOS (SwiftPM) and Android.\n * Use `cpu` for stable long generations. When omitted, iOS prefers CPU then falls back to GPU; Android uses CPU.\n * @since 8.2.0\n */\n backend?: 'gpu' | 'cpu';\n}\n"]}
@@ -17,7 +17,7 @@ import MediaPipeTasksGenAI
17
17
 
18
18
  @objc(LLMPlugin)
19
19
  public class LLMPlugin: CAPPlugin, CAPBridgedPlugin {
20
- private let pluginVersion: String = "8.1.0"
20
+ private let pluginVersion: String = "8.1.1"
21
21
  private let liteRtTopP: Float = 0.95
22
22
 
23
23
  public let identifier = "LLMPlugin"
@@ -80,6 +80,7 @@ public class LLMPlugin: CAPPlugin, CAPBridgedPlugin {
80
80
  let temperature = call.getFloat("temperature") ?? 0.8
81
81
  let randomSeed = call.getInt("randomSeed") ?? 0
82
82
  let modelType = call.getString("modelType")
83
+ let backend = call.getString("backend")
83
84
 
84
85
  modelPath = path
85
86
  isReady = false
@@ -112,7 +113,11 @@ public class LLMPlugin: CAPPlugin, CAPBridgedPlugin {
112
113
  Task {
113
114
  do {
114
115
  let modelURL = try resolveModelURL(path: path, modelType: modelType)
115
- let engine = try await initializeLiteRtEngine(modelURL: modelURL, maxTokens: maxTokens)
116
+ let engine = try await initializeLiteRtEngine(
117
+ modelURL: modelURL,
118
+ maxTokens: maxTokens,
119
+ backend: backend
120
+ )
116
121
  liteRtEngine = engine
117
122
  liteRtTopk = topk
118
123
  liteRtTemperature = temperature
@@ -528,7 +533,11 @@ private extension LLMPlugin {
528
533
 
529
534
  #if canImport(LiteRTLM)
530
535
  private extension LLMPlugin {
531
- func initializeLiteRtEngine(modelURL: URL, maxTokens: Int) async throws -> LiteRTLM.Engine {
536
+ func initializeLiteRtEngine(
537
+ modelURL: URL,
538
+ maxTokens: Int,
539
+ backend: String?
540
+ ) async throws -> LiteRTLM.Engine {
532
541
  guard let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
533
542
  throw NSError(
534
543
  domain: "CapgoLLM",
@@ -537,20 +546,25 @@ private extension LLMPlugin {
537
546
  )
538
547
  }
539
548
 
540
- let configs = [
549
+ let cacheDir = cacheDirectory.path
550
+ let makeConfig = { (selectedBackend: LiteRTLM.Backend) throws -> LiteRTLM.EngineConfig in
541
551
  try LiteRTLM.EngineConfig(
542
552
  modelPath: modelURL.path,
543
- backend: .gpu,
553
+ backend: selectedBackend,
544
554
  maxNumTokens: maxTokens,
545
- cacheDir: cacheDirectory.path
546
- ),
547
- try LiteRTLM.EngineConfig(
548
- modelPath: modelURL.path,
549
- backend: .cpu(),
550
- maxNumTokens: maxTokens,
551
- cacheDir: cacheDirectory.path
555
+ cacheDir: cacheDir
552
556
  )
553
- ]
557
+ }
558
+
559
+ let configs: [LiteRTLM.EngineConfig]
560
+ switch backend?.lowercased() {
561
+ case "cpu":
562
+ configs = [try makeConfig(.cpu())]
563
+ case "gpu":
564
+ configs = [try makeConfig(.gpu), try makeConfig(.cpu())]
565
+ default:
566
+ configs = [try makeConfig(.cpu()), try makeConfig(.gpu)]
567
+ }
554
568
 
555
569
  var lastError: Error?
556
570
  for config in configs {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-llm",
3
- "version": "8.1.0",
3
+ "version": "8.1.1",
4
4
  "description": "Adds support for LLM locally runned for Capacitor",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",