@emilshirokikh/slyos-sdk 1.0.0 → 1.1.0

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
@@ -1,48 +1,326 @@
1
- # @belto/slyos-sdk
1
+ # 🔥 @emilshirokikh/slyos-sdk
2
2
 
3
- On-device AI that runs locally in browsers and Node.js. Save 98.5% vs cloud APIs.
3
+ Official SDK for SlyOS on-device AI platform. Run AI models locally in browsers and Node.js.
4
4
 
5
- ## Installation
5
+ ---
6
+
7
+ ## 📦 Installation
6
8
  ```bash
7
- npm install @belto/slyos-sdk
9
+ npm install @emilshirokikh/slyos-sdk
8
10
  ```
9
11
 
10
- ## Quick Start
12
+ **npm:** https://www.npmjs.com/package/@emilshirokikh/slyos-sdk
13
+
14
+ ---
15
+
16
+ ## 🚀 Quick Start
11
17
  ```javascript
12
- import SlyOS from '@belto/slyos-sdk';
18
+ import SlyOS from '@emilshirokikh/slyos-sdk';
13
19
 
14
- // Initialize
20
+ // 1. Initialize
15
21
  const sdk = new SlyOS({
16
- apiKey: 'your-api-key'
22
+ apiKey: 'sk_live_your_api_key'
17
23
  });
18
24
  await sdk.initialize();
19
25
 
20
- // Load model (downloads once, ~200MB)
26
+ // 2. Load model (downloads ~200MB once)
21
27
  await sdk.loadModel('quantum-360m');
22
28
 
23
- // Generate AI responses
24
- const response = await sdk.generate('quantum-360m', 'Hello!');
29
+ // 3. Generate responses
30
+ const response = await sdk.generate('quantum-360m',
31
+ 'What is artificial intelligence?',
32
+ {
33
+ temperature: 0.7,
34
+ maxTokens: 100,
35
+ topP: 0.9
36
+ }
37
+ );
38
+
25
39
  console.log(response);
40
+ // AI runs locally - zero cost!
41
+ ```
42
+
43
+ ---
44
+
45
+ ## 📚 API Reference
46
+
47
+ ### Constructor
48
+ ```typescript
49
+ new SlyOS(config: SlyOSConfig)
50
+ ```
51
+
52
+ **Config:**
53
+ ```typescript
54
+ {
55
+ apiKey: string; // Get from dashboard
56
+ apiUrl?: string; // Optional, defaults to production
57
+ }
58
+ ```
59
+
60
+ ---
61
+
62
+ ### Methods
63
+
64
+ #### `initialize()`
65
+ Authenticates with SlyOS backend and registers device.
66
+ ```javascript
67
+ await sdk.initialize();
68
+ ```
69
+
70
+ **Returns:** `Promise<void>`
71
+
72
+ ---
73
+
74
+ #### `loadModel(modelId)`
75
+ Downloads and caches AI model locally.
76
+ ```javascript
77
+ await sdk.loadModel('quantum-360m');
78
+ ```
79
+
80
+ **Parameters:**
81
+ - `modelId` (string): Model identifier
82
+ - `quantum-135m` - 80MB, fastest
83
+ - `quantum-360m` - 200MB, recommended
84
+ - `quantum-1.7b` - 1GB, high quality
85
+ - `quantum-3b` - 1.7GB, best quality
86
+
87
+ **Returns:** `Promise<void>`
88
+
89
+ **First call:** Downloads model (~1-2 min)
90
+ **Subsequent calls:** Uses cached model (<1 sec)
91
+
92
+ ---
93
+
94
+ #### `generate(modelId, prompt, options?)`
95
+ Generates AI response locally.
96
+ ```javascript
97
+ const response = await sdk.generate('quantum-360m',
98
+ 'Tell me about your menu',
99
+ {
100
+ temperature: 0.7,
101
+ maxTokens: 150,
102
+ topP: 0.9
103
+ }
104
+ );
105
+ ```
106
+
107
+ **Parameters:**
108
+ - `modelId` (string): Model to use
109
+ - `prompt` (string): Input text
110
+ - `options` (object, optional):
111
+ - `temperature` (0-2): Creativity (default: 0.7)
112
+ - `maxTokens` (10-2000): Max response length (default: 100)
113
+ - `topP` (0-1): Nucleus sampling (default: 0.9)
114
+
115
+ **Returns:** `Promise<string>` - Generated text
116
+
117
+ ---
118
+
119
+ ## 🌐 Platform Support
120
+
121
+ | Platform | Status | Notes |
122
+ |----------|--------|-------|
123
+ | **Chrome** | ✅ Supported | Recommended |
124
+ | **Safari** | ✅ Supported | iOS 16+ |
125
+ | **Edge** | ✅ Supported | Chromium-based |
126
+ | **Firefox** | ⚠️ Limited | Some models work |
127
+ | **Node.js** | ✅ Supported | v18+ |
128
+ | **React Native** | 🚧 Coming Soon | Q2 2026 |
129
+
130
+ ---
131
+
132
+ ## 💡 Usage Examples
133
+
134
+ ### Basic Chatbot
135
+ ```javascript
136
+ import SlyOS from '@emilshirokikh/slyos-sdk';
137
+
138
+ const sdk = new SlyOS({ apiKey: 'sk_live_...' });
139
+ await sdk.initialize();
140
+ await sdk.loadModel('quantum-360m');
141
+
142
+ async function chat(userMessage) {
143
+ return await sdk.generate('quantum-360m', userMessage);
144
+ }
145
+
146
+ const response = await chat('What are your hours?');
147
+ console.log(response);
148
+ ```
149
+
150
+ ---
151
+
152
+ ### With System Prompt
153
+ ```javascript
154
+ const systemPrompt = `You are a helpful assistant for McDonald's.
155
+ Help with menu, hours, and nutrition. Be friendly and concise.`;
156
+
157
+ const userMessage = 'What breakfast items do you have?';
158
+ const fullPrompt = `${systemPrompt}\n\nCustomer: ${userMessage}\nAssistant:`;
159
+
160
+ const response = await sdk.generate('quantum-360m', fullPrompt, {
161
+ temperature: 0.7,
162
+ maxTokens: 150
163
+ });
164
+ ```
165
+
166
+ ---
167
+
168
+ ### React Integration
169
+ ```jsx
170
+ import { useState, useEffect } from 'react';
171
+ import SlyOS from '@emilshirokikh/slyos-sdk';
172
+
173
+ function Chatbot() {
174
+ const [sdk, setSdk] = useState(null);
175
+ const [loading, setLoading] = useState(true);
176
+ const [response, setResponse] = useState('');
177
+
178
+ useEffect(() => {
179
+ async function init() {
180
+ const client = new SlyOS({ apiKey: 'sk_live_...' });
181
+ await client.initialize();
182
+ await client.loadModel('quantum-360m');
183
+ setSdk(client);
184
+ setLoading(false);
185
+ }
186
+ init();
187
+ }, []);
188
+
189
+ async function handleChat(message) {
190
+ const reply = await sdk.generate('quantum-360m', message);
191
+ setResponse(reply);
192
+ }
193
+
194
+ if (loading) return <div>Loading AI...</div>;
195
+
196
+ return (
197
+ <div>
198
+ <button onClick={() => handleChat('Hello!')}>
199
+ Chat
200
+ </button>
201
+ <p>{response}</p>
202
+ </div>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ---
208
+
209
+ ## 🔧 Advanced Configuration
210
+
211
+ ### Custom Backend URL
212
+ ```javascript
213
+ const sdk = new SlyOS({
214
+ apiKey: 'sk_live_...',
215
+ apiUrl: 'https://api.slyos.world'
216
+ });
26
217
  ```
27
218
 
28
- ## Features
219
+ ---
220
+
221
+ ### Multiple Models
222
+ ```javascript
223
+ await sdk.loadModel('quantum-360m');
224
+ await sdk.loadModel('quantum-1.7b');
225
+
226
+ // Use different models
227
+ const fast = await sdk.generate('quantum-360m', 'Quick question?');
228
+ const detailed = await sdk.generate('quantum-1.7b', 'Complex question?');
229
+ ```
230
+
231
+ ---
232
+
233
+ ## 📊 Performance
234
+
235
+ ### Benchmarks (Quantum 360M)
236
+
237
+ | Metric | Browser | Node.js |
238
+ |--------|---------|---------|
239
+ | First load | 60-120s | 30-60s |
240
+ | Cached load | <1s | <0.5s |
241
+ | Inference | 35 tok/s | 50 tok/s |
242
+ | Memory | 500MB | 300MB |
243
+
244
+ ---
245
+
246
+ ## 🐛 Troubleshooting
247
+
248
+ ### Model won't load
249
+ ```javascript
250
+ // Check browser console for errors
251
+ // Ensure 2GB+ RAM available
252
+ // Try smaller model (quantum-135m)
253
+ ```
254
+
255
+ ### CORS errors
256
+ ```javascript
257
+ // Backend must allow your domain
258
+ // Check CORS_ORIGIN environment variable
259
+ ```
260
+
261
+ ### Slow inference
262
+ ```javascript
263
+ // Use smaller model
264
+ // Reduce maxTokens
265
+ // Check CPU/RAM availability
266
+ ```
267
+
268
+ ---
269
+
270
+ ## 🔒 Security
271
+
272
+ - API keys stored client-side (localStorage)
273
+ - All inference happens locally (private)
274
+ - Telemetry sent to SlyOS (anonymized)
275
+ - No user data sent to cloud
276
+
277
+ ---
278
+
279
+ ## 📦 Package Info
280
+
281
+ - **Package:** `@emilshirokikh/slyos-sdk`
282
+ - **Version:** 1.0.0
283
+ - **License:** MIT
284
+ - **Size:** 13.5 KB (unpacked)
285
+ - **Dependencies:** axios, @huggingface/transformers
286
+
287
+ ---
288
+
289
+ ## 🤝 Contributing
290
+ ```bash
291
+ # Clone repo
292
+ git clone https://github.com/BeltoAI/sly.git
293
+ cd sly/sdk
294
+
295
+ # Install dependencies
296
+ npm install
297
+
298
+ # Make changes to src/index.ts
299
+
300
+ # Build
301
+ npm run build
302
+
303
+ # Test locally
304
+ npm link
305
+ ```
306
+
307
+ ---
308
+
309
+ ## 📄 License
29
310
 
30
- - ✅ **Zero API costs** - AI runs on user's device
31
- - ✅ **Privacy-first** - Data never leaves device
32
- - ✅ **Works offline** - No internet required after download
33
- - ✅ **Auto-scaling** - No server capacity planning
34
- - ✅ **Real-time** - Sub-second response times
311
+ MIT - See LICENSE file
35
312
 
36
- ## Platform Support
313
+ ---
37
314
 
38
- - Web (Chrome, Safari, Edge)
39
- - Node.js (v18+)
40
- - React Native (coming soon)
315
+ ## 🙏 Credits
41
316
 
42
- ## Documentation
317
+ Built with Hugging Face Transformers.js
43
318
 
44
- Full docs at: https://docs.slyos.com
319
+ ---
45
320
 
46
- ## License
321
+ ## 📞 Support
47
322
 
48
- MIT
323
+ - **npm:** https://www.npmjs.com/package/@emilshirokikh/slyos-sdk
324
+ - **GitHub:** https://github.com/BeltoAI/sly
325
+ - **Docs:** See main README.md
326
+ - **Email:** support@slyos.world
package/dist/index.d.ts CHANGED
@@ -2,33 +2,28 @@ interface SlyOSConfig {
2
2
  apiKey: string;
3
3
  apiUrl?: string;
4
4
  }
5
- interface ModelInfo {
6
- id: string;
7
- name: string;
8
- displayName: string;
9
- size: number;
10
- requirements: {
11
- minMemoryMB: number;
12
- minStorageMB: number;
13
- platforms: string[];
14
- };
5
+ interface GenerateOptions {
6
+ temperature?: number;
7
+ maxTokens?: number;
8
+ topP?: number;
9
+ }
10
+ interface TranscribeOptions {
11
+ language?: string;
12
+ returnTimestamps?: boolean;
15
13
  }
16
14
  declare class SlyOS {
17
15
  private apiKey;
18
16
  private apiUrl;
19
- private api;
20
17
  private deviceId;
18
+ private token;
21
19
  private models;
22
20
  constructor(config: SlyOSConfig);
23
- private generateDeviceId;
24
21
  initialize(): Promise<void>;
25
- private detectPlatform;
26
- private getMemoryInfo;
27
- getAvailableModels(): Promise<ModelInfo[]>;
22
+ getAvailableModels(): Record<string, {
23
+ models: string[];
24
+ }>;
28
25
  loadModel(modelId: string): Promise<void>;
29
- generate(modelId: string, prompt: string, options?: any): Promise<string>;
30
- private sendTelemetry;
31
- getDeviceId(): string;
26
+ generate(modelId: string, prompt: string, options?: GenerateOptions): Promise<string>;
27
+ transcribe(modelId: string, audioInput: any, options?: TranscribeOptions): Promise<string>;
32
28
  }
33
29
  export default SlyOS;
34
- export { SlyOS, SlyOSConfig, ModelInfo };
package/dist/index.js CHANGED
@@ -1,156 +1,205 @@
1
1
  import axios from 'axios';
2
- import { pipeline } from '@huggingface/transformers';
2
+ import { pipeline, env } from '@huggingface/transformers';
3
+ // @ts-ignore - Force CPU in Node.js
4
+ if (env.backends?.onnx?.wasm) {
5
+ env.backends.onnx.wasm.proxy = false;
6
+ }
7
+ const modelMap = {
8
+ // LLM models (1B+)
9
+ 'quantum-1.7b': {
10
+ hfModel: 'HuggingFaceTB/SmolLM2-1.7B-Instruct',
11
+ task: 'text-generation',
12
+ category: 'llm',
13
+ },
14
+ 'quantum-3b': {
15
+ hfModel: 'meta-llama/Llama-3.2-3B-Instruct',
16
+ task: 'text-generation',
17
+ category: 'llm',
18
+ },
19
+ 'quantum-code-3b': {
20
+ hfModel: 'Qwen/Qwen2.5-Coder-3B-Instruct',
21
+ task: 'text-generation',
22
+ category: 'llm',
23
+ },
24
+ 'quantum-8b': {
25
+ hfModel: 'meta-llama/Llama-3.1-8B-Instruct',
26
+ task: 'text-generation',
27
+ category: 'llm',
28
+ },
29
+ // STT models
30
+ 'voicecore-base': {
31
+ hfModel: 'onnx-community/whisper-base',
32
+ task: 'automatic-speech-recognition',
33
+ category: 'stt',
34
+ },
35
+ 'voicecore-small': {
36
+ hfModel: 'onnx-community/whisper-small',
37
+ task: 'automatic-speech-recognition',
38
+ category: 'stt',
39
+ },
40
+ };
3
41
  class SlyOS {
4
42
  constructor(config) {
43
+ this.token = null;
5
44
  this.models = new Map();
6
45
  this.apiKey = config.apiKey;
7
- this.apiUrl = config.apiUrl || 'http://slyos-prod.eba-qjz3cmgq.us-east-2.elasticbeanstalk.com';
8
- this.api = axios.create({
9
- baseURL: `${this.apiUrl}/api`,
10
- headers: {
11
- 'Authorization': `Bearer ${this.apiKey}`,
12
- 'Content-Type': 'application/json'
13
- }
14
- });
15
- this.deviceId = this.generateDeviceId();
16
- }
17
- generateDeviceId() {
18
- return `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
46
+ this.apiUrl = config.apiUrl || 'https://api.slyos.world';
47
+ this.deviceId = `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
19
48
  }
20
49
  async initialize() {
21
- console.log('🔥 SlyOS SDK Initializing...');
22
- try {
23
- await this.api.post('/devices/register', {
24
- device_id: this.deviceId,
25
- platform: this.detectPlatform(),
26
- os_version: navigator.userAgent,
27
- total_memory_mb: this.getMemoryInfo(),
28
- cpu_cores: navigator.hardwareConcurrency || 4
29
- });
30
- console.log(' Device registered:', this.deviceId);
31
- }
32
- catch (error) {
33
- console.error('Failed to register device:', error);
34
- }
35
- }
36
- detectPlatform() {
37
- const ua = navigator.userAgent.toLowerCase();
38
- if (ua.includes('iphone') || ua.includes('ipad'))
39
- return 'ios';
40
- if (ua.includes('android'))
41
- return 'android';
42
- return 'web';
43
- }
44
- getMemoryInfo() {
45
- // @ts-ignore
46
- return (navigator.deviceMemory || 4) * 1024;
50
+ // Authenticate using API key
51
+ const authRes = await axios.post(`${this.apiUrl}/api/auth/sdk`, {
52
+ apiKey: this.apiKey,
53
+ });
54
+ this.token = authRes.data.token;
55
+ // Register this device
56
+ await axios.post(`${this.apiUrl}/api/devices/register`, {
57
+ device_id: this.deviceId,
58
+ platform: typeof window !== 'undefined' ? 'web' : 'nodejs',
59
+ os_version: typeof window !== 'undefined' ? navigator.userAgent : process.version,
60
+ total_memory_mb: 4096,
61
+ cpu_cores: 4,
62
+ has_gpu: false,
63
+ }, {
64
+ headers: { Authorization: `Bearer ${this.token}` },
65
+ });
47
66
  }
48
- async getAvailableModels() {
49
- try {
50
- const res = await this.api.get('/models');
51
- return res.data.map((m) => ({
52
- id: m.model_id,
53
- name: m.name,
54
- displayName: m.display_name,
55
- size: m.size_q4,
56
- requirements: {
57
- minMemoryMB: parseInt(m.memory_required) || 512,
58
- minStorageMB: m.size_q4 + 100,
59
- platforms: ['ios', 'android', 'web']
60
- }
61
- }));
62
- }
63
- catch (error) {
64
- console.error('Failed to fetch models:', error);
65
- return [];
67
+ getAvailableModels() {
68
+ const grouped = { llm: [], stt: [] };
69
+ for (const [id, info] of Object.entries(modelMap)) {
70
+ if (!grouped[info.category])
71
+ grouped[info.category] = [];
72
+ grouped[info.category].push(id);
66
73
  }
74
+ return Object.fromEntries(Object.entries(grouped).map(([cat, models]) => [cat, { models }]));
67
75
  }
68
76
  async loadModel(modelId) {
69
- console.log(`📥 Loading model: ${modelId}`);
70
- const startTime = Date.now();
77
+ const info = modelMap[modelId];
78
+ if (!info) {
79
+ throw new Error(`Unknown model "${modelId}". Available: ${Object.keys(modelMap).join(', ')}`);
80
+ }
71
81
  try {
72
- const modelMap = {
73
- 'quantum-135m': 'HuggingFaceTB/SmolLM2-135M-Instruct',
74
- 'quantum-360m': 'HuggingFaceTB/SmolLM2-360M-Instruct',
75
- 'quantum-1.7b': 'HuggingFaceTB/SmolLM2-1.7B-Instruct'
76
- };
77
- const hfModel = modelMap[modelId] || modelMap['quantum-360m'];
78
- const generator = await pipeline('text-generation', hfModel, {
79
- device: 'webgpu',
80
- dtype: 'q4'
81
- });
82
- this.models.set(modelId, generator);
83
- const loadTime = Date.now() - startTime;
84
- console.log(`✅ Model loaded in ${loadTime}ms`);
85
- await this.sendTelemetry({
86
- event_type: 'model_load',
87
- model_id: modelId,
88
- latency_ms: loadTime,
89
- success: true
82
+ const pipe = await pipeline(info.task, info.hfModel, {
83
+ device: 'cpu',
84
+ dtype: 'fp32',
90
85
  });
86
+ this.models.set(modelId, { pipe, info });
87
+ if (this.token) {
88
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
89
+ device_id: this.deviceId,
90
+ event_type: 'model_load',
91
+ model_id: modelId,
92
+ success: true,
93
+ }, {
94
+ headers: { Authorization: `Bearer ${this.token}` },
95
+ }).catch(() => { });
96
+ }
91
97
  }
92
98
  catch (error) {
93
- console.error('Failed to load model:', error);
94
- await this.sendTelemetry({
95
- event_type: 'model_load',
96
- model_id: modelId,
97
- success: false,
98
- error_message: String(error)
99
- });
99
+ if (this.token) {
100
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
101
+ device_id: this.deviceId,
102
+ event_type: 'model_load',
103
+ model_id: modelId,
104
+ success: false,
105
+ error_message: error.message,
106
+ }, {
107
+ headers: { Authorization: `Bearer ${this.token}` },
108
+ }).catch(() => { });
109
+ }
100
110
  throw error;
101
111
  }
102
112
  }
103
- async generate(modelId, prompt, options) {
113
+ async generate(modelId, prompt, options = {}) {
104
114
  if (!this.models.has(modelId)) {
105
115
  await this.loadModel(modelId);
106
116
  }
107
- const generator = this.models.get(modelId);
117
+ const { pipe, info } = this.models.get(modelId);
118
+ if (info.category !== 'llm') {
119
+ throw new Error(`Model "${modelId}" is not an LLM. Use transcribe() for STT models.`);
120
+ }
108
121
  const startTime = Date.now();
109
122
  try {
110
- const result = await generator(prompt, {
111
- max_new_tokens: options?.maxTokens || 100,
112
- temperature: options?.temperature || 0.7,
113
- top_p: options?.topP || 0.9,
114
- ...options
123
+ const result = await pipe(prompt, {
124
+ max_new_tokens: options.maxTokens || 100,
125
+ temperature: options.temperature || 0.7,
126
+ top_p: options.topP || 0.9,
127
+ do_sample: true,
115
128
  });
116
- const latency = Date.now() - startTime;
117
129
  const response = result[0].generated_text;
118
- const tokens = response.split(' ').length;
119
- await this.sendTelemetry({
120
- event_type: 'inference',
121
- model_id: modelId,
122
- latency_ms: latency,
123
- tokens_generated: tokens,
124
- success: true
125
- });
126
- console.log(`⚡ Generated ${tokens} tokens in ${latency}ms`);
130
+ const latency = Date.now() - startTime;
131
+ if (this.token) {
132
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
133
+ device_id: this.deviceId,
134
+ event_type: 'inference',
135
+ model_id: modelId,
136
+ latency_ms: latency,
137
+ tokens_generated: response.split(' ').length,
138
+ success: true,
139
+ }, {
140
+ headers: { Authorization: `Bearer ${this.token}` },
141
+ }).catch(() => { });
142
+ }
127
143
  return response;
128
144
  }
129
145
  catch (error) {
130
- console.error('Generation failed:', error);
131
- await this.sendTelemetry({
132
- event_type: 'inference',
133
- model_id: modelId,
134
- success: false,
135
- error_message: String(error)
136
- });
146
+ if (this.token) {
147
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
148
+ device_id: this.deviceId,
149
+ event_type: 'inference',
150
+ model_id: modelId,
151
+ success: false,
152
+ error_message: error.message,
153
+ }, {
154
+ headers: { Authorization: `Bearer ${this.token}` },
155
+ }).catch(() => { });
156
+ }
137
157
  throw error;
138
158
  }
139
159
  }
140
- async sendTelemetry(data) {
160
+ async transcribe(modelId, audioInput, options = {}) {
161
+ if (!this.models.has(modelId)) {
162
+ await this.loadModel(modelId);
163
+ }
164
+ const { pipe, info } = this.models.get(modelId);
165
+ if (info.category !== 'stt') {
166
+ throw new Error(`Model "${modelId}" is not an STT model. Use generate() for LLMs.`);
167
+ }
168
+ const startTime = Date.now();
141
169
  try {
142
- await this.api.post('/telemetry', {
143
- device_id: this.deviceId,
144
- ...data
170
+ const result = await pipe(audioInput, {
171
+ language: options.language || 'en',
172
+ return_timestamps: options.returnTimestamps || false,
145
173
  });
174
+ const text = result.text;
175
+ const latency = Date.now() - startTime;
176
+ if (this.token) {
177
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
178
+ device_id: this.deviceId,
179
+ event_type: 'inference',
180
+ model_id: modelId,
181
+ latency_ms: latency,
182
+ success: true,
183
+ }, {
184
+ headers: { Authorization: `Bearer ${this.token}` },
185
+ }).catch(() => { });
186
+ }
187
+ return text;
146
188
  }
147
189
  catch (error) {
148
- console.error('Failed to send telemetry:', error);
190
+ if (this.token) {
191
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
192
+ device_id: this.deviceId,
193
+ event_type: 'inference',
194
+ model_id: modelId,
195
+ success: false,
196
+ error_message: error.message,
197
+ }, {
198
+ headers: { Authorization: `Bearer ${this.token}` },
199
+ }).catch(() => { });
200
+ }
201
+ throw error;
149
202
  }
150
203
  }
151
- getDeviceId() {
152
- return this.deviceId;
153
- }
154
204
  }
155
205
  export default SlyOS;
156
- export { SlyOS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emilshirokikh/slyos-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "SlyOS - On-Device AI SDK for Web and Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -1,204 +1,257 @@
1
- import axios, { AxiosInstance } from 'axios';
2
- import { pipeline } from '@huggingface/transformers';
1
+ import axios from 'axios';
2
+ import { pipeline, env } from '@huggingface/transformers';
3
+
4
+ // @ts-ignore - Force CPU in Node.js
5
+ if (env.backends?.onnx?.wasm) {
6
+ env.backends.onnx.wasm.proxy = false;
7
+ }
3
8
 
4
9
  interface SlyOSConfig {
5
10
  apiKey: string;
6
11
  apiUrl?: string;
7
12
  }
8
13
 
14
+ interface GenerateOptions {
15
+ temperature?: number;
16
+ maxTokens?: number;
17
+ topP?: number;
18
+ }
19
+
20
+ interface TranscribeOptions {
21
+ language?: string;
22
+ returnTimestamps?: boolean;
23
+ }
24
+
25
+ type ModelCategory = 'llm' | 'tts' | 'stt';
26
+
9
27
  interface ModelInfo {
10
- id: string;
11
- name: string;
12
- displayName: string;
13
- size: number;
14
- requirements: {
15
- minMemoryMB: number;
16
- minStorageMB: number;
17
- platforms: string[];
18
- };
28
+ hfModel: string;
29
+ task: string;
30
+ category: ModelCategory;
19
31
  }
20
32
 
33
+ const modelMap: Record<string, ModelInfo> = {
34
+ // LLM models (1B+)
35
+ 'quantum-1.7b': {
36
+ hfModel: 'HuggingFaceTB/SmolLM2-1.7B-Instruct',
37
+ task: 'text-generation',
38
+ category: 'llm',
39
+ },
40
+ 'quantum-3b': {
41
+ hfModel: 'meta-llama/Llama-3.2-3B-Instruct',
42
+ task: 'text-generation',
43
+ category: 'llm',
44
+ },
45
+ 'quantum-code-3b': {
46
+ hfModel: 'Qwen/Qwen2.5-Coder-3B-Instruct',
47
+ task: 'text-generation',
48
+ category: 'llm',
49
+ },
50
+ 'quantum-8b': {
51
+ hfModel: 'meta-llama/Llama-3.1-8B-Instruct',
52
+ task: 'text-generation',
53
+ category: 'llm',
54
+ },
55
+ // STT models
56
+ 'voicecore-base': {
57
+ hfModel: 'onnx-community/whisper-base',
58
+ task: 'automatic-speech-recognition',
59
+ category: 'stt',
60
+ },
61
+ 'voicecore-small': {
62
+ hfModel: 'onnx-community/whisper-small',
63
+ task: 'automatic-speech-recognition',
64
+ category: 'stt',
65
+ },
66
+ };
67
+
21
68
  class SlyOS {
22
69
  private apiKey: string;
23
70
  private apiUrl: string;
24
- private api: AxiosInstance;
25
71
  private deviceId: string;
72
+ private token: string | null = null;
26
73
  private models: Map<string, any> = new Map();
27
74
 
28
75
  constructor(config: SlyOSConfig) {
29
76
  this.apiKey = config.apiKey;
30
- this.apiUrl = config.apiUrl || 'http://slyos-prod.eba-qjz3cmgq.us-east-2.elasticbeanstalk.com';
31
-
32
- this.api = axios.create({
33
- baseURL: `${this.apiUrl}/api`,
34
- headers: {
35
- 'Authorization': `Bearer ${this.apiKey}`,
36
- 'Content-Type': 'application/json'
37
- }
77
+ this.apiUrl = config.apiUrl || 'https://api.slyos.world';
78
+ this.deviceId = `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
79
+ }
80
+
81
+ async initialize(): Promise<void> {
82
+ // Authenticate using API key
83
+ const authRes = await axios.post(`${this.apiUrl}/api/auth/sdk`, {
84
+ apiKey: this.apiKey,
38
85
  });
86
+ this.token = authRes.data.token;
39
87
 
40
- this.deviceId = this.generateDeviceId();
88
+ // Register this device
89
+ await axios.post(`${this.apiUrl}/api/devices/register`, {
90
+ device_id: this.deviceId,
91
+ platform: typeof window !== 'undefined' ? 'web' : 'nodejs',
92
+ os_version: typeof window !== 'undefined' ? navigator.userAgent : process.version,
93
+ total_memory_mb: 4096,
94
+ cpu_cores: 4,
95
+ has_gpu: false,
96
+ }, {
97
+ headers: { Authorization: `Bearer ${this.token}` },
98
+ });
41
99
  }
