@ai-matrx/desktop-protocol 0.10.0 → 0.12.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/dist/client.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { BackoffOptions } from '@ai-matrx/realtime';
2
2
  export { RECONNECT_ALARM_ATTEMPTS } from '@ai-matrx/realtime';
3
3
  import { z } from 'zod';
4
- import { W as Welcome, D as DesktopProtocolError, C as CloseOutcome, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, e as ClientType } from './registry-B3NqARgh.cjs';
5
- export { i as isDesktopProtocolError } from './registry-B3NqARgh.cjs';
4
+ import { W as Welcome, D as DesktopProtocolError, C as CloseOutcome, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, e as ClientType, M as ModelsTranscribeResult, T as TranscriptionModelId, f as MlProgress } from './models-CxAHZMAM.cjs';
5
+ export { i as isDesktopProtocolError } from './models-CxAHZMAM.cjs';
6
6
  import { FrameHeader } from './frame.cjs';
7
7
 
8
8
  /** The subset of the WHATWG WebSocket the client uses — browser, React Native, `ws` and Workers all fit. */
@@ -213,4 +213,44 @@ declare function bindDesktopWake(client: Pick<DesktopClient, "wake">, options?:
213
213
  targets?: WakeTargets;
214
214
  }): () => void;
215
215
 
216
- export { type ClientTimers, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient };
216
+ /** fs.write carries at most 4 MiB of bytes (base64 in one message). */
217
+ declare const DESKTOP_TRANSCRIBE_MAX_BYTES: number;
218
+ interface DesktopTranscriberOptions {
219
+ /** Whisper size; omitted = the device's default. */
220
+ model?: TranscriptionModelId;
221
+ /** ISO 639-1; omitted = detect. */
222
+ language?: string;
223
+ /** Per call (first use installs the runtime and a model): default 15 minutes. */
224
+ timeoutMs?: number;
225
+ /** Progress for each call (install steps, then each segment as it is recognised). */
226
+ onProgress?: (progress: MlProgress) => void;
227
+ }
228
+ /** What a transcription returns: the shape `@ai-matrx/browser-audio`'s TranscriptionTransport expects. */
229
+ interface DesktopTranscript {
230
+ text: string;
231
+ language: string;
232
+ duration: number;
233
+ segments: Array<{
234
+ start: number;
235
+ end: number;
236
+ text: string;
237
+ }>;
238
+ result: ModelsTranscribeResult;
239
+ }
240
+ interface DesktopTranscriber {
241
+ /** Transcribe recorded audio on the device: written to its temp folder, transcribed, removed. */
242
+ transcribe(file: Blob, signal?: AbortSignal): Promise<DesktopTranscript>;
243
+ }
244
+ /**
245
+ * Speech to text on the person's own computer, from any surface connected to it (the app's
246
+ * screen, the web app or the phone through the relay). Structurally a
247
+ * `@ai-matrx/browser-audio` TranscriptionTransport, so every voice input on the platform can
248
+ * transcribe locally: `new BrowserAudioKernel({ transport: createDesktopTranscriber(client) })`.
249
+ *
250
+ * Audio travels as one `fs.write` into the device's temp folder (at most 4 MiB; longer
251
+ * recordings are chunked by the kernel), then `models.transcribe`, then `fs.delete` — every step
252
+ * an ordinary op, so this works through every transport with no special path.
253
+ */
254
+ declare function createDesktopTranscriber(client: DesktopClient, options?: DesktopTranscriberOptions): DesktopTranscriber;
255
+
256
+ export { type ClientTimers, DESKTOP_TRANSCRIBE_MAX_BYTES, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type DesktopTranscriber, type DesktopTranscriberOptions, type DesktopTranscript, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient, createDesktopTranscriber };
package/dist/client.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { BackoffOptions } from '@ai-matrx/realtime';
2
2
  export { RECONNECT_ALARM_ATTEMPTS } from '@ai-matrx/realtime';
3
3
  import { z } from 'zod';
4
- import { W as Welcome, D as DesktopProtocolError, C as CloseOutcome, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, e as ClientType } from './registry-B3NqARgh.js';
5
- export { i as isDesktopProtocolError } from './registry-B3NqARgh.js';
4
+ import { W as Welcome, D as DesktopProtocolError, C as CloseOutcome, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, e as ClientType, M as ModelsTranscribeResult, T as TranscriptionModelId, f as MlProgress } from './models-CxAHZMAM.js';
5
+ export { i as isDesktopProtocolError } from './models-CxAHZMAM.js';
6
6
  import { FrameHeader } from './frame.js';
7
7
 
8
8
  /** The subset of the WHATWG WebSocket the client uses — browser, React Native, `ws` and Workers all fit. */
@@ -213,4 +213,44 @@ declare function bindDesktopWake(client: Pick<DesktopClient, "wake">, options?:
213
213
  targets?: WakeTargets;
214
214
  }): () => void;
215
215
 
