@archetypeai/ds-cli 0.5.7 → 0.6.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.
@@ -1,427 +0,0 @@
1
- ---
2
- name: embedding-upload
3
- description: Run an Embedding Lens by uploading a CSV file for server-side processing. Use when you want to upload a file and get embeddings without local streaming.
4
- argument-hint: [csv-file-path]
5
- ---
6
-
7
- # Embedding Lens — Upload File (Server-Side Processing)
8
-
9
- Generate a script that uploads a CSV file to the Archetype AI platform and extracts embeddings server-side. The server reads the file directly — no local streaming loop required. Supports both Python and JavaScript/Web.
10
-
11
- ## Frontend Architecture
12
-
13
- Decompose the UI into components. See `@rules/frontend-architecture` for conventions.
14
-
15
- ### Recommended decomposition
16
-
17
- | UI Area | Component | Pattern/Primitives | Key Props |
18
- |---------|-----------|-------------------|-----------|
19
- | File upload | `DataInput.svelte` | BackgroundCard, Button, Input | `onselect`, `status` |
20
- | Scatter plot | Reuse ScatterChart pattern | BackgroundCard, Chart | `data[]`, `categories` |
21
- | Progress | `StreamProgress.svelte` | BackgroundCard, Progress | `current`, `total` |
22
-
23
- - Use `@skills/create-dashboard` for the page layout
24
- - Extract upload and session logic into `$lib/api/embeddings.js`
25
-
26
- ---
27
-
28
- ## Python Implementation
29
-
30
- ### Requirements
31
-
32
- - `archetypeai` Python package
33
- - Environment variables: `ATAI_API_KEY`, optionally `ATAI_API_ENDPOINT`
34
-
35
- ### Architecture
36
-
37
- Uses `create_and_run_lens` with YAML config. After the session is created, upload the data CSV and configure a `csv_file_reader` input stream for server-side reading.
38
-
39
- #### 1. API Client Setup
40
-
41
- ```python
42
- from archetypeai.api_client import ArchetypeAI
43
- import os
44
-
45
- api_key = os.getenv("ATAI_API_KEY")
46
- api_endpoint = os.getenv("ATAI_API_ENDPOINT", ArchetypeAI.get_default_endpoint())
47
- client = ArchetypeAI(api_key, api_endpoint=api_endpoint)
48
- ```
49
-
50
- #### 2. Lens YAML Configuration
51
-
52
- ```yaml
53
- lens_name: Embedding Lens
54
- lens_config:
55
- model_pipeline:
56
- - processor_name: lens_timeseries_embedding_processor
57
- processor_config: {}
58
- model_parameters:
59
- model_name: OmegaEncoder
60
- model_version: OmegaEncoder::omega_embeddings_01
61
- normalize_input: true
62
- buffer_size: {window_size}
63
- csv_configs:
64
- timestamp_column: timestamp
65
- data_columns: ['a1', 'a2', 'a3', 'a4']
66
- window_size: {window_size}
67
- step_size: {step_size}
68
- output_streams:
69
- - stream_type: server_sent_events_writer
70
- ```
71
-
72
- #### 3. Event Builders
73
-
74
- ```python
75
- def build_input_event(file_id, window_size, step_size):
76
- return {
77
- "type": "input_stream.set",
78
- "event_data": {
79
- "stream_type": "csv_file_reader",
80
- "stream_config": {
81
- "file_id": file_id,
82
- "window_size": window_size,
83
- "step_size": step_size,
84
- "loop_recording": False,
85
- "output_format": ""
86
- }
87
- }
88
- }
89
-
90
- def build_output_event():
91
- return {
92
- "type": "output_stream.set",
93
- "event_data": {
94
- "stream_type": "server_side_events_writer",
95
- "stream_config": {}
96
- }
97
- }
98
- ```
99
-
100
- #### 4. Session Callback
101
-
102
- ```python
103
- def session_callback(session_id, session_endpoint, client, args):
104
- print(f"Session created: {session_id}")
105
-
106
- # Upload the data CSV
107
- data_resp = client.files.local.upload(args["data_file_path"])
108
- data_file_id = data_resp["file_id"]
109
-
110
- # Tell server to read the uploaded CSV
111
- client.lens.sessions.process_event(
112
- session_id,
113
- build_input_event(data_file_id, args["window_size"], args["step_size"])
114
- )
115
- client.lens.sessions.process_event(
116
- session_id,
117
- build_output_event()
118
- )
119
-
120
- # Collect embeddings via SSE
121
- sse_reader = client.lens.sessions.create_sse_consumer(
122
- session_id, max_read_time_sec=args["max_run_time_sec"]
123
- )
124
-
125
- embeddings = []
126
- try:
127
- for event in sse_reader.read(block=True):
128
- if stop_flag:
129
- break
130
- if isinstance(event, dict) and event.get("type") == "inference.result":
131
- ed = event.get("event_data", {})
132
- embedding = ed.get("response")
133
- meta = ed.get("query_metadata", {})
134
-
135
- # Flatten 4×768 → 3072D
136
- if isinstance(embedding, list) and len(embedding) > 0:
137
- if isinstance(embedding[0], list):
138
- flat = [val for row in embedding for val in row]
139
- else:
140
- flat = embedding
141
-
142
- embeddings.append({
143
- "window_index": len(embeddings),
144
- "query_timestamp": meta.get("query_timestamp", "N/A"),
145
- "read_index": meta.get("query_metadata", {}).get("read_index", "N/A"),
146
- "embedding": flat,
147
- })
148
- print(f"[{len(embeddings)}] Embedding: {len(flat)}D")
149
- finally:
150
- sse_reader.close()
151
- print(f"Collected {len(embeddings)} embeddings. Stopped.")
152
- ```
153
-
154
- #### 5. Create and Run Lens
155
-
156
- ```python
157
- client.lens.create_and_run_lens(
158
- yaml_config, session_callback,
159
- client=client, args=args
160
- )
161
- ```
162
-
163
- ### CLI Arguments
164
-
165
- ```
166
- --api-key API key (fallback to ATAI_API_KEY env var)
167
- --api-endpoint API endpoint (default from SDK)
168
- --data-file Path to CSV file to analyze (required)
169
- --window-size Window size in samples (default: 100)
170
- --step-size Step size in samples (default: 100)
171
- --max-run-time-sec Max runtime (default: 600)
172
- --output-file Path to save embeddings CSV (optional)
173
- ```
174
-
175
- ---
176
-
177
- ## Web / JavaScript Implementation
178
-
179
- Uses direct `fetch` calls to the Archetype AI REST API. The simplest embedding approach on web — just upload and collect results.
180
-
181
- ### API Reference
182
-
183
- | Operation | Method | Endpoint | Body |
184
- |-----------|--------|----------|------|
185
- | Upload file | POST | `/files` | `FormData` |
186
- | Register lens | POST | `/lens/register` | `{ lens_config: config }` |
187
- | Create session | POST | `/lens/sessions/create` | `{ lens_id }` |
188
- | Process event | POST | `/lens/sessions/events/process` | `{ session_id, event }` |
189
- | Delete lens | POST | `/lens/delete` | `{ lens_id }` |
190
- | Destroy session | POST | `/lens/sessions/destroy` | `{ session_id }` |
191
- | SSE consumer | GET | `/lens/sessions/consumer/{sessionId}` | — |
192
-
193
- ### Helper: API fetch wrapper
194
-
195
- ```typescript
196
- const API_ENDPOINT = 'https://api.u1.archetypeai.app/v0.5'
197
-
198
- async function apiPost<T>(path: string, apiKey: string, body: unknown, timeoutMs = 5000): Promise<T> {
199
- const controller = new AbortController()
200
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
201
-
202
- try {
203
- const response = await fetch(`${API_ENDPOINT}${path}`, {
204
- method: 'POST',
205
- headers: {
206
- Authorization: `Bearer ${apiKey}`,
207
- 'Content-Type': 'application/json',
208
- },
209
- body: JSON.stringify(body),
210
- signal: controller.signal,
211
- })
212
-
213
- if (!response.ok) {
214
- const errorBody = await response.json().catch(() => ({}))
215
- throw new Error(`API POST ${path} failed: ${response.status} - ${JSON.stringify(errorBody)}`)
216
- }
217
-
218
- return response.json()
219
- } finally {
220
- clearTimeout(timeoutId)
221
- }
222
- }
223
- ```
224
-
225
- ### Step 1: Upload the data CSV
226
-
227
- ```typescript
228
- const dataFormData = new FormData()
229
- dataFormData.append('file', dataFile) // File from <input type="file">
230
-
231
- const dataResponse = await fetch(`${API_ENDPOINT}/files`, {
232
- method: 'POST',
233
- headers: { Authorization: `Bearer ${apiKey}` },
234
- body: dataFormData,
235
- })
236
- const dataUpload = await dataResponse.json()
237
- const dataFileId = dataUpload.file_id
238
- ```
239
-
240
- ### Step 2: Register embedding lens and create session
241
-
242
- ```typescript
243
- const windowSize = 100
244
- const stepSize = 100
245
-
246
- const lensConfig = {
247
- lens_name: 'embedding_lens',
248
- lens_config: {
249
- model_pipeline: [
250
- { processor_name: 'lens_timeseries_embedding_processor', processor_config: {} },
251
- ],
252
- model_parameters: {
253
- model_name: 'OmegaEncoder',
254
- model_version: 'OmegaEncoder::omega_embeddings_01',
255
- normalize_input: true,
256
- buffer_size: windowSize,
257
- csv_configs: {
258
- timestamp_column: 'timestamp',
259
- data_columns: ['a1', 'a2', 'a3', 'a4'],
260
- window_size: windowSize,
261
- step_size: stepSize,
262
- },
263
- },
264
- output_streams: [
265
- { stream_type: 'server_sent_events_writer' },
266
- ],
267
- },
268
- }
269
-
270
- const registeredLens = await apiPost<{ lens_id: string }>(
271
- '/lens/register', apiKey, { lens_config: lensConfig }
272
- )
273
- const lensId = registeredLens.lens_id
274
-
275
- const session = await apiPost<{ session_id: string }>(
276
- '/lens/sessions/create', apiKey, { lens_id: lensId }
277
- )
278
- const sessionId = session.session_id
279
-
280
- await apiPost('/lens/delete', apiKey, { lens_id: lensId })
281
-
282
- // Wait for session ready (same waitForSessionReady pattern)
283
- async function waitForSessionReady(sessionId: string, maxWaitMs = 30000): Promise<boolean> {
284
- const start = Date.now()
285
- while (Date.now() - start < maxWaitMs) {
286
- const status = await apiPost<{ session_status: string }>(
287
- '/lens/sessions/events/process', apiKey,
288
- { session_id: sessionId, event: { type: 'session.status' } },
289
- 10000
290
- )
291
- if (status.session_status === 'LensSessionStatus.SESSION_STATUS_RUNNING' ||
292
- status.session_status === '3') return true
293
- if (status.session_status === 'LensSessionStatus.SESSION_STATUS_FAILED' ||
294
- status.session_status === '6') return false
295
- await new Promise(r => setTimeout(r, 500))
296
- }
297
- return false
298
- }
299
-
300
- await waitForSessionReady(sessionId)
301
- ```
302
-
303
- ### Step 3: Tell server to read the uploaded CSV
304
-
305
- ```typescript
306
- // Set input stream to CSV file reader
307
- await apiPost('/lens/sessions/events/process', apiKey, {
308
- session_id: sessionId,
309
- event: {
310
- type: 'input_stream.set',
311
- event_data: {
312
- stream_type: 'csv_file_reader',
313
- stream_config: {
314
- file_id: dataFileId,
315
- window_size: windowSize,
316
- step_size: stepSize,
317
- loop_recording: false,
318
- output_format: '',
319
- },
320
- },
321
- },
322
- }, 10000)
323
-
324
- // Enable SSE output
325
- await apiPost('/lens/sessions/events/process', apiKey, {
326
- session_id: sessionId,
327
- event: {
328
- type: 'output_stream.set',
329
- event_data: {
330
- stream_type: 'server_side_events_writer',
331
- stream_config: {},
332
- },
333
- },
334
- }, 10000)
335
- ```
336
-
337
- ### Step 4: Consume SSE embedding results
338
-
339
- ```typescript
340
- import { fetchEventSource } from '@microsoft/fetch-event-source'
341
-
342
- interface EmbeddingResult {
343
- windowIndex: number
344
- queryTimestamp: string
345
- readIndex: number | string
346
- embedding: number[] // 3072D flattened
347
- }
348
-
349
- const embeddings: EmbeddingResult[] = []
350
- const abortController = new AbortController()
351
-
352
- fetchEventSource(`${API_ENDPOINT}/lens/sessions/consumer/${sessionId}`, {
353
- headers: { Authorization: `Bearer ${apiKey}` },
354
- signal: abortController.signal,
355
- onmessage(event) {
356
- const parsed = JSON.parse(event.data)
357
-
358
- if (parsed.type === 'inference.result') {
359
- const response = parsed.event_data.response
360
- const meta = parsed.event_data.query_metadata
361
- const queryMeta = meta?.query_metadata ?? {}
362
-
363
- const flat = Array.isArray(response[0]) ? response.flat() : response
364
-
365
- embeddings.push({
366
- windowIndex: embeddings.length,
367
- queryTimestamp: meta?.query_timestamp ?? 'N/A',
368
- readIndex: queryMeta.read_index ?? 'N/A',
369
- embedding: flat,
370
- })
371
- console.log(`[${embeddings.length}] Embedding: ${flat.length}D`)
372
- }
373
-
374
- if (parsed.type === 'sse.stream.end') {
375
- console.log(`Complete. ${embeddings.length} embeddings collected.`)
376
- abortController.abort()
377
- }
378
- },
379
- })
380
- ```
381
-
382
- ### Step 5: Cleanup
383
-
384
- ```typescript
385
- abortController.abort()
386
- await apiPost('/lens/sessions/destroy', apiKey, { session_id: sessionId })
387
- ```
388
-
389
- ### Web Lifecycle Summary
390
-
391
- ```
392
- 1. Upload data CSV -> POST /files (FormData)
393
- 2. Register lens -> POST /lens/register { lens_config: config }
394
- 3. Create session -> POST /lens/sessions/create { lens_id }
395
- 4. Wait for ready -> POST /lens/sessions/events/process (poll)
396
- 5. Set input stream -> POST /lens/sessions/events/process { session_id, event: input_stream.set }
397
- 6. Set output stream -> POST /lens/sessions/events/process { session_id, event: output_stream.set }
398
- 7. Consume SSE results -> GET /lens/sessions/consumer/{sessionId}
399
- 8. Destroy session -> POST /lens/sessions/destroy { session_id }
400
- ```
401
-
402
- ---
403
-
404
- ## Embedding Response Structure
405
-
406
- The `inference.result` response contains:
407
- - `response`: nested list `(4, 768)` — one 768D embedding per input channel
408
- - Flatten to `3072D` by concatenating: `[a1_768D, a2_768D, a3_768D, a4_768D]`
409
- - `query_metadata.query_timestamp`: timestamp
410
- - `query_metadata.query_metadata.read_index`: window position in file
411
- - `query_metadata.query_metadata.file_id`: the file being analyzed
412
-
413
- ## Key Differences from Streaming Approaches
414
-
415
- | | Upload (this skill) | Stream from File | Stream from Sensor |
416
- |---|---|---|---|
417
- | Data reading | Server-side `csv_file_reader` | Local pandas/JS + windowed push | Local sensor + buffered push |
418
- | Local processing | None (just upload) | Window slicing | Sensor acquisition + buffering |
419
- | Best for | Batch embedding extraction | Controlled local streaming | Real-time from hardware |
420
-
421
- ## Key Implementation Notes
422
-
423
- - Default `window_size` and `step_size`: **100**
424
- - No n-shot files or KNN config — this is pure embedding extraction
425
- - Embeddings are `(4, 768)` per window — flatten to `3072D` for downstream use
426
- - Use UMAP/t-SNE for 2D/3D visualization
427
- - Combine with machine state lens results for labeled embedding plots