@dxos/plugin-transcription 0.8.2-main.12df754 → 0.8.2-main.36232bc
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/lib/browser/{TranscriptContainer-4D4BHE7G.mjs → TranscriptContainer-2VFHUHLE.mjs} +3 -3
- package/dist/lib/browser/app-graph-builder-TDP6PYV6.mjs +350 -0
- package/dist/lib/browser/app-graph-builder-TDP6PYV6.mjs.map +7 -0
- package/dist/lib/browser/{chunk-DR3NBV6Q.mjs → chunk-KSUYWWIU.mjs} +105 -78
- package/dist/lib/browser/chunk-KSUYWWIU.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5BE6RTNC.mjs → chunk-LTIQFX4W.mjs} +1 -1
- package/dist/lib/browser/{chunk-5BE6RTNC.mjs.map → chunk-LTIQFX4W.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-RHHJZQPM.mjs → chunk-NFVDICSJ.mjs} +133 -116
- package/dist/lib/browser/chunk-NFVDICSJ.mjs.map +7 -0
- package/dist/lib/browser/chunk-O6RY7FNK.mjs +27 -0
- package/dist/lib/browser/chunk-O6RY7FNK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5Q3R53U3.mjs → chunk-YRWBY6UK.mjs} +9 -21
- package/dist/lib/browser/chunk-YRWBY6UK.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +29 -17
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-ZQQEH27F.mjs → intent-resolver-ZWKYRFE7.mjs} +4 -4
- package/dist/lib/browser/{intent-resolver-ZQQEH27F.mjs.map → intent-resolver-ZWKYRFE7.mjs.map} +2 -2
- package/dist/lib/browser/{meeting-transcription-state-5D52VTHU.mjs → meeting-transcription-state-MNA2XROE.mjs} +2 -2
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-HETJ5XY6.mjs → react-surface-F32UNCKZ.mjs} +18 -7
- package/dist/lib/browser/react-surface-F32UNCKZ.mjs.map +7 -0
- package/dist/lib/browser/settings-6YAHKVKX.mjs +24 -0
- package/dist/lib/browser/settings-6YAHKVKX.mjs.map +7 -0
- package/dist/lib/browser/{transcriber-SMRLU2KY.mjs → transcriber-MSBS4VBI.mjs} +4 -4
- package/dist/lib/browser/types/index.mjs +3 -3
- package/dist/lib/node/{TranscriptContainer-ZWP6UKY6.cjs → TranscriptContainer-E2D7PKO3.cjs} +8 -8
- package/dist/lib/node/{TranscriptContainer-ZWP6UKY6.cjs.map → TranscriptContainer-E2D7PKO3.cjs.map} +2 -2
- package/dist/lib/node/app-graph-builder-W4VDMVGV.cjs +351 -0
- package/dist/lib/node/app-graph-builder-W4VDMVGV.cjs.map +7 -0
- package/dist/lib/node/{chunk-LA73IHCB.cjs → chunk-7XIIUVN3.cjs} +108 -80
- package/dist/lib/node/chunk-7XIIUVN3.cjs.map +7 -0
- package/dist/lib/node/{chunk-3QEJ5EBO.cjs → chunk-IXU57SCA.cjs} +10 -22
- package/dist/lib/node/chunk-IXU57SCA.cjs.map +7 -0
- package/dist/lib/node/{chunk-HYGDHS6X.cjs → chunk-JUGOXWES.cjs} +4 -4
- package/dist/lib/node/{chunk-HYGDHS6X.cjs.map → chunk-JUGOXWES.cjs.map} +1 -1
- package/dist/lib/node/{chunk-KO6MKCED.cjs → chunk-NBC6V3M2.cjs} +136 -118
- package/dist/lib/node/chunk-NBC6V3M2.cjs.map +7 -0
- package/dist/lib/node/{chunk-WXG4Z2EZ.cjs → chunk-TJMZ26GS.cjs} +23 -8
- package/dist/lib/node/chunk-TJMZ26GS.cjs.map +7 -0
- package/dist/lib/node/index.cjs +46 -34
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/{intent-resolver-VY3XWYAA.cjs → intent-resolver-RM4JOCDV.cjs} +8 -8
- package/dist/lib/node/{intent-resolver-VY3XWYAA.cjs.map → intent-resolver-RM4JOCDV.cjs.map} +2 -2
- package/dist/lib/node/{meeting-transcription-state-OYWCY5XE.cjs → meeting-transcription-state-5XLTMWPA.cjs} +6 -6
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{react-surface-M2JQIIDY.cjs → react-surface-YQHBGPOC.cjs} +20 -11
- package/dist/lib/node/react-surface-YQHBGPOC.cjs.map +7 -0
- package/dist/lib/node/settings-ZMB4XRWS.cjs +38 -0
- package/dist/lib/node/settings-ZMB4XRWS.cjs.map +7 -0
- package/dist/lib/node/{transcriber-E6AAB4SU.cjs → transcriber-55OE4X6I.cjs} +10 -10
- package/dist/lib/node/types/index.cjs +8 -8
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{TranscriptContainer-3HJ752CP.mjs → TranscriptContainer-5N3BSK2S.mjs} +3 -3
- package/dist/lib/node-esm/app-graph-builder-DDDVKUHS.mjs +351 -0
- package/dist/lib/node-esm/app-graph-builder-DDDVKUHS.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-SDMGJZLN.mjs → chunk-4RMJO6QQ.mjs} +133 -116
- package/dist/lib/node-esm/chunk-4RMJO6QQ.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-YXZOLOFT.mjs → chunk-5E2MR5XK.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-YXZOLOFT.mjs.map → chunk-5E2MR5XK.mjs.map} +1 -1
- package/dist/lib/node-esm/chunk-HZBSWUJH.mjs +28 -0
- package/dist/lib/node-esm/chunk-HZBSWUJH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-54HDN33F.mjs → chunk-OS2ITZUL.mjs} +9 -21
- package/dist/lib/node-esm/chunk-OS2ITZUL.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-K3R3YK3S.mjs → chunk-UWF6LM27.mjs} +105 -78
- package/dist/lib/node-esm/chunk-UWF6LM27.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +29 -17
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-FCTNJPWY.mjs → intent-resolver-HDRFXMKP.mjs} +4 -4
- package/dist/lib/node-esm/{intent-resolver-FCTNJPWY.mjs.map → intent-resolver-HDRFXMKP.mjs.map} +2 -2
- package/dist/lib/node-esm/{meeting-transcription-state-XMZJ45P4.mjs → meeting-transcription-state-3WOZ52BQ.mjs} +2 -2
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-PXFSIM6V.mjs → react-surface-DRDNXTFZ.mjs} +18 -7
- package/dist/lib/node-esm/react-surface-DRDNXTFZ.mjs.map +7 -0
- package/dist/lib/node-esm/settings-I35TVDUG.mjs +25 -0
- package/dist/lib/node-esm/settings-I35TVDUG.mjs.map +7 -0
- package/dist/lib/node-esm/{transcriber-REAGRCPY.mjs → transcriber-HH7EMCGH.mjs} +4 -4
- package/dist/lib/node-esm/types/index.mjs +3 -3
- package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +4 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/components/Transcript/Transcript.d.ts +6 -4
- package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts +8 -4
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +27 -0
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -0
- package/dist/types/src/components/Transcript/transcript-extension.d.ts +4 -4
- package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -1
- package/dist/types/src/components/TranscriptContainer.d.ts.map +1 -1
- package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts +6 -0
- package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts.map +1 -0
- package/dist/types/src/components/TranscriptionSettings/index.d.ts +2 -0
- package/dist/types/src/components/TranscriptionSettings/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/transcription.stories.d.ts +6 -3
- package/dist/types/src/components/transcription.stories.d.ts.map +1 -1
- package/dist/types/src/entity-extraction/entity-extraction.d.ts +33 -7
- package/dist/types/src/entity-extraction/entity-extraction.d.ts.map +1 -1
- package/dist/types/src/hooks/useQueueModelAdapter.d.ts +2 -2
- package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -1
- package/dist/types/src/model/model.d.ts +23 -23
- package/dist/types/src/model/model.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/testing.d.ts +39 -0
- package/dist/types/src/testing/testing.d.ts.map +1 -0
- package/dist/types/src/transcriber/transcriber.d.ts +2 -2
- package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
- package/dist/types/src/transcriber/transcription-manager.d.ts +17 -15
- package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +0 -21
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +5 -1
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/package.json +48 -45
- package/src/TranscriptionPlugin.tsx +29 -12
- package/src/capabilities/app-graph-builder.ts +99 -29
- package/src/capabilities/capabilities.ts +1 -1
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +2 -2
- package/src/capabilities/react-surface.tsx +12 -4
- package/src/capabilities/settings.ts +20 -0
- package/src/components/Transcript/Transcript.stories.tsx +71 -35
- package/src/components/Transcript/Transcript.tsx +30 -29
- package/src/components/Transcript/deprecated/{Transcript.tsx → OldTranscript.tsx} +24 -1
- package/src/components/Transcript/transcript-extension.ts +20 -17
- package/src/components/TranscriptContainer.tsx +6 -4
- package/src/components/TranscriptionSettings/TranscriptionSettings.tsx +26 -0
- package/src/components/TranscriptionSettings/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/components/transcription.stories.tsx +77 -29
- package/src/entity-extraction/entity-extraction.test.ts +55 -9
- package/src/entity-extraction/entity-extraction.ts +105 -55
- package/src/entity-extraction/system-prompt.tpl +38 -9
- package/src/hooks/useQueueModelAdapter.ts +44 -11
- package/src/model/model.test.ts +85 -43
- package/src/model/model.ts +59 -59
- package/src/testing/index.ts +5 -0
- package/src/testing/testing.ts +208 -0
- package/src/transcriber/transcriber.browser.test.ts +3 -3
- package/src/transcriber/transcriber.ts +16 -10
- package/src/transcriber/transcription-manager.ts +66 -57
- package/src/translations.ts +2 -0
- package/src/types/schema.ts +1 -24
- package/src/types/types.ts +11 -3
- package/dist/lib/browser/app-graph-builder-I4SSIQMW.mjs +0 -168
- package/dist/lib/browser/app-graph-builder-I4SSIQMW.mjs.map +0 -7
- package/dist/lib/browser/chunk-5Q3R53U3.mjs.map +0 -7
- package/dist/lib/browser/chunk-DR3NBV6Q.mjs.map +0 -7
- package/dist/lib/browser/chunk-GI5LZ4SV.mjs +0 -8
- package/dist/lib/browser/chunk-GI5LZ4SV.mjs.map +0 -7
- package/dist/lib/browser/chunk-RHHJZQPM.mjs.map +0 -7
- package/dist/lib/browser/react-surface-HETJ5XY6.mjs.map +0 -7
- package/dist/lib/node/app-graph-builder-WWC4WNTG.cjs +0 -177
- package/dist/lib/node/app-graph-builder-WWC4WNTG.cjs.map +0 -7
- package/dist/lib/node/chunk-3QEJ5EBO.cjs.map +0 -7
- package/dist/lib/node/chunk-KO6MKCED.cjs.map +0 -7
- package/dist/lib/node/chunk-LA73IHCB.cjs.map +0 -7
- package/dist/lib/node/chunk-WXG4Z2EZ.cjs.map +0 -7
- package/dist/lib/node/react-surface-M2JQIIDY.cjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-PPJQAFSI.mjs +0 -169
- package/dist/lib/node-esm/app-graph-builder-PPJQAFSI.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-54HDN33F.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-K3R3YK3S.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SDMGJZLN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-XY22OP6H.mjs +0 -10
- package/dist/lib/node-esm/chunk-XY22OP6H.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-PXFSIM6V.mjs.map +0 -7
- package/dist/types/src/components/Transcript/deprecated/Transcript.d.ts +0 -13
- package/dist/types/src/components/Transcript/deprecated/Transcript.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/testings.d.ts +0 -51
- package/dist/types/src/components/Transcript/testings.d.ts.map +0 -1
- package/dist/types/src/testing/test-data.d.ts +0 -73
- package/dist/types/src/testing/test-data.d.ts.map +0 -1
- package/src/components/Transcript/testings.ts +0 -182
- package/src/testing/test-data.ts +0 -314
- /package/dist/lib/browser/{TranscriptContainer-4D4BHE7G.mjs.map → TranscriptContainer-2VFHUHLE.mjs.map} +0 -0
- /package/dist/lib/browser/{meeting-transcription-state-5D52VTHU.mjs.map → meeting-transcription-state-MNA2XROE.mjs.map} +0 -0
- /package/dist/lib/browser/{transcriber-SMRLU2KY.mjs.map → transcriber-MSBS4VBI.mjs.map} +0 -0
- /package/dist/lib/node/{meeting-transcription-state-OYWCY5XE.cjs.map → meeting-transcription-state-5XLTMWPA.cjs.map} +0 -0
- /package/dist/lib/node/{transcriber-E6AAB4SU.cjs.map → transcriber-55OE4X6I.cjs.map} +0 -0
- /package/dist/lib/node-esm/{TranscriptContainer-3HJ752CP.mjs.map → TranscriptContainer-5N3BSK2S.mjs.map} +0 -0
- /package/dist/lib/node-esm/{meeting-transcription-state-XMZJ45P4.mjs.map → meeting-transcription-state-3WOZ52BQ.mjs.map} +0 -0
- /package/dist/lib/node-esm/{transcriber-REAGRCPY.mjs.map → transcriber-HH7EMCGH.mjs.map} +0 -0
|
@@ -9,11 +9,11 @@ import { WaveFile } from 'wavefile';
|
|
|
9
9
|
|
|
10
10
|
import { Trigger } from '@dxos/async';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
|
+
import { type TranscriptionContentBlock } from '@dxos/schema';
|
|
12
13
|
import { openAndClose } from '@dxos/test-utils';
|
|
13
14
|
import { trace, TRACE_PROCESSOR } from '@dxos/tracing';
|
|
14
15
|
|
|
15
16
|
import { type AudioChunk, type AudioRecorder, Transcriber } from '../transcriber';
|
|
16
|
-
import { type TranscriptSegment } from '../types';
|
|
17
17
|
import { mergeFloat64Arrays } from '../util';
|
|
18
18
|
|
|
19
19
|
// TODO(burdon): ReferenceError: Worker is not defined (Can only run with web workers).
|
|
@@ -93,7 +93,7 @@ describe.skip('Transcriber', () => {
|
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
test.skip('transcription of audio recording', { timeout: 10_000 }, async () => {
|
|
96
|
-
const trigger = new Trigger<
|
|
96
|
+
const trigger = new Trigger<TranscriptionContentBlock[]>({ autoReset: true });
|
|
97
97
|
const recorder = new MockAudioRecorder({
|
|
98
98
|
buffer: await readFile('test.wav'),
|
|
99
99
|
chunkDuration: 3_000,
|
|
@@ -127,7 +127,7 @@ describe.skip('Transcriber', () => {
|
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
test.skip('transcription of audio recording with overlapping chunks', { timeout: 20_000 }, async () => {
|
|
130
|
-
const trigger = new Trigger<
|
|
130
|
+
const trigger = new Trigger<TranscriptionContentBlock[]>({ autoReset: true });
|
|
131
131
|
const recorder = new MockAudioRecorder({
|
|
132
132
|
buffer: await readFile('test.wav'),
|
|
133
133
|
chunkDuration: 3_000,
|
|
@@ -7,10 +7,11 @@ import { WaveFile } from 'wavefile';
|
|
|
7
7
|
import { DeferredTask, Trigger } from '@dxos/async';
|
|
8
8
|
import { type Context, LifecycleState, Resource } from '@dxos/context';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
|
+
import { type TranscriptionContentBlock } from '@dxos/schema';
|
|
10
11
|
import { trace } from '@dxos/tracing';
|
|
11
12
|
|
|
12
13
|
import { type AudioRecorder, type AudioChunk } from './audio-recorder';
|
|
13
|
-
import { TRANSCRIPTION_URL
|
|
14
|
+
import { TRANSCRIPTION_URL } from '../types';
|
|
14
15
|
import { mergeFloat64Arrays } from '../util';
|
|
15
16
|
|
|
16
17
|
type WhisperWord = {
|
|
@@ -64,7 +65,7 @@ export type TranscribeConfig = {
|
|
|
64
65
|
export type TranscriberParams = {
|
|
65
66
|
config: TranscribeConfig;
|
|
66
67
|
recorder: AudioRecorder;
|
|
67
|
-
onSegments: (segments:
|
|
68
|
+
onSegments: (segments: TranscriptionContentBlock[]) => Promise<void>;
|
|
68
69
|
};
|
|
69
70
|
|
|
70
71
|
/**
|
|
@@ -93,6 +94,7 @@ export class Transcriber extends Resource {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
protected override async _open(ctx: Context) {
|
|
97
|
+
log.info('opening');
|
|
96
98
|
this._recorder.setOnChunk((chunk) => this._saveAudioChunk(chunk));
|
|
97
99
|
await this._recorder.start();
|
|
98
100
|
this._transcribeTask = new DeferredTask(ctx, async () => this._transcribe());
|
|
@@ -100,15 +102,18 @@ export class Transcriber extends Resource {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
protected override async _close() {
|
|
105
|
+
log.info('closing');
|
|
103
106
|
this._recording = false;
|
|
104
107
|
this._transcribeTask = undefined;
|
|
105
108
|
await this._recorder.stop();
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
startChunksRecording() {
|
|
112
|
+
log.info('starting');
|
|
109
113
|
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
110
114
|
return;
|
|
111
115
|
}
|
|
116
|
+
|
|
112
117
|
this._recording = true;
|
|
113
118
|
}
|
|
114
119
|
|
|
@@ -116,8 +121,10 @@ export class Transcriber extends Resource {
|
|
|
116
121
|
if (this._lifecycleState !== LifecycleState.OPEN || !this._recording) {
|
|
117
122
|
return;
|
|
118
123
|
}
|
|
124
|
+
|
|
119
125
|
this._recording = false;
|
|
120
126
|
this._transcribeTask?.schedule();
|
|
127
|
+
log.info('stopped');
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
private _saveAudioChunk(chunk: AudioChunk) {
|
|
@@ -194,24 +201,22 @@ export class Transcriber extends Resource {
|
|
|
194
201
|
|
|
195
202
|
if (!response.ok) {
|
|
196
203
|
this._audioChunks = [];
|
|
197
|
-
throw new Error(
|
|
204
|
+
throw new Error(`Transcription failed: ${response.statusText}`);
|
|
198
205
|
}
|
|
199
206
|
|
|
200
|
-
const {
|
|
201
|
-
segments,
|
|
202
|
-
}: {
|
|
207
|
+
const { segments } = (await response.json()) as {
|
|
203
208
|
segments: WhisperSegment[];
|
|
204
|
-
}
|
|
209
|
+
};
|
|
205
210
|
|
|
206
211
|
log.info('transcription response', {
|
|
207
|
-
segments,
|
|
212
|
+
segments: segments.length,
|
|
208
213
|
string: segments.map((segments) => segments.text).join(' '),
|
|
209
214
|
});
|
|
210
215
|
|
|
211
216
|
return segments;
|
|
212
217
|
}
|
|
213
218
|
|
|
214
|
-
private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]):
|
|
219
|
+
private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]): TranscriptionContentBlock[] {
|
|
215
220
|
// Absolute zero for all relative timestamps in the segments.
|
|
216
221
|
const zeroTimestamp = originalChunks.at(0)!.timestamp;
|
|
217
222
|
|
|
@@ -240,8 +245,9 @@ export class Transcriber extends Resource {
|
|
|
240
245
|
|
|
241
246
|
// Add absolute timestamp to each segment.
|
|
242
247
|
return filteredSegments.map((segment) => ({
|
|
248
|
+
type: 'transcription',
|
|
243
249
|
started: new Date(zeroTimestamp + segment.start * 1_000).toISOString(),
|
|
244
|
-
text: segment.text,
|
|
250
|
+
text: segment.text.trim(),
|
|
245
251
|
}));
|
|
246
252
|
}
|
|
247
253
|
}
|
|
@@ -6,14 +6,13 @@ import { synchronized } from '@dxos/async';
|
|
|
6
6
|
import { Resource } from '@dxos/context';
|
|
7
7
|
import { QueueImpl, type Queue } from '@dxos/echo-db';
|
|
8
8
|
import { create } from '@dxos/echo-schema';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { type DXN } from '@dxos/keys';
|
|
10
|
+
import { log } from '@dxos/log';
|
|
11
11
|
import { type EdgeHttpClient } from '@dxos/react-edge-client';
|
|
12
|
-
import { type
|
|
12
|
+
import { MessageType, type TranscriptionContentBlock } from '@dxos/schema';
|
|
13
13
|
|
|
14
14
|
import { MediaStreamRecorder } from './media-stream-recorder';
|
|
15
15
|
import { Transcriber } from './transcriber';
|
|
16
|
-
import { TranscriptBlock, type TranscriptSegment } from '../types';
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Length of the chunk in ms.
|
|
@@ -31,23 +30,34 @@ const PREFIXED_CHUNKS_AMOUNT = 10;
|
|
|
31
30
|
*/
|
|
32
31
|
const TRANSCRIBE_AFTER_CHUNKS_AMOUNT = 50;
|
|
33
32
|
|
|
33
|
+
export type TranscriptMessageEnricher = (message: MessageType) => Promise<MessageType>;
|
|
34
|
+
|
|
35
|
+
export type TranscriptionManagerOptions = {
|
|
36
|
+
edgeClient: EdgeHttpClient;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Enrich the message before it is written to the transcription queue.
|
|
40
|
+
*/
|
|
41
|
+
messageEnricher?: TranscriptMessageEnricher;
|
|
42
|
+
};
|
|
43
|
+
|
|
34
44
|
/**
|
|
35
45
|
* Manages transcription state for a meeting.
|
|
36
46
|
*/
|
|
37
|
-
// TODO(mykola): Reconcile with transcriber capability.
|
|
38
47
|
export class TranscriptionManager extends Resource {
|
|
39
48
|
private readonly _edgeClient: EdgeHttpClient;
|
|
49
|
+
private readonly _messageEnricher?: TranscriptMessageEnricher;
|
|
40
50
|
private _audioStreamTrack?: MediaStreamTrack = undefined;
|
|
41
|
-
private
|
|
42
|
-
private _hue?: HuePalette = undefined;
|
|
51
|
+
private _identityDid?: string = undefined;
|
|
43
52
|
private _mediaRecorder?: MediaStreamRecorder = undefined;
|
|
44
53
|
private _transcriber?: Transcriber = undefined;
|
|
54
|
+
private _queue?: Queue<MessageType> = undefined;
|
|
45
55
|
private _enabled = false;
|
|
46
|
-
private _queue?: Queue<TranscriptBlock> = undefined;
|
|
47
56
|
|
|
48
|
-
constructor(
|
|
57
|
+
constructor(options: TranscriptionManagerOptions) {
|
|
49
58
|
super();
|
|
50
|
-
this._edgeClient = edgeClient;
|
|
59
|
+
this._edgeClient = options.edgeClient;
|
|
60
|
+
this._messageEnricher = options.messageEnricher;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
protected override async _open() {
|
|
@@ -58,10 +68,24 @@ export class TranscriptionManager extends Resource {
|
|
|
58
68
|
void this._transcriber?.close();
|
|
59
69
|
}
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
setQueue(queueDxn: DXN): TranscriptionManager {
|
|
72
|
+
if (this._queue?.dxn.toString() !== queueDxn.toString()) {
|
|
73
|
+
log.info('setQueue', { queueDxn: queueDxn.toString() });
|
|
74
|
+
this._queue = new QueueImpl<MessageType>(this._edgeClient, queueDxn);
|
|
75
|
+
}
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setIdentityDid(did: string): TranscriptionManager {
|
|
80
|
+
if (this._identityDid !== did) {
|
|
81
|
+
this._identityDid = did;
|
|
82
|
+
}
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setRecording(recording?: boolean): TranscriptionManager {
|
|
63
87
|
if (!this.isOpen || !this._enabled) {
|
|
64
|
-
return;
|
|
88
|
+
return this;
|
|
65
89
|
}
|
|
66
90
|
|
|
67
91
|
if (recording) {
|
|
@@ -69,6 +93,7 @@ export class TranscriptionManager extends Resource {
|
|
|
69
93
|
} else {
|
|
70
94
|
this._transcriber?.stopChunksRecording();
|
|
71
95
|
}
|
|
96
|
+
return this;
|
|
72
97
|
}
|
|
73
98
|
|
|
74
99
|
/**
|
|
@@ -80,7 +105,9 @@ export class TranscriptionManager extends Resource {
|
|
|
80
105
|
if (this._enabled === enabled) {
|
|
81
106
|
return;
|
|
82
107
|
}
|
|
108
|
+
|
|
83
109
|
this._enabled = enabled ?? false;
|
|
110
|
+
// TODO(burdon): Why is toggle called here?
|
|
84
111
|
this.isOpen && (await this._toggleTranscriber());
|
|
85
112
|
}
|
|
86
113
|
|
|
@@ -89,60 +116,33 @@ export class TranscriptionManager extends Resource {
|
|
|
89
116
|
if (this._audioStreamTrack === track) {
|
|
90
117
|
return;
|
|
91
118
|
}
|
|
119
|
+
|
|
92
120
|
this._audioStreamTrack = track;
|
|
93
121
|
this.isOpen && (await this._toggleTranscriber());
|
|
94
122
|
}
|
|
95
123
|
|
|
96
|
-
|
|
97
|
-
* Set the queue to save the transcription to.
|
|
98
|
-
* @param queue - The queue to save the transcription to or the DXN of the queue.
|
|
99
|
-
*/
|
|
100
|
-
@synchronized
|
|
101
|
-
setQueue(queue?: Queue<TranscriptBlock> | string) {
|
|
102
|
-
switch (typeof queue) {
|
|
103
|
-
case 'string':
|
|
104
|
-
if (this._queue?.dxn.toString() === queue) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
this._queue = new QueueImpl<TranscriptBlock>(this._edgeClient, DXN.parse(queue));
|
|
108
|
-
break;
|
|
109
|
-
case 'object':
|
|
110
|
-
if (this._queue === queue) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
invariant(queue instanceof QueueImpl);
|
|
114
|
-
this._queue = queue;
|
|
115
|
-
break;
|
|
116
|
-
case 'undefined':
|
|
117
|
-
this._queue = undefined;
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@synchronized
|
|
123
|
-
setName(name: string) {
|
|
124
|
-
if (this._name === name) {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
this._name = name;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@synchronized
|
|
131
|
-
setHue(hue: HuePalette) {
|
|
132
|
-
if (this._hue === hue) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
this._hue = hue;
|
|
136
|
-
}
|
|
137
|
-
|
|
124
|
+
// TODO(burdon): Change this to setEnables (explicit), not toggle.
|
|
138
125
|
private async _toggleTranscriber() {
|
|
139
126
|
await this._maybeReinitTranscriber();
|
|
140
127
|
|
|
141
128
|
// Open or close transcriber if transcription is enabled or disabled.
|
|
142
129
|
if (this._enabled) {
|
|
143
130
|
await this._transcriber?.open();
|
|
131
|
+
// TODO(burdon): Started and stopped blocks appear twice.
|
|
132
|
+
const block = create(MessageType, {
|
|
133
|
+
created: new Date().toISOString(),
|
|
134
|
+
blocks: [{ type: 'transcription', text: 'Started', started: new Date().toISOString() }],
|
|
135
|
+
sender: { role: 'assistant' },
|
|
136
|
+
});
|
|
137
|
+
this._queue?.append([block]);
|
|
144
138
|
} else {
|
|
145
139
|
await this._transcriber?.close();
|
|
140
|
+
const block = create(MessageType, {
|
|
141
|
+
created: new Date().toISOString(),
|
|
142
|
+
blocks: [{ type: 'transcription', text: 'Stopped', started: new Date().toISOString() }],
|
|
143
|
+
sender: { role: 'assistant' },
|
|
144
|
+
});
|
|
145
|
+
this._queue?.append([block]);
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -173,12 +173,21 @@ export class TranscriptionManager extends Resource {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
private async _onSegments(segments:
|
|
176
|
+
private async _onSegments(segments: TranscriptionContentBlock[]) {
|
|
177
177
|
if (!this.isOpen || !this._queue) {
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
let block = create(MessageType, {
|
|
182
|
+
created: new Date().toISOString(),
|
|
183
|
+
blocks: segments,
|
|
184
|
+
sender: { identityDid: this._identityDid },
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (this._messageEnricher) {
|
|
188
|
+
block = await this._messageEnricher(block);
|
|
189
|
+
}
|
|
190
|
+
|
|
182
191
|
this._queue.append([block]);
|
|
183
192
|
}
|
|
184
193
|
}
|
package/src/translations.ts
CHANGED
package/src/types/schema.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Expando, Ref, S, TypedObject } from '@dxos/echo-schema';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Root transcript object created when the user starts a transcription.
|
|
@@ -37,26 +37,3 @@ const TranscriptHeader = S.Struct({
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
export type TranscriptHeader = S.Schema.Type<typeof TranscriptHeader>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Transcription fragment.
|
|
43
|
-
*/
|
|
44
|
-
const TranscriptSegment = S.Struct({
|
|
45
|
-
// TODO(burdon): TS from service is not Unix TS (x1000).
|
|
46
|
-
started: S.String,
|
|
47
|
-
text: S.String,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export type TranscriptSegment = S.Schema.Type<typeof TranscriptSegment>;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Transcription block (from single speaker).
|
|
54
|
-
*/
|
|
55
|
-
export const TranscriptBlock = S.Struct({
|
|
56
|
-
id: S.String,
|
|
57
|
-
authorName: S.optional(S.String), // TODO(burdon): Replace with identityDid.
|
|
58
|
-
authorHue: S.optional(S.String), // TOOD(burdon): Remove.
|
|
59
|
-
segments: S.Array(TranscriptSegment),
|
|
60
|
-
}).pipe(EchoObject({ typename: 'dxos.org/type/TranscriptBlock', version: '0.1.0' }));
|
|
61
|
-
|
|
62
|
-
export type TranscriptBlock = S.Schema.Type<typeof TranscriptBlock>;
|
package/src/types/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { S, isInstanceOf } from '@dxos/echo-schema';
|
|
5
|
+
import { SpaceIdSchema, S, isInstanceOf } from '@dxos/echo-schema';
|
|
6
6
|
import { isLiveObject } from '@dxos/react-client/echo';
|
|
7
7
|
|
|
8
8
|
import { TranscriptType } from './schema';
|
|
@@ -22,8 +22,7 @@ export namespace TranscriptionAction {
|
|
|
22
22
|
export class Create extends S.TaggedClass<Create>()(`${TRANSCRIPTION_ACTION}/create`, {
|
|
23
23
|
input: S.Struct({
|
|
24
24
|
name: S.optional(S.String),
|
|
25
|
-
|
|
26
|
-
spaceId: S.String,
|
|
25
|
+
spaceId: SpaceIdSchema,
|
|
27
26
|
}),
|
|
28
27
|
output: S.Struct({
|
|
29
28
|
object: TranscriptType,
|
|
@@ -34,3 +33,12 @@ export namespace TranscriptionAction {
|
|
|
34
33
|
export const isTranscript = (object: unknown): object is typeof TranscriptType => {
|
|
35
34
|
return isLiveObject(object) && isInstanceOf(TranscriptType, object);
|
|
36
35
|
};
|
|
36
|
+
|
|
37
|
+
// TODO(burdon): Create with decode consistently: S.decodeSync(TranscriptionSettingsSchema)({}))
|
|
38
|
+
export const TranscriptionSettingsSchema = S.mutable(
|
|
39
|
+
S.Struct({
|
|
40
|
+
entityExtraction: S.optional(S.Boolean).pipe(S.withConstructorDefault(() => true)),
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export type TranscriptionSettingsProps = S.Schema.Type<typeof TranscriptionSettingsSchema>;
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TranscriptionManager
|
|
3
|
-
} from "./chunk-DR3NBV6Q.mjs";
|
|
4
|
-
import "./chunk-KLD7O5GJ.mjs";
|
|
5
|
-
import {
|
|
6
|
-
TranscriptType,
|
|
7
|
-
TranscriptionAction
|
|
8
|
-
} from "./chunk-5Q3R53U3.mjs";
|
|
9
|
-
import {
|
|
10
|
-
TranscriptionCapabilities
|
|
11
|
-
} from "./chunk-5BE6RTNC.mjs";
|
|
12
|
-
import {
|
|
13
|
-
TRANSCRIPTION_PLUGIN
|
|
14
|
-
} from "./chunk-6ZR5MDK3.mjs";
|
|
15
|
-
|
|
16
|
-
// packages/plugins/plugin-transcription/src/capabilities/app-graph-builder.ts
|
|
17
|
-
import { Capabilities, contributes, createIntent } from "@dxos/app-framework";
|
|
18
|
-
import { fullyQualifiedId, getSpace, makeRef } from "@dxos/client/echo";
|
|
19
|
-
import { generateName } from "@dxos/display-name";
|
|
20
|
-
import { getSchemaTypename, isInstanceOf } from "@dxos/echo-schema";
|
|
21
|
-
import { invariant } from "@dxos/invariant";
|
|
22
|
-
import { ClientCapabilities } from "@dxos/plugin-client";
|
|
23
|
-
import { PLANK_COMPANION_TYPE, ATTENDABLE_PATH_SEPARATOR } from "@dxos/plugin-deck/types";
|
|
24
|
-
import { createExtension } from "@dxos/plugin-graph";
|
|
25
|
-
import { MeetingCapabilities } from "@dxos/plugin-meeting";
|
|
26
|
-
import { MeetingType } from "@dxos/plugin-meeting/types";
|
|
27
|
-
import { keyToFallback } from "@dxos/util";
|
|
28
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-transcription/src/capabilities/app-graph-builder.ts";
|
|
29
|
-
var getMeetingTranscript = async (context, meeting) => {
|
|
30
|
-
const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
|
|
31
|
-
const typename = getSchemaTypename(TranscriptType);
|
|
32
|
-
const existing = await meeting.artifacts[typename]?.load();
|
|
33
|
-
if (existing instanceof TranscriptType) {
|
|
34
|
-
return existing;
|
|
35
|
-
}
|
|
36
|
-
const space = getSpace(meeting);
|
|
37
|
-
invariant(space, void 0, {
|
|
38
|
-
F: __dxlog_file,
|
|
39
|
-
L: 41,
|
|
40
|
-
S: void 0,
|
|
41
|
-
A: [
|
|
42
|
-
"space",
|
|
43
|
-
""
|
|
44
|
-
]
|
|
45
|
-
});
|
|
46
|
-
const { data } = await dispatch(createIntent(TranscriptionAction.Create, {
|
|
47
|
-
spaceId: space.id
|
|
48
|
-
}));
|
|
49
|
-
meeting.artifacts[typename] = makeRef(data.object);
|
|
50
|
-
return data?.object;
|
|
51
|
-
};
|
|
52
|
-
var app_graph_builder_default = (context) => contributes(Capabilities.AppGraphBuilder, [
|
|
53
|
-
createExtension({
|
|
54
|
-
id: `${TRANSCRIPTION_PLUGIN}/meeting-transcript`,
|
|
55
|
-
filter: (node) => isInstanceOf(MeetingType, node.data) && node.type !== PLANK_COMPANION_TYPE,
|
|
56
|
-
actions: ({ node }) => {
|
|
57
|
-
const meeting = node.data;
|
|
58
|
-
const state = context.requestCapability(TranscriptionCapabilities.MeetingTranscriptionState);
|
|
59
|
-
return [
|
|
60
|
-
{
|
|
61
|
-
id: `${fullyQualifiedId(meeting)}/action/start-stop-transcription`,
|
|
62
|
-
data: async () => {
|
|
63
|
-
const transcript = await getMeetingTranscript(context, meeting);
|
|
64
|
-
invariant(transcript, "Failed to create transcript", {
|
|
65
|
-
F: __dxlog_file,
|
|
66
|
-
L: 66,
|
|
67
|
-
S: void 0,
|
|
68
|
-
A: [
|
|
69
|
-
"transcript",
|
|
70
|
-
"'Failed to create transcript'"
|
|
71
|
-
]
|
|
72
|
-
});
|
|
73
|
-
const call = context.requestCapability(MeetingCapabilities.CallManager);
|
|
74
|
-
call.setActivity(getSchemaTypename(TranscriptType), {
|
|
75
|
-
enabled: !state.enabled,
|
|
76
|
-
queueDxn: transcript.queue.dxn.toString()
|
|
77
|
-
});
|
|
78
|
-
},
|
|
79
|
-
properties: {
|
|
80
|
-
label: state.enabled ? [
|
|
81
|
-
"stop transcription label",
|
|
82
|
-
{
|
|
83
|
-
ns: TRANSCRIPTION_PLUGIN
|
|
84
|
-
}
|
|
85
|
-
] : [
|
|
86
|
-
"start transcription label",
|
|
87
|
-
{
|
|
88
|
-
ns: TRANSCRIPTION_PLUGIN
|
|
89
|
-
}
|
|
90
|
-
],
|
|
91
|
-
icon: "ph--subtitles--regular",
|
|
92
|
-
disposition: "toolbar",
|
|
93
|
-
classNames: state.enabled ? "bg-callAlert" : ""
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
];
|
|
97
|
-
},
|
|
98
|
-
connector: ({ node }) => {
|
|
99
|
-
const meeting = node.data;
|
|
100
|
-
const client = context.requestCapability(ClientCapabilities.Client);
|
|
101
|
-
const state = context.requestCapability(TranscriptionCapabilities.MeetingTranscriptionState);
|
|
102
|
-
return [
|
|
103
|
-
{
|
|
104
|
-
id: `${fullyQualifiedId(meeting)}${ATTENDABLE_PATH_SEPARATOR}${getSchemaTypename(TranscriptType)}`,
|
|
105
|
-
type: PLANK_COMPANION_TYPE,
|
|
106
|
-
data: meeting.artifacts[getSchemaTypename(TranscriptType)]?.target,
|
|
107
|
-
properties: {
|
|
108
|
-
label: [
|
|
109
|
-
"transcript companion label",
|
|
110
|
-
{
|
|
111
|
-
ns: TRANSCRIPTION_PLUGIN
|
|
112
|
-
}
|
|
113
|
-
],
|
|
114
|
-
icon: "ph--subtitles--regular",
|
|
115
|
-
disposition: "hidden",
|
|
116
|
-
schema: TranscriptType,
|
|
117
|
-
getIntent: ({ space }) => createIntent(TranscriptionAction.Create, {
|
|
118
|
-
spaceId: space.id
|
|
119
|
-
}),
|
|
120
|
-
onJoin: () => {
|
|
121
|
-
const transcriptionManager = new TranscriptionManager(client.edge);
|
|
122
|
-
const identity = client.halo.identity.get();
|
|
123
|
-
invariant(identity, void 0, {
|
|
124
|
-
F: __dxlog_file,
|
|
125
|
-
L: 105,
|
|
126
|
-
S: void 0,
|
|
127
|
-
A: [
|
|
128
|
-
"identity",
|
|
129
|
-
""
|
|
130
|
-
]
|
|
131
|
-
});
|
|
132
|
-
transcriptionManager.setName(identity.profile?.displayName ?? generateName(identity.identityKey.toHex()));
|
|
133
|
-
const fallbackValue = keyToFallback(identity.identityKey);
|
|
134
|
-
const userHue = identity.profile?.data?.hue || fallbackValue.hue;
|
|
135
|
-
transcriptionManager.setHue(userHue);
|
|
136
|
-
void transcriptionManager.open();
|
|
137
|
-
state.transcriptionManager = transcriptionManager;
|
|
138
|
-
},
|
|
139
|
-
onLeave: () => {
|
|
140
|
-
void state.transcriptionManager?.close();
|
|
141
|
-
state.transcriptionManager = void 0;
|
|
142
|
-
state.enabled = false;
|
|
143
|
-
},
|
|
144
|
-
onCallStateUpdated: (callState) => {
|
|
145
|
-
const typename = getSchemaTypename(TranscriptType);
|
|
146
|
-
const transcription = typename ? callState.activities?.[typename] : void 0;
|
|
147
|
-
if (!transcription?.payload) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const payload = transcription.payload;
|
|
151
|
-
state.enabled = !!payload.enabled;
|
|
152
|
-
void state.transcriptionManager?.setEnabled(payload.enabled);
|
|
153
|
-
void state.transcriptionManager?.setQueue(payload.queueDxn);
|
|
154
|
-
},
|
|
155
|
-
onMediaStateUpdated: ([mediaState, isSpeaking]) => {
|
|
156
|
-
void state.transcriptionManager?.setAudioTrack(mediaState.audioTrack);
|
|
157
|
-
void state.transcriptionManager?.setRecording(isSpeaking);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
];
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
]);
|
|
165
|
-
export {
|
|
166
|
-
app_graph_builder_default as default
|
|
167
|
-
};
|
|
168
|
-
//# sourceMappingURL=app-graph-builder-I4SSIQMW.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/capabilities/app-graph-builder.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Capabilities, contributes, createIntent, type PluginsContext } from '@dxos/app-framework';\nimport { fullyQualifiedId, getSpace, makeRef, type Space } from '@dxos/client/echo';\nimport { generateName } from '@dxos/display-name';\nimport { getSchemaTypename, isInstanceOf } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { ClientCapabilities } from '@dxos/plugin-client';\nimport { PLANK_COMPANION_TYPE, ATTENDABLE_PATH_SEPARATOR } from '@dxos/plugin-deck/types';\nimport { createExtension, type Node } from '@dxos/plugin-graph';\nimport { MeetingCapabilities, type CallState, type MediaState } from '@dxos/plugin-meeting';\nimport { MeetingType } from '@dxos/plugin-meeting/types';\nimport { type buf } from '@dxos/protocols/buf';\nimport { type TranscriptionPayloadSchema } from '@dxos/protocols/buf/dxos/edge/calls_pb';\nimport { keyToFallback } from '@dxos/util';\n\nimport { TranscriptionCapabilities } from './capabilities';\nimport { TRANSCRIPTION_PLUGIN } from '../meta';\nimport { TranscriptionManager } from '../transcriber';\nimport { TranscriptionAction, TranscriptType } from '../types';\n\n// TODO(wittjosiah): Factor out.\n// TODO(wittjosiah): Can we stop using protobuf for this?\ntype TranscriptionPayload = buf.MessageInitShape<typeof TranscriptionPayloadSchema>;\n\nconst getMeetingTranscript = async (\n context: PluginsContext,\n meeting: MeetingType,\n): Promise<TranscriptType | undefined> => {\n const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);\n\n const typename = getSchemaTypename(TranscriptType)!;\n const existing = await meeting.artifacts[typename]?.load();\n if (existing instanceof TranscriptType) {\n return existing;\n }\n\n const space = getSpace(meeting);\n invariant(space);\n const { data } = await dispatch(createIntent(TranscriptionAction.Create, { spaceId: space.id }));\n meeting.artifacts[typename] = makeRef(data!.object);\n return data?.object;\n};\n\n// TODO(wittjosiah): Introduce a sound that plays when transcription is activated/deactivated.\nexport default (context: PluginsContext) =>\n contributes(Capabilities.AppGraphBuilder, [\n createExtension({\n id: `${TRANSCRIPTION_PLUGIN}/meeting-transcript`,\n filter: (node): node is Node<MeetingType> =>\n isInstanceOf(MeetingType, node.data) && node.type !== PLANK_COMPANION_TYPE,\n actions: ({ node }) => {\n const meeting = node.data;\n const state = context.requestCapability(TranscriptionCapabilities.MeetingTranscriptionState);\n return [\n {\n id: `${fullyQualifiedId(meeting)}/action/start-stop-transcription`,\n data: async () => {\n // NOTE: We are not saving the state of the transcription manager here.\n // We expect the state to be updated through `onCallStateUpdated` once it is propagated through Swarm.\n // This is done to avoid race conditions and to not handle optimistic updates.\n\n const transcript = await getMeetingTranscript(context, meeting);\n invariant(transcript, 'Failed to create transcript');\n\n const call = context.requestCapability(MeetingCapabilities.CallManager);\n call.setActivity(getSchemaTypename(TranscriptType)!, {\n enabled: !state.enabled,\n queueDxn: transcript.queue.dxn.toString(),\n });\n },\n properties: {\n label: state.enabled\n ? ['stop transcription label', { ns: TRANSCRIPTION_PLUGIN }]\n : ['start transcription label', { ns: TRANSCRIPTION_PLUGIN }],\n icon: 'ph--subtitles--regular',\n disposition: 'toolbar',\n classNames: state.enabled ? 'bg-callAlert' : '',\n },\n },\n ];\n },\n connector: ({ node }) => {\n const meeting = node.data;\n const client = context.requestCapability(ClientCapabilities.Client);\n const state = context.requestCapability(TranscriptionCapabilities.MeetingTranscriptionState);\n\n return [\n {\n id: `${fullyQualifiedId(meeting)}${ATTENDABLE_PATH_SEPARATOR}${getSchemaTypename(TranscriptType)}`,\n type: PLANK_COMPANION_TYPE,\n data: meeting.artifacts[getSchemaTypename(TranscriptType)!]?.target,\n properties: {\n label: ['transcript companion label', { ns: TRANSCRIPTION_PLUGIN }],\n icon: 'ph--subtitles--regular',\n disposition: 'hidden',\n schema: TranscriptType,\n getIntent: ({ space }: { space: Space }) =>\n createIntent(TranscriptionAction.Create, { spaceId: space.id }),\n onJoin: () => {\n const transcriptionManager = new TranscriptionManager(client.edge);\n const identity = client.halo.identity.get();\n invariant(identity);\n transcriptionManager.setName(\n identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),\n );\n const fallbackValue = keyToFallback(identity!.identityKey);\n const userHue = identity!.profile?.data?.hue || fallbackValue.hue;\n transcriptionManager.setHue(userHue);\n void transcriptionManager.open();\n state.transcriptionManager = transcriptionManager;\n },\n onLeave: () => {\n void state.transcriptionManager?.close();\n state.transcriptionManager = undefined;\n state.enabled = false;\n },\n onCallStateUpdated: (callState: CallState) => {\n const typename = getSchemaTypename(TranscriptType);\n const transcription = typename ? callState.activities?.[typename] : undefined;\n if (!transcription?.payload) {\n return;\n }\n\n const payload: TranscriptionPayload = transcription.payload;\n state.enabled = !!payload.enabled;\n void state.transcriptionManager?.setEnabled(payload.enabled);\n void state.transcriptionManager?.setQueue(payload.queueDxn);\n },\n onMediaStateUpdated: ([mediaState, isSpeaking]: [MediaState, boolean]) => {\n void state.transcriptionManager?.setAudioTrack(mediaState.audioTrack);\n void state.transcriptionManager?.setRecording(isSpeaking);\n },\n },\n },\n ];\n },\n }),\n ]);\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Capabilities", "contributes", "createIntent", "fullyQualifiedId", "getSpace", "makeRef", "generateName", "getSchemaTypename", "isInstanceOf", "invariant", "ClientCapabilities", "PLANK_COMPANION_TYPE", "ATTENDABLE_PATH_SEPARATOR", "createExtension", "MeetingCapabilities", "MeetingType", "keyToFallback", "getMeetingTranscript", "context", "meeting", "dispatchPromise", "dispatch", "requestCapability", "Capabilities", "IntentDispatcher", "typename", "getSchemaTypename", "TranscriptType", "existing", "artifacts", "load", "space", "getSpace", "invariant", "data", "createIntent", "TranscriptionAction", "Create", "spaceId", "id", "makeRef", "object", "contributes", "AppGraphBuilder", "createExtension", "TRANSCRIPTION_PLUGIN", "filter", "node", "isInstanceOf", "MeetingType", "type", "PLANK_COMPANION_TYPE", "actions", "state", "TranscriptionCapabilities", "MeetingTranscriptionState", "fullyQualifiedId", "transcript", "call", "MeetingCapabilities", "CallManager", "setActivity", "enabled", "queueDxn", "queue", "dxn", "toString", "properties", "label", "ns", "icon", "disposition", "classNames", "connector", "client", "ClientCapabilities", "Client", "ATTENDABLE_PATH_SEPARATOR", "target", "schema", "getIntent", "onJoin", "transcriptionManager", "TranscriptionManager", "edge", "identity", "halo", "get", "setName", "profile", "displayName", "generateName", "identityKey", "toHex", "fallbackValue", "keyToFallback", "userHue", "hue", "setHue", "open", "onLeave", "close", "undefined", "onCallStateUpdated", "callState", "transcription", "activities", "payload", "setEnabled", "setQueue", "onMediaStateUpdated", "mediaState", "isSpeaking", "setAudioTrack", "audioTrack", "setRecording"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types/schema.ts", "../../../src/types/types.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { EchoObject, Expando, Ref, S, TypedObject } from '@dxos/echo-schema';\n\n/**\n * Root transcript object created when the user starts a transcription.\n */\nexport const TranscriptSchema = S.Struct({\n name: S.String,\n\n // TODO(burdon): Use Date or string?\n started: S.optional(S.String),\n ended: S.optional(S.String),\n\n /**\n * Queue containing TranscriptBlock objects.\n */\n // TODO(wittjosiah): Should be a ref to a queue.\n queue: Ref(Expando),\n});\n\nexport class TranscriptType extends TypedObject({\n typename: 'dxos.org/type/Transcript',\n version: '0.1.0',\n})(TranscriptSchema.fields) {}\n\n// TODO(burdon): Do these need to be kept in sync with EDGE?\n\n/**\n * First message in queue.\n * Contains metadata for the recording and transcript.\n */\nconst TranscriptHeader = S.Struct({\n started: S.optional(S.String),\n});\n\nexport type TranscriptHeader = S.Schema.Type<typeof TranscriptHeader>;\n\n/**\n * Transcription fragment.\n */\nconst TranscriptSegment = S.Struct({\n // TODO(burdon): TS from service is not Unix TS (x1000).\n started: S.String,\n text: S.String,\n});\n\nexport type TranscriptSegment = S.Schema.Type<typeof TranscriptSegment>;\n\n/**\n * Transcription block (from single speaker).\n */\nexport const TranscriptBlock = S.Struct({\n id: S.String,\n authorName: S.optional(S.String), // TODO(burdon): Replace with identityDid.\n authorHue: S.optional(S.String), // TOOD(burdon): Remove.\n segments: S.Array(TranscriptSegment),\n}).pipe(EchoObject({ typename: 'dxos.org/type/TranscriptBlock', version: '0.1.0' }));\n\nexport type TranscriptBlock = S.Schema.Type<typeof TranscriptBlock>;\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { S, isInstanceOf } from '@dxos/echo-schema';\nimport { isLiveObject } from '@dxos/react-client/echo';\n\nimport { TranscriptType } from './schema';\nimport { TRANSCRIPTION_PLUGIN } from '../meta';\n\n// TODO(burdon): Move to separate proto.\n\n/**\n * Endpoint to the calls service.\n */\n// TODO(burdon): Reconfigure/move.\nexport const TRANSCRIPTION_URL = 'https://calls-service.dxos.workers.dev';\n\nexport namespace TranscriptionAction {\n const TRANSCRIPTION_ACTION = `${TRANSCRIPTION_PLUGIN}/action`;\n\n export class Create extends S.TaggedClass<Create>()(`${TRANSCRIPTION_ACTION}/create`, {\n input: S.Struct({\n name: S.optional(S.String),\n // TODO(wittjosiah): SpaceId.\n spaceId: S.String,\n }),\n output: S.Struct({\n object: TranscriptType,\n }),\n }) {}\n}\n\nexport const isTranscript = (object: unknown): object is typeof TranscriptType => {\n return isLiveObject(object) && isInstanceOf(TranscriptType, object);\n};\n"],
|
|
5
|
-
"mappings": ";;;;;AAIA,SAASA,YAAYC,SAASC,KAAKC,GAAGC,mBAAmB;AAKlD,IAAMC,mBAAmBC,EAAEC,OAAO;EACvCC,MAAMF,EAAEG;;EAGRC,SAASJ,EAAEK,SAASL,EAAEG,MAAM;EAC5BG,OAAON,EAAEK,SAASL,EAAEG,MAAM;;;;;EAM1BI,OAAOC,IAAIC,OAAAA;AACb,CAAA;AAEO,IAAMC,iBAAN,cAA6BC,YAAY;EAC9CC,UAAU;EACVC,SAAS;AACX,CAAA,EAAGd,iBAAiBe,MAAM,EAAA;AAAG;AAQ7B,IAAMC,mBAAmBf,EAAEC,OAAO;EAChCG,SAASJ,EAAEK,SAASL,EAAEG,MAAM;AAC9B,CAAA;AAOA,IAAMa,oBAAoBhB,EAAEC,OAAO;;EAEjCG,SAASJ,EAAEG;EACXc,MAAMjB,EAAEG;AACV,CAAA;AAOO,IAAMe,kBAAkBlB,EAAEC,OAAO;EACtCkB,IAAInB,EAAEG;EACNiB,YAAYpB,EAAEK,SAASL,EAAEG,MAAM;EAC/BkB,WAAWrB,EAAEK,SAASL,EAAEG,MAAM;EAC9BmB,UAAUtB,EAAEuB,MAAMP,iBAAAA;AACpB,CAAA,EAAGQ,KAAKC,WAAW;EAAEb,UAAU;EAAiCC,SAAS;AAAQ,CAAA,CAAA;;;ACvDjF,SAASa,KAAAA,IAAGC,oBAAoB;AAChC,SAASC,oBAAoB;AAWtB,IAAMC,oBAAoB;;UAEhBC,sBAAAA;AACf,QAAMC,uBAAuB,GAAGC,oBAAAA;EAEzB,MAAMC,eAAeC,GAAEC,YAAW,EAAW,GAAGJ,oBAAAA,WAA+B;IACpFK,OAAOF,GAAEG,OAAO;MACdC,MAAMJ,GAAEK,SAASL,GAAEM,MAAM;;MAEzBC,SAASP,GAAEM;IACb,CAAA;IACAE,QAAQR,GAAEG,OAAO;MACfM,QAAQC;IACV,CAAA;EACF,CAAA,EAAA;EAAI;uBATSX,SAAAA;AAUf,GAbiBH,wBAAAA,sBAAAA,CAAAA,EAAAA;AAeV,IAAMe,eAAe,CAACF,WAAAA;AAC3B,SAAOG,aAAaH,MAAAA,KAAWI,aAAaH,gBAAgBD,MAAAA;AAC9D;",
|
|
6
|
-
"names": ["EchoObject", "Expando", "Ref", "S", "TypedObject", "TranscriptSchema", "S", "Struct", "name", "String", "started", "optional", "ended", "queue", "Ref", "Expando", "TranscriptType", "TypedObject", "typename", "version", "fields", "TranscriptHeader", "TranscriptSegment", "text", "TranscriptBlock", "id", "authorName", "authorHue", "segments", "Array", "pipe", "EchoObject", "S", "isInstanceOf", "isLiveObject", "TRANSCRIPTION_URL", "TranscriptionAction", "TRANSCRIPTION_ACTION", "TRANSCRIPTION_PLUGIN", "Create", "S", "TaggedClass", "input", "Struct", "name", "optional", "String", "spaceId", "output", "object", "TranscriptType", "isTranscript", "isLiveObject", "isInstanceOf"]
|
|
7
|
-
}
|