@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 +32 -0
- package/README.md +600 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/ee/forgr/capgo_llm/LLM.java +317 -0
- package/android/src/main/java/ee/forgr/capgo_llm/LLMPlugin.java +211 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +466 -0
- package/dist/esm/definitions.d.ts +154 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +20 -0
- package/dist/esm/web.js +156 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +170 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +172 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/LLMPlugin/LLMPlugin.swift +469 -0
- package/ios/Tests/LLMPluginTests/LLMPluginPluginTests.swift +15 -0
- package/package.json +92 -0
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
2
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
3
|
+
var m = o[Symbol.asyncIterator], i;
|
|
4
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
5
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
6
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
7
|
+
};
|
|
8
|
+
import { WebPlugin } from '@capacitor/core';
|
|
9
|
+
import { FilesetResolver, LlmInference } from '@mediapipe/tasks-genai';
|
|
10
|
+
export class CapgoLLMWeb extends WebPlugin {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.llm = null;
|
|
14
|
+
this.chatSessions = new Map();
|
|
15
|
+
this.readiness = 'not-loaded';
|
|
16
|
+
}
|
|
17
|
+
async getReadiness() {
|
|
18
|
+
return { readiness: this.readiness };
|
|
19
|
+
}
|
|
20
|
+
async createChat() {
|
|
21
|
+
if (!this.llm) {
|
|
22
|
+
throw new Error('Model not loaded. Call setModel first.');
|
|
23
|
+
}
|
|
24
|
+
const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
25
|
+
this.chatSessions.set(chatId, {
|
|
26
|
+
id: chatId,
|
|
27
|
+
llm: this.llm,
|
|
28
|
+
isActive: true,
|
|
29
|
+
});
|
|
30
|
+
return { id: chatId };
|
|
31
|
+
}
|
|
32
|
+
async sendMessage(options) {
|
|
33
|
+
var e_1, _a;
|
|
34
|
+
const session = this.chatSessions.get(options.chatId);
|
|
35
|
+
if (!session) {
|
|
36
|
+
throw new Error(`Chat session ${options.chatId} not found`);
|
|
37
|
+
}
|
|
38
|
+
if (!session.isActive) {
|
|
39
|
+
throw new Error(`Chat session ${options.chatId} is not active`);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
// Generate response using MediaPipe GenAI streaming API
|
|
43
|
+
const response = session.llm.generateResponseStream(options.message);
|
|
44
|
+
try {
|
|
45
|
+
for (var response_1 = __asyncValues(response), response_1_1; response_1_1 = await response_1.next(), !response_1_1.done;) {
|
|
46
|
+
const partialResponse = response_1_1.value;
|
|
47
|
+
// Send incremental text
|
|
48
|
+
this.notifyListeners('textFromAi', {
|
|
49
|
+
text: partialResponse,
|
|
50
|
+
chatId: options.chatId,
|
|
51
|
+
isChunk: true,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
56
|
+
finally {
|
|
57
|
+
try {
|
|
58
|
+
if (response_1_1 && !response_1_1.done && (_a = response_1.return)) await _a.call(response_1);
|
|
59
|
+
}
|
|
60
|
+
finally { if (e_1) throw e_1.error; }
|
|
61
|
+
}
|
|
62
|
+
// Notify completion
|
|
63
|
+
this.notifyListeners('aiFinished', {
|
|
64
|
+
chatId: options.chatId,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error('Error generating response:', error);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async setModel(options) {
|
|
73
|
+
try {
|
|
74
|
+
// Update readiness
|
|
75
|
+
this.readiness = 'loading';
|
|
76
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
77
|
+
// Create LLM configuration
|
|
78
|
+
const config = {
|
|
79
|
+
baseOptions: {
|
|
80
|
+
modelAssetPath: options.path,
|
|
81
|
+
},
|
|
82
|
+
maxTokens: options.maxTokens || 2048,
|
|
83
|
+
topK: options.topk || 40,
|
|
84
|
+
temperature: options.temperature || 0.8,
|
|
85
|
+
randomSeed: options.randomSeed || 0,
|
|
86
|
+
};
|
|
87
|
+
const genai = await FilesetResolver.forGenAiTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm');
|
|
88
|
+
// Create LLM instance
|
|
89
|
+
this.llm = await LlmInference.createFromOptions(genai, config);
|
|
90
|
+
// Update readiness
|
|
91
|
+
this.readiness = 'ready';
|
|
92
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
this.readiness = 'error';
|
|
96
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async downloadModel(options) {
|
|
101
|
+
var _a;
|
|
102
|
+
try {
|
|
103
|
+
// For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL
|
|
104
|
+
const response = await fetch(options.url, {
|
|
105
|
+
method: 'GET',
|
|
106
|
+
headers: {
|
|
107
|
+
'Content-Type': 'application/octet-stream',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
throw new Error(`Failed to download model: ${response.statusText}`);
|
|
112
|
+
}
|
|
113
|
+
const contentLength = response.headers.get('content-length');
|
|
114
|
+
const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;
|
|
115
|
+
// Read the response with progress
|
|
116
|
+
const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
|
|
117
|
+
if (!reader) {
|
|
118
|
+
throw new Error('Failed to get reader from response');
|
|
119
|
+
}
|
|
120
|
+
const chunks = [];
|
|
121
|
+
let downloadedBytes = 0;
|
|
122
|
+
while (true) {
|
|
123
|
+
const { done, value } = await reader.read();
|
|
124
|
+
if (done)
|
|
125
|
+
break;
|
|
126
|
+
if (value) {
|
|
127
|
+
chunks.push(value);
|
|
128
|
+
downloadedBytes += value.length;
|
|
129
|
+
}
|
|
130
|
+
// Notify progress
|
|
131
|
+
const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;
|
|
132
|
+
this.notifyListeners('downloadProgress', {
|
|
133
|
+
progress,
|
|
134
|
+
totalBytes,
|
|
135
|
+
downloadedBytes,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// For web, we'll return the original URL as the path
|
|
139
|
+
// In a real implementation, you might want to store this in IndexedDB
|
|
140
|
+
const result = {
|
|
141
|
+
path: options.url,
|
|
142
|
+
};
|
|
143
|
+
// Handle companion file if provided
|
|
144
|
+
if (options.companionUrl) {
|
|
145
|
+
// For web, just return the companion URL
|
|
146
|
+
result.companionPath = options.companionUrl;
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error('Error downloading model:', error);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport { FilesetResolver, LlmInference } from '@mediapipe/tasks-genai';\n\nimport type {\n LLMPlugin,\n DownloadModelOptions,\n DownloadModelResult,\n ModelOptions,\n TextFromAiEvent,\n AiFinishedEvent,\n DownloadProgressEvent,\n ReadinessChangeEvent,\n} from './definitions';\n\ninterface ChatSession {\n id: string;\n llm: any;\n isActive: boolean;\n}\n\nexport class CapgoLLMWeb extends WebPlugin implements LLMPlugin {\n private llm: any = null;\n private chatSessions: Map<string, ChatSession> = new Map();\n private readiness = 'not-loaded';\n\n async getReadiness(): Promise<{ readiness: string }> {\n return { readiness: this.readiness };\n }\n\n async createChat(): Promise<{ id: string; instructions?: string }> {\n if (!this.llm) {\n throw new Error('Model not loaded. Call setModel first.');\n }\n\n const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n this.chatSessions.set(chatId, {\n id: chatId,\n llm: this.llm,\n isActive: true,\n });\n\n return { id: chatId };\n }\n\n async sendMessage(options: { chatId: string; message: string }): Promise<void> {\n const session = this.chatSessions.get(options.chatId);\n if (!session) {\n throw new Error(`Chat session ${options.chatId} not found`);\n }\n\n if (!session.isActive) {\n throw new Error(`Chat session ${options.chatId} is not active`);\n }\n\n try {\n // Generate response using MediaPipe GenAI streaming API\n const response = session.llm.generateResponseStream(options.message);\n\n for await (const partialResponse of response) {\n // Send incremental text\n this.notifyListeners('textFromAi', {\n text: partialResponse,\n chatId: options.chatId,\n isChunk: true,\n } as TextFromAiEvent);\n }\n\n // Notify completion\n this.notifyListeners('aiFinished', {\n chatId: options.chatId,\n } as AiFinishedEvent);\n } catch (error) {\n console.error('Error generating response:', error);\n throw error;\n }\n }\n\n async setModel(options: ModelOptions): Promise<void> {\n try {\n // Update readiness\n this.readiness = 'loading';\n this.notifyListeners('readinessChange', { readiness: this.readiness } as ReadinessChangeEvent);\n\n // Create LLM configuration\n const config: any = {\n baseOptions: {\n modelAssetPath: options.path,\n },\n maxTokens: options.maxTokens || 2048,\n topK: options.topk || 40,\n temperature: options.temperature || 0.8,\n randomSeed: options.randomSeed || 0,\n };\n\n const genai = await FilesetResolver.forGenAiTasks(\n 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm',\n );\n // Create LLM instance\n this.llm = await LlmInference.createFromOptions(genai, config);\n\n // Update readiness\n this.readiness = 'ready';\n this.notifyListeners('readinessChange', { readiness: this.readiness } as ReadinessChangeEvent);\n } catch (error) {\n this.readiness = 'error';\n this.notifyListeners('readinessChange', { readiness: this.readiness } as ReadinessChangeEvent);\n throw error;\n }\n }\n\n async downloadModel(options: DownloadModelOptions): Promise<DownloadModelResult> {\n try {\n // For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL\n const response = await fetch(options.url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/octet-stream',\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to download model: ${response.statusText}`);\n }\n\n const contentLength = response.headers.get('content-length');\n const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;\n\n // Read the response with progress\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Failed to get reader from response');\n }\n\n const chunks: Uint8Array[] = [];\n let downloadedBytes = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n if (value) {\n chunks.push(value);\n downloadedBytes += value.length;\n }\n\n // Notify progress\n const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;\n this.notifyListeners('downloadProgress', {\n progress,\n totalBytes,\n downloadedBytes,\n } as DownloadProgressEvent);\n }\n\n // For web, we'll return the original URL as the path\n // In a real implementation, you might want to store this in IndexedDB\n const result: DownloadModelResult = {\n path: options.url,\n };\n\n // Handle companion file if provided\n if (options.companionUrl) {\n // For web, just return the companion URL\n result.companionPath = options.companionUrl;\n }\n\n return result;\n } catch (error) {\n console.error('Error downloading model:', error);\n throw error;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@capacitor/core');
|
|
4
|
+
var tasksGenai = require('@mediapipe/tasks-genai');
|
|
5
|
+
|
|
6
|
+
const CapgoLLM = core.registerPlugin('CapgoLLM', {
|
|
7
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CapgoLLMWeb()),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
var __asyncValues = (globalThis && globalThis.__asyncValues) || function (o) {
|
|
11
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
+
var m = o[Symbol.asyncIterator], i;
|
|
13
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
+
};
|
|
17
|
+
class CapgoLLMWeb extends core.WebPlugin {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
this.llm = null;
|
|
21
|
+
this.chatSessions = new Map();
|
|
22
|
+
this.readiness = 'not-loaded';
|
|
23
|
+
}
|
|
24
|
+
async getReadiness() {
|
|
25
|
+
return { readiness: this.readiness };
|
|
26
|
+
}
|
|
27
|
+
async createChat() {
|
|
28
|
+
if (!this.llm) {
|
|
29
|
+
throw new Error('Model not loaded. Call setModel first.');
|
|
30
|
+
}
|
|
31
|
+
const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
32
|
+
this.chatSessions.set(chatId, {
|
|
33
|
+
id: chatId,
|
|
34
|
+
llm: this.llm,
|
|
35
|
+
isActive: true,
|
|
36
|
+
});
|
|
37
|
+
return { id: chatId };
|
|
38
|
+
}
|
|
39
|
+
async sendMessage(options) {
|
|
40
|
+
var e_1, _a;
|
|
41
|
+
const session = this.chatSessions.get(options.chatId);
|
|
42
|
+
if (!session) {
|
|
43
|
+
throw new Error(`Chat session ${options.chatId} not found`);
|
|
44
|
+
}
|
|
45
|
+
if (!session.isActive) {
|
|
46
|
+
throw new Error(`Chat session ${options.chatId} is not active`);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
// Generate response using MediaPipe GenAI streaming API
|
|
50
|
+
const response = session.llm.generateResponseStream(options.message);
|
|
51
|
+
try {
|
|
52
|
+
for (var response_1 = __asyncValues(response), response_1_1; response_1_1 = await response_1.next(), !response_1_1.done;) {
|
|
53
|
+
const partialResponse = response_1_1.value;
|
|
54
|
+
// Send incremental text
|
|
55
|
+
this.notifyListeners('textFromAi', {
|
|
56
|
+
text: partialResponse,
|
|
57
|
+
chatId: options.chatId,
|
|
58
|
+
isChunk: true,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
63
|
+
finally {
|
|
64
|
+
try {
|
|
65
|
+
if (response_1_1 && !response_1_1.done && (_a = response_1.return)) await _a.call(response_1);
|
|
66
|
+
}
|
|
67
|
+
finally { if (e_1) throw e_1.error; }
|
|
68
|
+
}
|
|
69
|
+
// Notify completion
|
|
70
|
+
this.notifyListeners('aiFinished', {
|
|
71
|
+
chatId: options.chatId,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error('Error generating response:', error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async setModel(options) {
|
|
80
|
+
try {
|
|
81
|
+
// Update readiness
|
|
82
|
+
this.readiness = 'loading';
|
|
83
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
84
|
+
// Create LLM configuration
|
|
85
|
+
const config = {
|
|
86
|
+
baseOptions: {
|
|
87
|
+
modelAssetPath: options.path,
|
|
88
|
+
},
|
|
89
|
+
maxTokens: options.maxTokens || 2048,
|
|
90
|
+
topK: options.topk || 40,
|
|
91
|
+
temperature: options.temperature || 0.8,
|
|
92
|
+
randomSeed: options.randomSeed || 0,
|
|
93
|
+
};
|
|
94
|
+
const genai = await tasksGenai.FilesetResolver.forGenAiTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm');
|
|
95
|
+
// Create LLM instance
|
|
96
|
+
this.llm = await tasksGenai.LlmInference.createFromOptions(genai, config);
|
|
97
|
+
// Update readiness
|
|
98
|
+
this.readiness = 'ready';
|
|
99
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.readiness = 'error';
|
|
103
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async downloadModel(options) {
|
|
108
|
+
var _a;
|
|
109
|
+
try {
|
|
110
|
+
// For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL
|
|
111
|
+
const response = await fetch(options.url, {
|
|
112
|
+
method: 'GET',
|
|
113
|
+
headers: {
|
|
114
|
+
'Content-Type': 'application/octet-stream',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new Error(`Failed to download model: ${response.statusText}`);
|
|
119
|
+
}
|
|
120
|
+
const contentLength = response.headers.get('content-length');
|
|
121
|
+
const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;
|
|
122
|
+
// Read the response with progress
|
|
123
|
+
const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
|
|
124
|
+
if (!reader) {
|
|
125
|
+
throw new Error('Failed to get reader from response');
|
|
126
|
+
}
|
|
127
|
+
const chunks = [];
|
|
128
|
+
let downloadedBytes = 0;
|
|
129
|
+
while (true) {
|
|
130
|
+
const { done, value } = await reader.read();
|
|
131
|
+
if (done)
|
|
132
|
+
break;
|
|
133
|
+
if (value) {
|
|
134
|
+
chunks.push(value);
|
|
135
|
+
downloadedBytes += value.length;
|
|
136
|
+
}
|
|
137
|
+
// Notify progress
|
|
138
|
+
const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;
|
|
139
|
+
this.notifyListeners('downloadProgress', {
|
|
140
|
+
progress,
|
|
141
|
+
totalBytes,
|
|
142
|
+
downloadedBytes,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// For web, we'll return the original URL as the path
|
|
146
|
+
// In a real implementation, you might want to store this in IndexedDB
|
|
147
|
+
const result = {
|
|
148
|
+
path: options.url,
|
|
149
|
+
};
|
|
150
|
+
// Handle companion file if provided
|
|
151
|
+
if (options.companionUrl) {
|
|
152
|
+
// For web, just return the companion URL
|
|
153
|
+
result.companionPath = options.companionUrl;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.error('Error downloading model:', error);
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
165
|
+
__proto__: null,
|
|
166
|
+
CapgoLLMWeb: CapgoLLMWeb
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
exports.CapgoLLM = CapgoLLM;
|
|
170
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapgoLLM = registerPlugin('CapgoLLM', {\n web: () => import('./web').then((m) => new m.CapgoLLMWeb()),\n});\nexport * from './definitions';\nexport { CapgoLLM };\n//# sourceMappingURL=index.js.map","var __asyncValues = (this && this.__asyncValues) || function (o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n};\nimport { WebPlugin } from '@capacitor/core';\nimport { FilesetResolver, LlmInference } from '@mediapipe/tasks-genai';\nexport class CapgoLLMWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.llm = null;\n this.chatSessions = new Map();\n this.readiness = 'not-loaded';\n }\n async getReadiness() {\n return { readiness: this.readiness };\n }\n async createChat() {\n if (!this.llm) {\n throw new Error('Model not loaded. Call setModel first.');\n }\n const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.chatSessions.set(chatId, {\n id: chatId,\n llm: this.llm,\n isActive: true,\n });\n return { id: chatId };\n }\n async sendMessage(options) {\n var e_1, _a;\n const session = this.chatSessions.get(options.chatId);\n if (!session) {\n throw new Error(`Chat session ${options.chatId} not found`);\n }\n if (!session.isActive) {\n throw new Error(`Chat session ${options.chatId} is not active`);\n }\n try {\n // Generate response using MediaPipe GenAI streaming API\n const response = session.llm.generateResponseStream(options.message);\n try {\n for (var response_1 = __asyncValues(response), response_1_1; response_1_1 = await response_1.next(), !response_1_1.done;) {\n const partialResponse = response_1_1.value;\n // Send incremental text\n this.notifyListeners('textFromAi', {\n text: partialResponse,\n chatId: options.chatId,\n isChunk: true,\n });\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (response_1_1 && !response_1_1.done && (_a = response_1.return)) await _a.call(response_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n // Notify completion\n this.notifyListeners('aiFinished', {\n chatId: options.chatId,\n });\n }\n catch (error) {\n console.error('Error generating response:', error);\n throw error;\n }\n }\n async setModel(options) {\n try {\n // Update readiness\n this.readiness = 'loading';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n // Create LLM configuration\n const config = {\n baseOptions: {\n modelAssetPath: options.path,\n },\n maxTokens: options.maxTokens || 2048,\n topK: options.topk || 40,\n temperature: options.temperature || 0.8,\n randomSeed: options.randomSeed || 0,\n };\n const genai = await FilesetResolver.forGenAiTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm');\n // Create LLM instance\n this.llm = await LlmInference.createFromOptions(genai, config);\n // Update readiness\n this.readiness = 'ready';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n }\n catch (error) {\n this.readiness = 'error';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n throw error;\n }\n }\n async downloadModel(options) {\n var _a;\n try {\n // For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL\n const response = await fetch(options.url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/octet-stream',\n },\n });\n if (!response.ok) {\n throw new Error(`Failed to download model: ${response.statusText}`);\n }\n const contentLength = response.headers.get('content-length');\n const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;\n // Read the response with progress\n const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();\n if (!reader) {\n throw new Error('Failed to get reader from response');\n }\n const chunks = [];\n let downloadedBytes = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n if (value) {\n chunks.push(value);\n downloadedBytes += value.length;\n }\n // Notify progress\n const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;\n this.notifyListeners('downloadProgress', {\n progress,\n totalBytes,\n downloadedBytes,\n });\n }\n // For web, we'll return the original URL as the path\n // In a real implementation, you might want to store this in IndexedDB\n const result = {\n path: options.url,\n };\n // Handle companion file if provided\n if (options.companionUrl) {\n // For web, just return the companion URL\n result.companionPath = options.companionUrl;\n }\n return result;\n }\n catch (error) {\n console.error('Error downloading model:', error);\n throw error;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","this","WebPlugin","FilesetResolver","LlmInference"],"mappings":"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"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
var capacitorLLM = (function (exports, core, tasksGenai) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const CapgoLLM = core.registerPlugin('CapgoLLM', {
|
|
5
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CapgoLLMWeb()),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
var __asyncValues = (globalThis && globalThis.__asyncValues) || function (o) {
|
|
9
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
10
|
+
var m = o[Symbol.asyncIterator], i;
|
|
11
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
12
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
13
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
14
|
+
};
|
|
15
|
+
class CapgoLLMWeb extends core.WebPlugin {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.llm = null;
|
|
19
|
+
this.chatSessions = new Map();
|
|
20
|
+
this.readiness = 'not-loaded';
|
|
21
|
+
}
|
|
22
|
+
async getReadiness() {
|
|
23
|
+
return { readiness: this.readiness };
|
|
24
|
+
}
|
|
25
|
+
async createChat() {
|
|
26
|
+
if (!this.llm) {
|
|
27
|
+
throw new Error('Model not loaded. Call setModel first.');
|
|
28
|
+
}
|
|
29
|
+
const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
30
|
+
this.chatSessions.set(chatId, {
|
|
31
|
+
id: chatId,
|
|
32
|
+
llm: this.llm,
|
|
33
|
+
isActive: true,
|
|
34
|
+
});
|
|
35
|
+
return { id: chatId };
|
|
36
|
+
}
|
|
37
|
+
async sendMessage(options) {
|
|
38
|
+
var e_1, _a;
|
|
39
|
+
const session = this.chatSessions.get(options.chatId);
|
|
40
|
+
if (!session) {
|
|
41
|
+
throw new Error(`Chat session ${options.chatId} not found`);
|
|
42
|
+
}
|
|
43
|
+
if (!session.isActive) {
|
|
44
|
+
throw new Error(`Chat session ${options.chatId} is not active`);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
// Generate response using MediaPipe GenAI streaming API
|
|
48
|
+
const response = session.llm.generateResponseStream(options.message);
|
|
49
|
+
try {
|
|
50
|
+
for (var response_1 = __asyncValues(response), response_1_1; response_1_1 = await response_1.next(), !response_1_1.done;) {
|
|
51
|
+
const partialResponse = response_1_1.value;
|
|
52
|
+
// Send incremental text
|
|
53
|
+
this.notifyListeners('textFromAi', {
|
|
54
|
+
text: partialResponse,
|
|
55
|
+
chatId: options.chatId,
|
|
56
|
+
isChunk: true,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
61
|
+
finally {
|
|
62
|
+
try {
|
|
63
|
+
if (response_1_1 && !response_1_1.done && (_a = response_1.return)) await _a.call(response_1);
|
|
64
|
+
}
|
|
65
|
+
finally { if (e_1) throw e_1.error; }
|
|
66
|
+
}
|
|
67
|
+
// Notify completion
|
|
68
|
+
this.notifyListeners('aiFinished', {
|
|
69
|
+
chatId: options.chatId,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('Error generating response:', error);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async setModel(options) {
|
|
78
|
+
try {
|
|
79
|
+
// Update readiness
|
|
80
|
+
this.readiness = 'loading';
|
|
81
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
82
|
+
// Create LLM configuration
|
|
83
|
+
const config = {
|
|
84
|
+
baseOptions: {
|
|
85
|
+
modelAssetPath: options.path,
|
|
86
|
+
},
|
|
87
|
+
maxTokens: options.maxTokens || 2048,
|
|
88
|
+
topK: options.topk || 40,
|
|
89
|
+
temperature: options.temperature || 0.8,
|
|
90
|
+
randomSeed: options.randomSeed || 0,
|
|
91
|
+
};
|
|
92
|
+
const genai = await tasksGenai.FilesetResolver.forGenAiTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm');
|
|
93
|
+
// Create LLM instance
|
|
94
|
+
this.llm = await tasksGenai.LlmInference.createFromOptions(genai, config);
|
|
95
|
+
// Update readiness
|
|
96
|
+
this.readiness = 'ready';
|
|
97
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
this.readiness = 'error';
|
|
101
|
+
this.notifyListeners('readinessChange', { readiness: this.readiness });
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async downloadModel(options) {
|
|
106
|
+
var _a;
|
|
107
|
+
try {
|
|
108
|
+
// For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL
|
|
109
|
+
const response = await fetch(options.url, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type': 'application/octet-stream',
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw new Error(`Failed to download model: ${response.statusText}`);
|
|
117
|
+
}
|
|
118
|
+
const contentLength = response.headers.get('content-length');
|
|
119
|
+
const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;
|
|
120
|
+
// Read the response with progress
|
|
121
|
+
const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
|
|
122
|
+
if (!reader) {
|
|
123
|
+
throw new Error('Failed to get reader from response');
|
|
124
|
+
}
|
|
125
|
+
const chunks = [];
|
|
126
|
+
let downloadedBytes = 0;
|
|
127
|
+
while (true) {
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done)
|
|
130
|
+
break;
|
|
131
|
+
if (value) {
|
|
132
|
+
chunks.push(value);
|
|
133
|
+
downloadedBytes += value.length;
|
|
134
|
+
}
|
|
135
|
+
// Notify progress
|
|
136
|
+
const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;
|
|
137
|
+
this.notifyListeners('downloadProgress', {
|
|
138
|
+
progress,
|
|
139
|
+
totalBytes,
|
|
140
|
+
downloadedBytes,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// For web, we'll return the original URL as the path
|
|
144
|
+
// In a real implementation, you might want to store this in IndexedDB
|
|
145
|
+
const result = {
|
|
146
|
+
path: options.url,
|
|
147
|
+
};
|
|
148
|
+
// Handle companion file if provided
|
|
149
|
+
if (options.companionUrl) {
|
|
150
|
+
// For web, just return the companion URL
|
|
151
|
+
result.companionPath = options.companionUrl;
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error('Error downloading model:', error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
163
|
+
__proto__: null,
|
|
164
|
+
CapgoLLMWeb: CapgoLLMWeb
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
exports.CapgoLLM = CapgoLLM;
|
|
168
|
+
|
|
169
|
+
return exports;
|
|
170
|
+
|
|
171
|
+
})({}, capacitorExports, MediaPipeTasksGenAI);
|
|
172
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapgoLLM = registerPlugin('CapgoLLM', {\n web: () => import('./web').then((m) => new m.CapgoLLMWeb()),\n});\nexport * from './definitions';\nexport { CapgoLLM };\n//# sourceMappingURL=index.js.map","var __asyncValues = (this && this.__asyncValues) || function (o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n};\nimport { WebPlugin } from '@capacitor/core';\nimport { FilesetResolver, LlmInference } from '@mediapipe/tasks-genai';\nexport class CapgoLLMWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.llm = null;\n this.chatSessions = new Map();\n this.readiness = 'not-loaded';\n }\n async getReadiness() {\n return { readiness: this.readiness };\n }\n async createChat() {\n if (!this.llm) {\n throw new Error('Model not loaded. Call setModel first.');\n }\n const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.chatSessions.set(chatId, {\n id: chatId,\n llm: this.llm,\n isActive: true,\n });\n return { id: chatId };\n }\n async sendMessage(options) {\n var e_1, _a;\n const session = this.chatSessions.get(options.chatId);\n if (!session) {\n throw new Error(`Chat session ${options.chatId} not found`);\n }\n if (!session.isActive) {\n throw new Error(`Chat session ${options.chatId} is not active`);\n }\n try {\n // Generate response using MediaPipe GenAI streaming API\n const response = session.llm.generateResponseStream(options.message);\n try {\n for (var response_1 = __asyncValues(response), response_1_1; response_1_1 = await response_1.next(), !response_1_1.done;) {\n const partialResponse = response_1_1.value;\n // Send incremental text\n this.notifyListeners('textFromAi', {\n text: partialResponse,\n chatId: options.chatId,\n isChunk: true,\n });\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (response_1_1 && !response_1_1.done && (_a = response_1.return)) await _a.call(response_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n // Notify completion\n this.notifyListeners('aiFinished', {\n chatId: options.chatId,\n });\n }\n catch (error) {\n console.error('Error generating response:', error);\n throw error;\n }\n }\n async setModel(options) {\n try {\n // Update readiness\n this.readiness = 'loading';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n // Create LLM configuration\n const config = {\n baseOptions: {\n modelAssetPath: options.path,\n },\n maxTokens: options.maxTokens || 2048,\n topK: options.topk || 40,\n temperature: options.temperature || 0.8,\n randomSeed: options.randomSeed || 0,\n };\n const genai = await FilesetResolver.forGenAiTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm');\n // Create LLM instance\n this.llm = await LlmInference.createFromOptions(genai, config);\n // Update readiness\n this.readiness = 'ready';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n }\n catch (error) {\n this.readiness = 'error';\n this.notifyListeners('readinessChange', { readiness: this.readiness });\n throw error;\n }\n }\n async downloadModel(options) {\n var _a;\n try {\n // For web, we'll simulate download by fetching and storing in IndexedDB or returning the URL\n const response = await fetch(options.url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/octet-stream',\n },\n });\n if (!response.ok) {\n throw new Error(`Failed to download model: ${response.statusText}`);\n }\n const contentLength = response.headers.get('content-length');\n const totalBytes = contentLength ? parseInt(contentLength, 10) : undefined;\n // Read the response with progress\n const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();\n if (!reader) {\n throw new Error('Failed to get reader from response');\n }\n const chunks = [];\n let downloadedBytes = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n if (value) {\n chunks.push(value);\n downloadedBytes += value.length;\n }\n // Notify progress\n const progress = totalBytes ? (downloadedBytes / totalBytes) * 100 : 0;\n this.notifyListeners('downloadProgress', {\n progress,\n totalBytes,\n downloadedBytes,\n });\n }\n // For web, we'll return the original URL as the path\n // In a real implementation, you might want to store this in IndexedDB\n const result = {\n path: options.url,\n };\n // Handle companion file if provided\n if (options.companionUrl) {\n // For web, just return the companion URL\n result.companionPath = options.companionUrl;\n }\n return result;\n }\n catch (error) {\n console.error('Error downloading model:', error);\n throw error;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","this","WebPlugin","FilesetResolver","LlmInference"],"mappings":"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"}
|