@framers/agentos-ext-streaming-stt-deepgram 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AA4BjE,iFAAiF;AACjF,MAAM,4BAA4B,GAAG,wBAAwB,CAAC;AAE9D,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAc;IACvD,OAAO,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO;QACL,EAAE,EAAE,wBAAwB;QAC5B,WAAW,EAAE;YACX;gBACE,EAAE,EAAE,wBAAwB;gBAC5B,IAAI,EAAE,4BAA4B;gBAClC,OAAO,EAAE,GAAG;gBACZ,eAAe,EAAE,IAAI;gBACrB,QAAQ,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAAE;aAC/C;SACF;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACL,uBAAuB,EACvB,eAAe,GAChB,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @file types.ts
3
+ * @description Deepgram-specific configuration types for the streaming STT extension pack.
4
+ *
5
+ * These types augment the generic {@link StreamingSTTConfig} with Deepgram WebSocket
6
+ * API options that have no counterpart in the core voice pipeline interface.
7
+ *
8
+ * @module streaming-stt-deepgram/types
9
+ */
10
+ /**
11
+ * Deepgram-specific configuration for the streaming STT session.
12
+ *
13
+ * All fields are optional — sensible defaults are applied when omitted.
14
+ * The `apiKey` field is required and must be a valid Deepgram API key.
15
+ */
16
+ export interface DeepgramStreamingConfig {
17
+ /**
18
+ * Deepgram API key. Must be set to a non-empty string; the pack reads this
19
+ * from the `DEEPGRAM_API_KEY` secret when constructed via {@link createExtensionPack}.
20
+ */
21
+ apiKey: string;
22
+ /**
23
+ * Deepgram model name.
24
+ * @defaultValue 'nova-2'
25
+ * @see {@link https://developers.deepgram.com/docs/models}
26
+ */
27
+ model?: string;
28
+ /**
29
+ * BCP-47 language code for recognition (e.g. `'en-US'`, `'fr-FR'`).
30
+ * @defaultValue 'en-US'
31
+ */
32
+ language?: string;
33
+ /**
34
+ * Whether to insert punctuation into the transcript.
35
+ * @defaultValue true
36
+ */
37
+ punctuate?: boolean;
38
+ /**
39
+ * Whether to emit interim (non-final) transcript events.
40
+ * @defaultValue true
41
+ */
42
+ interimResults?: boolean;
43
+ /**
44
+ * Whether to enable speaker diarization (speaker turn segmentation).
45
+ * When `true`, each {@link TranscriptWord} in the result carries a `speaker`
46
+ * label populated by {@link extractSpeakerFromWords}.
47
+ * @defaultValue false
48
+ */
49
+ diarize?: boolean;
50
+ /**
51
+ * Custom keyword boosting list. Deepgram will upweight these terms during
52
+ * recognition. Format: `['keyword:boost']` where boost is an optional float.
53
+ * @see {@link https://developers.deepgram.com/docs/keywords}
54
+ */
55
+ keywords?: string[];
56
+ /**
57
+ * Deepgram native endpointing duration in milliseconds.
58
+ * Set to `false` to disable provider-side endpointing (the voice pipeline's
59
+ * {@link IEndpointDetector} is then solely responsible for utterance segmentation).
60
+ * @defaultValue false
61
+ */
62
+ endpointing?: number | false;
63
+ }
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B"}
package/dist/types.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @file types.ts
3
+ * @description Deepgram-specific configuration types for the streaming STT extension pack.
4
+ *
5
+ * These types augment the generic {@link StreamingSTTConfig} with Deepgram WebSocket
6
+ * API options that have no counterpart in the core voice pipeline interface.
7
+ *
8
+ * @module streaming-stt-deepgram/types
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
package/manifest.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "@framers/agentos-ext-streaming-stt-deepgram",
3
+ "version": "0.1.0",
4
+ "description": "Real-time streaming STT via Deepgram WebSocket API",
5
+ "kind": "streaming-stt-provider",
6
+ "extensionId": "streaming-stt-deepgram",
7
+ "entryPoint": "./dist/index.js"
8
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@framers/agentos-ext-streaming-stt-deepgram",
3
+ "version": "0.2.0",
4
+ "description": "Real-time streaming STT via Deepgram WebSocket API for AgentOS voice pipeline",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src",
17
+ "SKILL.md",
18
+ "manifest.json"
19
+ ],
20
+ "peerDependencies": {
21
+ "@framers/agentos": "^0.1.0"
22
+ },
23
+ "dependencies": {
24
+ "ws": "^8.17.0"
25
+ },
26
+ "devDependencies": {
27
+ "typescript": "^5.5.0",
28
+ "vitest": "^1.6.0",
29
+ "@types/ws": "^8.5.0",
30
+ "@framers/agentos": "0.1.94"
31
+ },
32
+ "license": "MIT",
33
+ "author": "Frame.dev",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/framersai/agentos-extensions.git",
37
+ "directory": "registry/curated/voice/streaming-stt-deepgram"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.json",
44
+ "test": "vitest run"
45
+ }
46
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @file DeepgramDiarizationAdapter.ts
3
+ * @description Utilities for extracting speaker labels from Deepgram word-level
4
+ * diarization results.
5
+ *
6
+ * Deepgram's `diarize: true` option annotates each word in the transcript with
7
+ * a zero-indexed integer `speaker` field. This module converts that raw
8
+ * numeric label into the string format expected by {@link TranscriptWord.speaker}
9
+ * (`'Speaker_0'`, `'Speaker_1'`, …) and determines the majority speaker for
10
+ * an utterance.
11
+ *
12
+ * @module streaming-stt-deepgram/DeepgramDiarizationAdapter
13
+ */
14
+
15
+ /**
16
+ * A single Deepgram word object as returned by the WebSocket API when
17
+ * `diarize: true` is passed in the connection query string.
18
+ *
19
+ * Only the fields used by this adapter are declared; the raw JSON may contain
20
+ * additional fields that are ignored.
21
+ */
22
+ export interface DeepgramWord {
23
+ /** Recognised word token. */
24
+ word: string;
25
+ /** Start time relative to the stream start in seconds. */
26
+ start: number;
27
+ /** End time relative to the stream start in seconds. */
28
+ end: number;
29
+ /** Recognition confidence in [0, 1]. */
30
+ confidence: number;
31
+ /**
32
+ * Zero-indexed speaker index assigned by Deepgram's diarization model.
33
+ * Present only when the session was opened with `diarize=true`.
34
+ */
35
+ speaker?: number;
36
+ /** Punctuated variant of {@link word} when `punctuate=true`. */
37
+ punctuated_word?: string;
38
+ }
39
+
40
+ /**
41
+ * Extract the majority speaker label from an array of Deepgram word objects.
42
+ *
43
+ * The function tallies votes by `speaker` index and returns the label for the
44
+ * speaker with the most words. Ties are broken by lowest index (i.e. the
45
+ * earliest-assigned speaker wins).
46
+ *
47
+ * Returns `undefined` when the array is empty or no word carries a `speaker`
48
+ * field (i.e. diarization was not requested for this session).
49
+ *
50
+ * @param words - Raw Deepgram word objects from `channel.alternatives[0].words`.
51
+ * @returns A string label such as `'Speaker_0'`, or `undefined`.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const words = [
56
+ * { word: 'Hello', speaker: 0, start: 0, end: 0.3, confidence: 0.99 },
57
+ * { word: 'world', speaker: 1, start: 0.4, end: 0.7, confidence: 0.97 },
58
+ * { word: 'today', speaker: 0, start: 0.8, end: 1.1, confidence: 0.95 },
59
+ * ];
60
+ * extractSpeakerFromWords(words); // → 'Speaker_0'
61
+ * ```
62
+ */
63
+ export function extractSpeakerFromWords(words: DeepgramWord[]): string | undefined {
64
+ if (words.length === 0) return undefined;
65
+
66
+ /** Vote counts keyed by speaker index. */
67
+ const votes = new Map<number, number>();
68
+
69
+ for (const w of words) {
70
+ if (w.speaker === undefined) continue;
71
+ votes.set(w.speaker, (votes.get(w.speaker) ?? 0) + 1);
72
+ }
73
+
74
+ if (votes.size === 0) return undefined;
75
+
76
+ // Find the speaker index with the highest vote count; ties broken by lowest index.
77
+ let majorityIndex = -1;
78
+ let majorityCount = -1;
79
+
80
+ for (const [index, count] of votes) {
81
+ if (count > majorityCount || (count === majorityCount && index < majorityIndex)) {
82
+ majorityCount = count;
83
+ majorityIndex = index;
84
+ }
85
+ }
86
+
87
+ return majorityIndex >= 0 ? `Speaker_${majorityIndex}` : undefined;
88
+ }
89
+
90
+ /**
91
+ * Map a Deepgram word object to the canonical `TranscriptWord`-compatible shape.
92
+ *
93
+ * Seconds are converted to milliseconds to match the voice pipeline convention.
94
+ * The `word` field prefers the punctuated variant when available.
95
+ *
96
+ * @param dw - Raw Deepgram word object.
97
+ * @returns A plain object matching the {@link TranscriptWord} interface.
98
+ */
99
+ export function mapDeepgramWord(dw: DeepgramWord): {
100
+ word: string;
101
+ start: number;
102
+ end: number;
103
+ confidence: number;
104
+ speaker?: string;
105
+ } {
106
+ return {
107
+ word: dw.punctuated_word ?? dw.word,
108
+ start: Math.round(dw.start * 1000),
109
+ end: Math.round(dw.end * 1000),
110
+ confidence: dw.confidence,
111
+ speaker: dw.speaker !== undefined ? `Speaker_${dw.speaker}` : undefined,
112
+ };
113
+ }