42
100
 
43
- private generateDeviceId(): string {
44
- return `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
101
+ getAvailableModels(): Record<string, { models: string[] }> {
102
+ const grouped: Record<string, string[]> = { llm: [], stt: [] };
103
+ for (const [id, info] of Object.entries(modelMap)) {
104
+ if (!grouped[info.category]) grouped[info.category] = [];
105
+ grouped[info.category].push(id);
106
+ }
107
+ return Object.fromEntries(
108
+ Object.entries(grouped).map(([cat, models]) => [cat, { models }])
109
+ );
45
110
  }
46
111
 
47
- async initialize(): Promise<void> {
48
- console.log('🔥 SlyOS SDK Initializing...');
49
-
112
+ async loadModel(modelId: string): Promise<void> {
113
+ const info = modelMap[modelId];
114
+ if (!info) {
115
+ throw new Error(
116
+ `Unknown model "${modelId}". Available: ${Object.keys(modelMap).join(', ')}`
117
+ );
118
+ }
119
+
50
120
  try {
51
- await this.api.post('/devices/register', {
52
- device_id: this.deviceId,
53
- platform: this.detectPlatform(),
54
- os_version: navigator.userAgent,
55
- total_memory_mb: this.getMemoryInfo(),
56
- cpu_cores: navigator.hardwareConcurrency || 4
121
+ const pipe = await pipeline(info.task as any, info.hfModel, {
122
+ device: 'cpu',
123
+ dtype: 'fp32',
57
124
  });
58
- console.log('✅ Device registered:', this.deviceId);
59
- } catch (error) {
60
- console.error('Failed to register device:', error);
61
- }
62
- }
125
+ this.models.set(modelId, { pipe, info });
63
126
 
64
- private detectPlatform(): string {
65
- const ua = navigator.userAgent.toLowerCase();
66
- if (ua.includes('iphone') || ua.includes('ipad')) return 'ios';
67
- if (ua.includes('android')) return 'android';
68
- return 'web';
127
+ if (this.token) {
128
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
129
+ device_id: this.deviceId,
130
+ event_type: 'model_load',
131
+ model_id: modelId,
132
+ success: true,
133
+ }, {
134
+ headers: { Authorization: `Bearer ${this.token}` },
135
+ }).catch(() => {});
136
+ }
137
+ } catch (error: any) {
138
+ if (this.token) {
139
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
140
+ device_id: this.deviceId,
141
+ event_type: 'model_load',
142
+ model_id: modelId,
143
+ success: false,
144
+ error_message: error.message,
145
+ }, {
146
+ headers: { Authorization: `Bearer ${this.token}` },
147
+ }).catch(() => {});
148
+ }
149
+ throw error;
150
+ }
69
151
  }
70
152
 
71
- private getMemoryInfo(): number {
72
- // @ts-ignore
73
- return (navigator.deviceMemory || 4) * 1024;
74
- }
153
+ async generate(modelId: string, prompt: string, options: GenerateOptions = {}): Promise<string> {
154
+ if (!this.models.has(modelId)) {
155
+ await this.loadModel(modelId);
156
+ }
75
157
 
76
- async getAvailableModels(): Promise<ModelInfo[]> {
77
- try {
78
- const res = await this.api.get('/models');
79
- return res.data.map((m: any) => ({
80
- id: m.model_id,
81
- name: m.name,
82
- displayName: m.display_name,
83
- size: m.size_q4,
84
- requirements: {
85
- minMemoryMB: parseInt(m.memory_required) || 512,
86
- minStorageMB: m.size_q4 + 100,
87
- platforms: ['ios', 'android', 'web']
88
- }
89
- }));
90
- } catch (error) {
91
- console.error('Failed to fetch models:', error);
92
- return [];
158
+ const { pipe, info } = this.models.get(modelId);
159
+ if (info.category !== 'llm') {
160
+ throw new Error(`Model "${modelId}" is not an LLM. Use transcribe() for STT models.`);
93
161
  }
94
- }
95
162
 
96
- async loadModel(modelId: string): Promise<void> {
97
- console.log(`📥 Loading model: ${modelId}`);
98
-
99
163
  const startTime = Date.now();
100
164
 
101
165
  try {
102
- const modelMap: Record<string, string> = {
103
- 'quantum-135m': 'HuggingFaceTB/SmolLM2-135M-Instruct',
104
- 'quantum-360m': 'HuggingFaceTB/SmolLM2-360M-Instruct',
105
- 'quantum-1.7b': 'HuggingFaceTB/SmolLM2-1.7B-Instruct'
106
- };
107
-
108
- const hfModel = modelMap[modelId] || modelMap['quantum-360m'];
109
-
110
- const generator = await pipeline('text-generation', hfModel, {
111
- device: 'webgpu',
112
- dtype: 'q4'
166
+ const result = await pipe(prompt, {
167
+ max_new_tokens: options.maxTokens || 100,
168
+ temperature: options.temperature || 0.7,
169
+ top_p: options.topP || 0.9,
170
+ do_sample: true,
113
171
  });
114
172
 
115
- this.models.set(modelId, generator);
116
-
117
- const loadTime = Date.now() - startTime;
118
- console.log(`✅ Model loaded in ${loadTime}ms`);
119
-
120
- await this.sendTelemetry({
121
- event_type: 'model_load',
122
- model_id: modelId,
123
- latency_ms: loadTime,
124
- success: true
125
- });
173
+ const response = result[0].generated_text;
174
+ const latency = Date.now() - startTime;
126
175
 
127
- } catch (error) {
128
- console.error('Failed to load model:', error);
129
-
130
- await this.sendTelemetry({
131
- event_type: 'model_load',
132
- model_id: modelId,
133
- success: false,
134
- error_message: String(error)
135
- });
176
+ if (this.token) {
177
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
178
+ device_id: this.deviceId,
179
+ event_type: 'inference',
180
+ model_id: modelId,
181
+ latency_ms: latency,
182
+ tokens_generated: response.split(' ').length,
183
+ success: true,
184
+ }, {
185
+ headers: { Authorization: `Bearer ${this.token}` },
186
+ }).catch(() => {});
187
+ }
136
188
 
189
+ return response;
190
+ } catch (error: any) {
191
+ if (this.token) {
192
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
193
+ device_id: this.deviceId,
194
+ event_type: 'inference',
195
+ model_id: modelId,
196
+ success: false,
197
+ error_message: error.message,
198
+ }, {
199
+ headers: { Authorization: `Bearer ${this.token}` },
200
+ }).catch(() => {});
201
+ }
137
202
  throw error;
138
203
  }
139
204
  }
140
205
 
141
- async generate(modelId: string, prompt: string, options?: any): Promise<string> {
206
+ async transcribe(modelId: string, audioInput: any, options: TranscribeOptions = {}): Promise<string> {
142
207
  if (!this.models.has(modelId)) {
143
208
  await this.loadModel(modelId);
144
209
  }
145
210
 
146
- const generator = this.models.get(modelId);
211
+ const { pipe, info } = this.models.get(modelId);
212
+ if (info.category !== 'stt') {
213
+ throw new Error(`Model "${modelId}" is not an STT model. Use generate() for LLMs.`);
214
+ }
215
+
147
216
  const startTime = Date.now();
148
217
 
149
218
  try {
150
- const result = await generator(prompt, {
151
- max_new_tokens: options?.maxTokens || 100,
152
- temperature: options?.temperature || 0.7,
153
- top_p: options?.topP || 0.9,
154
- ...options
219
+ const result = await pipe(audioInput, {
220
+ language: options.language || 'en',
221
+ return_timestamps: options.returnTimestamps || false,
155
222
  });
156
223
 
224
+ const text = result.text;
157
225
  const latency = Date.now() - startTime;
158
- const response = result[0].generated_text;
159
- const tokens = response.split(' ').length;
160
-
161
- await this.sendTelemetry({
162
- event_type: 'inference',
163
- model_id: modelId,
164
- latency_ms: latency,
165
- tokens_generated: tokens,
166
- success: true
167
- });
168
-
169
- console.log(`⚡ Generated ${tokens} tokens in ${latency}ms`);
170
-
171
- return response;
172
226
 
173
- } catch (error) {
174
- console.error('Generation failed:', error);
175
-
176
- await this.sendTelemetry({
177
- event_type: 'inference',
178
- model_id: modelId,
179
- success: false,
180
- error_message: String(error)
181
- });
227
+ if (this.token) {
228
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
229
+ device_id: this.deviceId,
230
+ event_type: 'inference',
231
+ model_id: modelId,
232
+ latency_ms: latency,
233
+ success: true,
234
+ }, {
235
+ headers: { Authorization: `Bearer ${this.token}` },
236
+ }).catch(() => {});
237
+ }
182
238
 
239
+ return text;
240
+ } catch (error: any) {
241
+ if (this.token) {
242
+ await axios.post(`${this.apiUrl}/api/telemetry`, {
243
+ device_id: this.deviceId,
244
+ event_type: 'inference',
245
+ model_id: modelId,
246
+ success: false,
247
+ error_message: error.message,
248
+ }, {
249
+ headers: { Authorization: `Bearer ${this.token}` },
250
+ }).catch(() => {});
251
+ }
183
252
  throw error;
184
253
  }
185
254
  }
186
-
187
- private async sendTelemetry(data: any): Promise<void> {
188
- try {
189
- await this.api.post('/telemetry', {
190
- device_id: this.deviceId,
191
- ...data
192
- });
193
- } catch (error) {
194
- console.error('Failed to send telemetry:', error);
195
- }
196
- }
197
-
198
- getDeviceId(): string {
199
- return this.deviceId;
200
- }
201
255
  }
202
256
 
203
257
  export default SlyOS;
204
- export { SlyOS, SlyOSConfig, ModelInfo };