216
- export { type ClientTimers, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient };
216
+ /** fs.write carries at most 4 MiB of bytes (base64 in one message). */
217
+ declare const DESKTOP_TRANSCRIBE_MAX_BYTES: number;
218
+ interface DesktopTranscriberOptions {
219
+ /** Whisper size; omitted = the device's default. */
220
+ model?: TranscriptionModelId;
221
+ /** ISO 639-1; omitted = detect. */
222
+ language?: string;
223
+ /** Per call (first use installs the runtime and a model): default 15 minutes. */
224
+ timeoutMs?: number;
225
+ /** Progress for each call (install steps, then each segment as it is recognised). */
226
+ onProgress?: (progress: MlProgress) => void;
227
+ }
228
+ /** What a transcription returns: the shape `@ai-matrx/browser-audio`'s TranscriptionTransport expects. */
229
+ interface DesktopTranscript {
230
+ text: string;
231
+ language: string;
232
+ duration: number;
233
+ segments: Array<{
234
+ start: number;
235
+ end: number;
236
+ text: string;
237
+ }>;
238
+ result: ModelsTranscribeResult;
239
+ }
240
+ interface DesktopTranscriber {
241
+ /** Transcribe recorded audio on the device: written to its temp folder, transcribed, removed. */
242
+ transcribe(file: Blob, signal?: AbortSignal): Promise<DesktopTranscript>;
243
+ }
244
+ /**
245
+ * Speech to text on the person's own computer, from any surface connected to it (the app's
246
+ * screen, the web app or the phone through the relay). Structurally a
247
+ * `@ai-matrx/browser-audio` TranscriptionTransport, so every voice input on the platform can
248
+ * transcribe locally: `new BrowserAudioKernel({ transport: createDesktopTranscriber(client) })`.
249
+ *
250
+ * Audio travels as one `fs.write` into the device's temp folder (at most 4 MiB; longer
251
+ * recordings are chunked by the kernel), then `models.transcribe`, then `fs.delete` — every step
252
+ * an ordinary op, so this works through every transport with no special path.
253
+ */
254
+ declare function createDesktopTranscriber(client: DesktopClient, options?: DesktopTranscriberOptions): DesktopTranscriber;
255
+
256
+ export { type ClientTimers, DESKTOP_TRANSCRIBE_MAX_BYTES, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type DesktopTranscriber, type DesktopTranscriberOptions, type DesktopTranscript, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient, createDesktopTranscriber };
package/dist/client.js CHANGED
@@ -1639,11 +1639,68 @@ function bindDesktopWake(client, options = {}) {
1639
1639
  targets.window.removeEventListener("focus", onWake);
1640
1640
  };
1641
1641
  }
1642
+
1643
+ // src/client/transcribe.ts
1644
+ var DESKTOP_TRANSCRIBE_MAX_BYTES = 4 * 1024 * 1024;
1645
+ var EXT = {
1646
+ "audio/webm": "webm",
1647
+ "audio/ogg": "ogg",
1648
+ "audio/mp4": "m4a",
1649
+ "audio/mpeg": "mp3",
1650
+ "audio/wav": "wav",
1651
+ "audio/x-wav": "wav",
1652
+ "video/webm": "webm",
1653
+ "video/mp4": "mp4"
1654
+ };
1655
+ function base64(bytes) {
1656
+ let binary = "";
1657
+ for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
1658
+ return btoa(binary);
1659
+ }
1660
+ function createDesktopTranscriber(client, options = {}) {
1661
+ let temp = null;
1662
+ const tempDir = () => temp ??= client.request("sysinfo.get", {}).then((s) => s.paths.temp.replace(/\/$/, ""));
1663
+ return {
1664
+ async transcribe(file, signal) {
1665
+ if (file.size > DESKTOP_TRANSCRIBE_MAX_BYTES) {
1666
+ throw new DesktopProtocolError("PAYLOAD_TOO_LARGE", "Recording is larger than 4 MB", { retryable: false, data: { limit_bytes: DESKTOP_TRANSCRIBE_MAX_BYTES } });
1667
+ }
1668
+ const type = file.type.split(";")[0]?.trim() ?? "";
1669
+ const name = `matrx-transcribe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.${EXT[type] ?? "webm"}`;
1670
+ const path = `${await tempDir()}/${name}`;
1671
+ const bytes = new Uint8Array(await file.arrayBuffer());
1672
+ await client.request("fs.write", { path, content: base64(bytes), encoding: "base64", mode: 384 }, signal ? { signal } : {});
1673
+ let requestId = "";
1674
+ const off = options.onProgress ? client.on("models.progress", (payload) => {
1675
+ if (payload.request_id === requestId) options.onProgress?.(payload.progress);
1676
+ }) : () => void 0;
1677
+ try {
1678
+ const result = await client.request(
1679
+ "models.transcribe",
1680
+ { path, ...options.model ? { model: options.model } : {}, ...options.language ? { language: options.language } : {} },
1681
+ { timeoutMs: options.timeoutMs ?? 15 * 6e4, onRequestId: (id) => requestId = id, ...signal ? { signal } : {} }
1682
+ );
1683
+ return {
1684
+ text: result.text,
1685
+ language: result.language,
1686
+ duration: result.duration_s,
1687
+ segments: result.segments.map((s) => ({ start: s.start_s, end: s.end_s, text: s.text })),
1688
+ result
1689
+ };
1690
+ } finally {
1691
+ off();
1692
+ void client.request("fs.delete", { path, to_trash: false }).catch(() => void 0);
1693
+ }
1694
+ }
1695
+ };
1696
+ }
1642
1697
  export {
1698
+ DESKTOP_TRANSCRIBE_MAX_BYTES,
1643
1699
  DesktopProtocolError,
1644
1700
  RECONNECT_ALARM_ATTEMPTS,
1645
1701
  bindDesktopWake,
1646
1702
  createDesktopClient,
1703
+ createDesktopTranscriber,
1647
1704
  isDesktopProtocolError
1648
1705
  };
1649
1706
  //# sourceMappingURL=client.js.map