@emilshirokikh/slyos-sdk 1.0.0 → 1.0.4
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 +303 -25
- package/dist/index.d.ts +6 -19
- package/dist/index.js +81 -121
- package/package.json +1 -1
- package/src/index.ts +91 -151
package/README.md
CHANGED
|
@@ -1,48 +1,326 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# 🔥 @emilshirokikh/slyos-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official SDK for SlyOS on-device AI platform. Run AI models locally in browsers and Node.js.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📦 Installation
|
|
6
8
|
```bash
|
|
7
|
-
npm install @
|
|
9
|
+
npm install @emilshirokikh/slyos-sdk
|
|
8
10
|
```
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
**npm:** https://www.npmjs.com/package/@emilshirokikh/slyos-sdk
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🚀 Quick Start
|
|
11
17
|
```javascript
|
|
12
|
-
import SlyOS from '@
|
|
18
|
+
import SlyOS from '@emilshirokikh/slyos-sdk';
|
|
13
19
|
|
|
14
|
-
// Initialize
|
|
20
|
+
// 1. Initialize
|
|
15
21
|
const sdk = new SlyOS({
|
|
16
|
-
apiKey: '
|
|
22
|
+
apiKey: 'sk_live_your_api_key'
|
|
17
23
|
});
|
|
18
24
|
await sdk.initialize();
|
|
19
25
|
|
|
20
|
-
// Load model (downloads
|
|
26
|
+
// 2. Load model (downloads ~200MB once)
|
|
21
27
|
await sdk.loadModel('quantum-360m');
|
|
22
28
|
|
|
23
|
-
// Generate
|
|
24
|
-
const response = await sdk.generate('quantum-360m',
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
313
|
+
---
|
|
37
314
|
|
|
38
|
-
|
|
39
|
-
- Node.js (v18+)
|
|
40
|
-
- React Native (coming soon)
|
|
315
|
+
## 🙏 Credits
|
|
41
316
|
|
|
42
|
-
|
|
317
|
+
Built with Hugging Face Transformers.js
|
|
43
318
|
|
|
44
|
-
|
|
319
|
+
---
|
|
45
320
|
|
|
46
|
-
##
|
|
321
|
+
## 📞 Support
|
|
47
322
|
|
|
48
|
-
|
|
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,20 @@ interface SlyOSConfig {
|
|
|
2
2
|
apiKey: string;
|
|
3
3
|
apiUrl?: string;
|
|
4
4
|
}
|
|
5
|
-
interface
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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;
|
|
15
9
|
}
|
|
16
10
|
declare class SlyOS {
|
|
17
11
|
private apiKey;
|
|
18
12
|
private apiUrl;
|
|
19
|
-
private api;
|
|
20
13
|
private deviceId;
|
|
14
|
+
private token;
|
|
21
15
|
private models;
|
|
22
16
|
constructor(config: SlyOSConfig);
|
|
23
|
-
private generateDeviceId;
|
|
24
17
|
initialize(): Promise<void>;
|
|
25
|
-
private detectPlatform;
|
|
26
|
-
private getMemoryInfo;
|
|
27
|
-
getAvailableModels(): Promise<ModelInfo[]>;
|
|
28
18
|
loadModel(modelId: string): Promise<void>;
|
|
29
|
-
generate(modelId: string, prompt: string, options?:
|
|
30
|
-
private sendTelemetry;
|
|
31
|
-
getDeviceId(): string;
|
|
19
|
+
generate(modelId: string, prompt: string, options?: GenerateOptions): Promise<string>;
|
|
32
20
|
}
|
|
33
21
|
export default SlyOS;
|
|
34
|
-
export { SlyOS, SlyOSConfig, ModelInfo };
|
package/dist/index.js
CHANGED
|
@@ -1,106 +1,74 @@
|
|
|
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
|
+
}
|
|
3
7
|
class SlyOS {
|
|
4
8
|
constructor(config) {
|
|
9
|
+
this.token = null;
|
|
5
10
|
this.models = new Map();
|
|
6
11
|
this.apiKey = config.apiKey;
|
|
7
|
-
this.apiUrl = config.apiUrl || '
|
|
8
|
-
this.
|
|
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)}`;
|
|
12
|
+
this.apiUrl = config.apiUrl || 'https://api.slyos.world';
|
|
13
|
+
this.deviceId = `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
19
14
|
}
|
|
20
15
|
async initialize() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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;
|
|
47
|
-
}
|
|
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 [];
|
|
66
|
-
}
|
|
16
|
+
const loginRes = await axios.post(`${this.apiUrl}/api/auth/login`, {
|
|
17
|
+
email: 'admin@demo.com',
|
|
18
|
+
password: 'admin123'
|
|
19
|
+
});
|
|
20
|
+
this.token = loginRes.data.token;
|
|
21
|
+
await axios.post(`${this.apiUrl}/api/devices/register`, {
|
|
22
|
+
device_id: this.deviceId,
|
|
23
|
+
platform: typeof window !== 'undefined' ? 'web' : 'nodejs',
|
|
24
|
+
os_version: typeof window !== 'undefined' ? navigator.userAgent : process.version,
|
|
25
|
+
total_memory_mb: 4096,
|
|
26
|
+
cpu_cores: 4,
|
|
27
|
+
has_gpu: false
|
|
28
|
+
}, {
|
|
29
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
30
|
+
});
|
|
67
31
|
}
|
|
68
32
|
async loadModel(modelId) {
|
|
69
|
-
|
|
70
|
-
|
|
33
|
+
const modelMap = {
|
|
34
|
+
'quantum-135m': 'HuggingFaceTB/SmolLM2-135M-Instruct',
|
|
35
|
+
'quantum-360m': 'HuggingFaceTB/SmolLM2-360M-Instruct',
|
|
36
|
+
'quantum-1.7b': 'HuggingFaceTB/SmolLM2-1.7B-Instruct'
|
|
37
|
+
};
|
|
38
|
+
const hfModel = modelMap[modelId] || modelMap['quantum-360m'];
|
|
71
39
|
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
40
|
const generator = await pipeline('text-generation', hfModel, {
|
|
79
|
-
device: '
|
|
80
|
-
dtype: '
|
|
41
|
+
device: 'cpu',
|
|
42
|
+
dtype: 'fp32'
|
|
81
43
|
});
|
|
82
44
|
this.models.set(modelId, generator);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
45
|
+
if (this.token) {
|
|
46
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
47
|
+
device_id: this.deviceId,
|
|
48
|
+
event_type: 'model_load',
|
|
49
|
+
model_id: modelId,
|
|
50
|
+
success: true
|
|
51
|
+
}, {
|
|
52
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
53
|
+
}).catch(() => { });
|
|
54
|
+
}
|
|
91
55
|
}
|
|
92
56
|
catch (error) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
57
|
+
if (this.token) {
|
|
58
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
59
|
+
device_id: this.deviceId,
|
|
60
|
+
event_type: 'model_load',
|
|
61
|
+
model_id: modelId,
|
|
62
|
+
success: false,
|
|
63
|
+
error_message: error.message
|
|
64
|
+
}, {
|
|
65
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
66
|
+
}).catch(() => { });
|
|
67
|
+
}
|
|
100
68
|
throw error;
|
|
101
69
|
}
|
|
102
70
|
}
|
|
103
|
-
async generate(modelId, prompt, options) {
|
|
71
|
+
async generate(modelId, prompt, options = {}) {
|
|
104
72
|
if (!this.models.has(modelId)) {
|
|
105
73
|
await this.loadModel(modelId);
|
|
106
74
|
}
|
|
@@ -108,49 +76,41 @@ class SlyOS {
|
|
|
108
76
|
const startTime = Date.now();
|
|
109
77
|
try {
|
|
110
78
|
const result = await generator(prompt, {
|
|
111
|
-
max_new_tokens: options
|
|
112
|
-
temperature: options
|
|
113
|
-
top_p: options
|
|
114
|
-
|
|
79
|
+
max_new_tokens: options.maxTokens || 100,
|
|
80
|
+
temperature: options.temperature || 0.7,
|
|
81
|
+
top_p: options.topP || 0.9,
|
|
82
|
+
do_sample: true
|
|
115
83
|
});
|
|
116
|
-
const latency = Date.now() - startTime;
|
|
117
84
|
const response = result[0].generated_text;
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
85
|
+
const latency = Date.now() - startTime;
|
|
86
|
+
if (this.token) {
|
|
87
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
88
|
+
device_id: this.deviceId,
|
|
89
|
+
event_type: 'inference',
|
|
90
|
+
model_id: modelId,
|
|
91
|
+
latency_ms: latency,
|
|
92
|
+
tokens_generated: response.split(' ').length,
|
|
93
|
+
success: true
|
|
94
|
+
}, {
|
|
95
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
96
|
+
}).catch(() => { });
|
|
97
|
+
}
|
|
127
98
|
return response;
|
|
128
99
|
}
|
|
129
100
|
catch (error) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
if (this.token) {
|
|
102
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
103
|
+
device_id: this.deviceId,
|
|
104
|
+
event_type: 'inference',
|
|
105
|
+
model_id: modelId,
|
|
106
|
+
success: false,
|
|
107
|
+
error_message: error.message
|
|
108
|
+
}, {
|
|
109
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
110
|
+
}).catch(() => { });
|
|
111
|
+
}
|
|
137
112
|
throw error;
|
|
138
113
|
}
|
|
139
114
|
}
|
|
140
|
-
async sendTelemetry(data) {
|
|
141
|
-
try {
|
|
142
|
-
await this.api.post('/telemetry', {
|
|
143
|
-
device_id: this.deviceId,
|
|
144
|
-
...data
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
console.error('Failed to send telemetry:', error);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
getDeviceId() {
|
|
152
|
-
return this.deviceId;
|
|
153
|
-
}
|
|
154
115
|
}
|
|
155
116
|
export default SlyOS;
|
|
156
|
-
export { SlyOS };
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,144 +1,97 @@
|
|
|
1
|
-
import 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
|
|
|
9
|
-
interface
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
size: number;
|
|
14
|
-
requirements: {
|
|
15
|
-
minMemoryMB: number;
|
|
16
|
-
minStorageMB: number;
|
|
17
|
-
platforms: string[];
|
|
18
|
-
};
|
|
14
|
+
interface GenerateOptions {
|
|
15
|
+
temperature?: number;
|
|
16
|
+
maxTokens?: number;
|
|
17
|
+
topP?: number;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
class SlyOS {
|
|
22
21
|
private apiKey: string;
|
|
23
22
|
private apiUrl: string;
|
|
24
|
-
private api: AxiosInstance;
|
|
25
23
|
private deviceId: string;
|
|
24
|
+
private token: string | null = null;
|
|
26
25
|
private models: Map<string, any> = new Map();
|
|
27
26
|
|
|
28
27
|
constructor(config: SlyOSConfig) {
|
|
29
28
|
this.apiKey = config.apiKey;
|
|
30
|
-
this.apiUrl = config.apiUrl || '
|
|
31
|
-
|
|
32
|
-
this.api = axios.create({
|
|
33
|
-
baseURL: `${this.apiUrl}/api`,
|
|
34
|
-
headers: {
|
|
35
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
36
|
-
'Content-Type': 'application/json'
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
this.deviceId = this.generateDeviceId();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private generateDeviceId(): string {
|
|
44
|
-
return `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
29
|
+
this.apiUrl = config.apiUrl || 'https://api.slyos.world';
|
|
30
|
+
this.deviceId = `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
45
31
|
}
|
|
46
32
|
|
|
47
33
|
async initialize(): Promise<void> {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
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';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private getMemoryInfo(): number {
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
return (navigator.deviceMemory || 4) * 1024;
|
|
74
|
-
}
|
|
75
|
-
|
|
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 [];
|
|
93
|
-
}
|
|
34
|
+
const loginRes = await axios.post(`${this.apiUrl}/api/auth/login`, {
|
|
35
|
+
email: 'admin@demo.com',
|
|
36
|
+
password: 'admin123'
|
|
37
|
+
});
|
|
38
|
+
this.token = loginRes.data.token;
|
|
39
|
+
|
|
40
|
+
await axios.post(`${this.apiUrl}/api/devices/register`, {
|
|
41
|
+
device_id: this.deviceId,
|
|
42
|
+
platform: typeof window !== 'undefined' ? 'web' : 'nodejs',
|
|
43
|
+
os_version: typeof window !== 'undefined' ? navigator.userAgent : process.version,
|
|
44
|
+
total_memory_mb: 4096,
|
|
45
|
+
cpu_cores: 4,
|
|
46
|
+
has_gpu: false
|
|
47
|
+
}, {
|
|
48
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
49
|
+
});
|
|
94
50
|
}
|
|
95
51
|
|
|
96
52
|
async loadModel(modelId: string): Promise<void> {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
53
|
+
const modelMap: Record<string, string> = {
|
|
54
|
+
'quantum-135m': 'HuggingFaceTB/SmolLM2-135M-Instruct',
|
|
55
|
+
'quantum-360m': 'HuggingFaceTB/SmolLM2-360M-Instruct',
|
|
56
|
+
'quantum-1.7b': 'HuggingFaceTB/SmolLM2-1.7B-Instruct'
|
|
57
|
+
};
|
|
100
58
|
|
|
59
|
+
const hfModel = modelMap[modelId] || modelMap['quantum-360m'];
|
|
60
|
+
|
|
101
61
|
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
62
|
const generator = await pipeline('text-generation', hfModel, {
|
|
111
|
-
device: '
|
|
112
|
-
dtype: '
|
|
63
|
+
device: 'cpu',
|
|
64
|
+
dtype: 'fp32'
|
|
113
65
|
});
|
|
114
|
-
|
|
115
66
|
this.models.set(modelId, generator);
|
|
116
67
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} catch (error) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
68
|
+
if (this.token) {
|
|
69
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
70
|
+
device_id: this.deviceId,
|
|
71
|
+
event_type: 'model_load',
|
|
72
|
+
model_id: modelId,
|
|
73
|
+
success: true
|
|
74
|
+
}, {
|
|
75
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
76
|
+
}).catch(() => {});
|
|
77
|
+
}
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
if (this.token) {
|
|
80
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
81
|
+
device_id: this.deviceId,
|
|
82
|
+
event_type: 'model_load',
|
|
83
|
+
model_id: modelId,
|
|
84
|
+
success: false,
|
|
85
|
+
error_message: error.message
|
|
86
|
+
}, {
|
|
87
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
88
|
+
}).catch(() => {});
|
|
89
|
+
}
|
|
137
90
|
throw error;
|
|
138
91
|
}
|
|
139
92
|
}
|
|
140
93
|
|
|
141
|
-
async generate(modelId: string, prompt: string, options
|
|
94
|
+
async generate(modelId: string, prompt: string, options: GenerateOptions = {}): Promise<string> {
|
|
142
95
|
if (!this.models.has(modelId)) {
|
|
143
96
|
await this.loadModel(modelId);
|
|
144
97
|
}
|
|
@@ -148,57 +101,44 @@ class SlyOS {
|
|
|
148
101
|
|
|
149
102
|
try {
|
|
150
103
|
const result = await generator(prompt, {
|
|
151
|
-
max_new_tokens: options
|
|
152
|
-
temperature: options
|
|
153
|
-
top_p: options
|
|
154
|
-
|
|
104
|
+
max_new_tokens: options.maxTokens || 100,
|
|
105
|
+
temperature: options.temperature || 0.7,
|
|
106
|
+
top_p: options.topP || 0.9,
|
|
107
|
+
do_sample: true
|
|
155
108
|
});
|
|
156
109
|
|
|
157
|
-
const latency = Date.now() - startTime;
|
|
158
110
|
const response = result[0].generated_text;
|
|
159
|
-
const
|
|
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
|
-
});
|
|
111
|
+
const latency = Date.now() - startTime;
|
|
168
112
|
|
|
169
|
-
|
|
113
|
+
if (this.token) {
|
|
114
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
115
|
+
device_id: this.deviceId,
|
|
116
|
+
event_type: 'inference',
|
|
117
|
+
model_id: modelId,
|
|
118
|
+
latency_ms: latency,
|
|
119
|
+
tokens_generated: response.split(' ').length,
|
|
120
|
+
success: true
|
|
121
|
+
}, {
|
|
122
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
123
|
+
}).catch(() => {});
|
|
124
|
+
}
|
|
170
125
|
|
|
171
126
|
return response;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
127
|
+
} catch (error: any) {
|
|
128
|
+
if (this.token) {
|
|
129
|
+
await axios.post(`${this.apiUrl}/api/telemetry`, {
|
|
130
|
+
device_id: this.deviceId,
|
|
131
|
+
event_type: 'inference',
|
|
132
|
+
model_id: modelId,
|
|
133
|
+
success: false,
|
|
134
|
+
error_message: error.message
|
|
135
|
+
}, {
|
|
136
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
137
|
+
}).catch(() => {});
|
|
138
|
+
}
|
|
183
139
|
throw error;
|
|
184
140
|
}
|
|
185
141
|
}
|
|
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
142
|
}
|
|
202
143
|
|
|
203
144
|
export default SlyOS;
|
|
204
|
-
export { SlyOS, SlyOSConfig, ModelInfo };
|